This commit is contained in:
ADElectronics 2017-12-24 12:49:22 +03:00
parent 7f07f696e1
commit c6c5eeed6f
1170 changed files with 608790 additions and 1 deletions

View file

@ -0,0 +1,52 @@
/*
* web_auth.c
*
* Created on: 23/04/2017.
* Author: pvvx
*/
#include "autoconf.h"
#include "FreeRTOS.h"
#include "diag.h"
#include "web_utils.h"
#include "wifi_api.h"
#include "web_srv.h"
#include "rtl8195a/rtl_libc.h"
#include "esp_comp.h"
/* ----------------------------------------------------------------------------------
* pbuf[77] = Username and password are combined into a string "username:password"
* Return: Authorization Level
* 0 - Not Authorized */
uint8 UserAuthorization(uint8 *pbuf, size_t declen)
{
uint8 * psw = rtl_strchr(pbuf, ':');
if(psw != NULL)
{
#if USE_WEB_AUTH_LEVEL
if(rtl_strcmp(pbuf, "rtl871x:webfs_write") == 0)
{
return WEB_AUTH_LEVEL_WEBFS;
}
if(rtl_strcmp(pbuf, "rtl871x:ota_write") == 0)
{
return WEB_AUTH_LEVEL_OTA;
}
if(rtl_strcmp(pbuf, "rtl871x:supervisor") == 0)
{
return WEB_AUTH_LEVEL_SUPERVISOR;
}
#endif
*psw++ = 0;
if(rom_xstrcmp(wifi_ap_cfg.ssid, pbuf) && rom_xstrcmp( wifi_ap_cfg.password, psw))
{
return WEB_AUTH_LEVEL_USER;
}
if(rom_xstrcmp(wifi_st_cfg.ssid, pbuf) && rom_xstrcmp( wifi_st_cfg.password, psw))
{
return WEB_AUTH_LEVEL_USER1;
}
}
return 0;
}

View file

@ -0,0 +1,733 @@
/******************************************************************************
* FileName: web_int_callbacks.c
* Description: The web server inernal callbacks.
*******************************************************************************/
#include "user_config.h"
#ifdef USE_WEB
#include "autoconf.h"
#include "FreeRTOS.h"
#include "task.h"
#include "diag.h"
#include "tcm_heap.h"
#include "lwip/tcp.h"
#include "flash_eep.h"
#include "device_lock.h"
#include "ethernetif.h"
#include "tcpsrv/tcp_srv_conn.h"
#include "web_srv_int.h"
#include "web_utils.h"
#include "webfs/webfs.h"
#include "rtl8195a/rtl_libc.h"
#include "sys_cfg.h"
#include "wifi_api.h"
#include "sys_api.h"
#include "esp_comp.h"
#include "sdk_ver.h"
#include "ledeffectsserver.h"
#ifdef USE_NETBIOS
#include "netbios/netbios.h"
#endif
#ifdef USE_SNTP
#include "sntp/sntp.h"
#endif
#ifdef USE_CAPTDNS
#include "captdns.h"
#endif
#ifdef USE_MODBUS
#include "modbustcp.h"
#include "mdbtab.h"
#endif
#ifdef USE_RS485DRV
#include "driver/rs485drv.h"
#endif
#ifdef USE_OVERLAY
#include "overlay.h"
#endif
#undef atoi
#define atoi rom_atoi
//#define mMIN(a, b) ((a<b)?a:b)
#define ifcmp(a) if(rom_xstrcmp(cstr, a))
#define OpenFlash() { device_mutex_lock(RT_DEV_LOCK_FLASH); flash_turnon(); }
#define CloseFlash() { SpicDisableRtl8195A(); device_mutex_unlock(RT_DEV_LOCK_FLASH); }
extern struct netif xnetif[NET_IF_NUM]; /* network interface structure */
#if WEB_DEBUG_FUNCTIONS
//#define TEST_SEND_WAVE
#endif // #if WEB_DEBUG_FUNCTIONS
#ifdef TEST_SEND_WAVE
//-------------------------------------------------------------------------------
// Test adc
// Читает adc в одиночный буфер (~2килобайта) на ~20ksps и сохраняет в виде WAV
// Правильное чтение организуется по прерыванию таймера(!).
// Тут только демо!
//-------------------------------------------------------------------------------
typedef struct
{ // https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
unsigned long int RIFF ;/* +00 'RIFF' */
unsigned long int size8;/* +04 file size - 8 */
unsigned long int WAVE ;/* +08 'WAVE' */
unsigned long int fmt ;/* +12 'fmt ' */
unsigned long int fsize;/* +16 указатель до 'fact' или 'data' */
unsigned short int ccod;/* +20 01 00 Compression code: 1 - PCM/uncompressed */
unsigned short int mono;/* +22 00 01 или 00 02 */
unsigned long int freq ;/* +24 частота */
unsigned long int bps ;/* +28 */
unsigned short int blka;/* +32 1/2/4 BlockAlign*/
unsigned short int bits;/* +34 разрядность 8/16 */
unsigned long int data ;/* +36 'data' */
unsigned long int dsize;/* +40 размер данных */
} WAV_HEADER;
const WAV_HEADER ICACHE_RODATA_ATTR wav_header =
{0x46464952L,
0x00000008L,
0x45564157L,
0x20746d66L,
0x00000010L,
0x0001 ,
0x0001 ,
0x000055f0L,
0x000055f0L,
0x0002 ,
0x0010 ,
0x61746164L,
0x00000000L};
#define WAV_HEADER_SIZE sizeof(wav_header)
//===============================================================================
// web_test_adc()
//-------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR web_test_adc(TCP_SERV_CONN *ts_conn)
{
WEB_SRV_CONN *web_conn = (WEB_SRV_CONN *) ts_conn->linkd;
unsigned int len = web_conn->msgbufsize - web_conn->msgbuflen;
if(len > WAV_HEADER_SIZE + 10) {
len -= WAV_HEADER_SIZE;
WAV_HEADER * ptr = (WAV_HEADER *) &web_conn->msgbuf[web_conn->msgbuflen];
os_memcpy(ptr, &wav_header, WAV_HEADER_SIZE);
ptr->dsize = len;
web_conn->msgbuflen += WAV_HEADER_SIZE;
len >>= 1;
read_adcs((uint16 *)(web_conn->msgbuf + web_conn->msgbuflen), len, 0x0808);
web_conn->msgbuflen += len << 1;
}
if(!CheckSCB(SCB_WEBSOC)) SetSCB(SCB_FCLOSE | SCB_DISCONNECT); // connection close
}
#endif // TEST_SEND_WAVE
//===============================================================================
// WiFi Scan XML
//-------------------------------------------------------------------------------
extern void wifi_set_timer_scan(int ms);
static void ICACHE_FLASH_ATTR web_wscan_xml(TCP_SERV_CONN *ts_conn)
{
WEB_SRV_CONN *web_conn = (WEB_SRV_CONN *) ts_conn->linkd;
web_scan_handler_t * pwscn_rec = &web_scan_handler_ptr;
// Check if this is a first round call
if(CheckSCB(SCB_RETRYCB)==0) {
int i = 0;
web_conn->udata_start = 0;
if(pwscn_rec->flg == 2) {
i = pwscn_rec->ap_count;
wifi_set_timer_scan(7000);
} else if(pwscn_rec->flg == 0) api_wifi_scan(NULL);
tcp_puts_fd("<total>%d</total>", i);
if(i == 0) return;
}
while(web_conn->msgbuflen + 96 + 10 + 32 <= web_conn->msgbufsize) {
if(pwscn_rec->flg && web_conn->udata_start < pwscn_rec->ap_count) {
rtw_scan_result_t *si = &pwscn_rec->ap_details[web_conn->udata_start];
uint8 ssid[32*6 + 1];
int len = si->SSID.len;
if(len > 32) len = 32;
si->SSID.val[len] = '\0';
if(web_conn->msgbuflen + 96 + 10 + htmlcode(ssid, si->SSID.val, 32*6, 32) > web_conn->msgbufsize) break;
tcp_puts_fd("<ap id=\"%d\"><ch>%d</ch><au>%d</au><bs>" MACSTR "</bs><ss>%s</ss><rs>%d</rs><hd>%d</hd><wp>%d</wp></ap>",
web_conn->udata_start,
si->channel,
rtw_security_to_idx(si->security),
MAC2STR(si->BSSID.octet),
ssid,
si->signal_strength,
// si->band, // rtw_802_11_band_t
si->bss_type & 3, // rtw_bss_type_t
si->wps_type); // rtw_wps_type_t
web_conn->udata_start++;
if(web_conn->udata_start >= pwscn_rec->ap_count) {
wifi_close_scan();
ClrSCB(SCB_RETRYCB);
return;
}
}
else {
wifi_close_scan();
ClrSCB(SCB_RETRYCB);
return;
}
}
// repeat in the next call ...
SetSCB(SCB_RETRYCB);
SetNextFunSCB(web_wscan_xml);
return;
}
#ifdef USE_MODBUS
//===============================================================================
// Mdb XML
//-------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR web_modbus_xml(TCP_SERV_CONN *ts_conn)
{
WEB_SRV_CONN *web_conn = (WEB_SRV_CONN *) ts_conn->linkd;
while(web_conn->msgbuflen + 24 <= web_conn->msgbufsize) {
if(web_conn->udata_start < web_conn->udata_stop) {
uint16 val16;
if(RdMdbData((uint8 *)&val16, web_conn->udata_start, 1) != 0) tcp_puts_fd("<m%u>?</m%u>", web_conn->udata_start, web_conn->udata_start);
else {
if(ts_conn->flag.user_option2) {
if(ts_conn->flag.user_option1) {
tcp_puts_fd("<m%u>0x%04x</m%u>", web_conn->udata_start, val16, web_conn->udata_start);
}
else {
tcp_puts_fd("<m%u>%04x</m%u>", web_conn->udata_start, val16, web_conn->udata_start);
};
}
else {
if(ts_conn->flag.user_option1) {
tcp_puts_fd("<m%u>%d</m%u>", web_conn->udata_start, (sint32)((sint16)val16), web_conn->udata_start);
}
else {
tcp_puts_fd("<m%u>%u</m%u>", web_conn->udata_start, val16, web_conn->udata_start);
};
};
};
web_conn->udata_start++;
}
else {
ClrSCB(SCB_RETRYCB);
return;
}
}
// repeat in the next call ...
SetSCB(SCB_RETRYCB);
SetNextFunSCB(web_modbus_xml);
return;
}
#endif
//===============================================================================
// RAM hexdump
//-------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR web_hexdump(TCP_SERV_CONN *ts_conn)
{
WEB_SRV_CONN *web_conn = (WEB_SRV_CONN *) ts_conn->linkd;
union {
uint32 dw[4];
uint8 b[16];
}data;
web_conn->udata_start &= 0xfffffff0;
uint32 *addr = (uint32 *)web_conn->udata_start;
int i;
web_conn->udata_stop &= 0xfffffff0;
while(web_conn->msgbuflen + (9+3*16+17+2) <= web_conn->msgbufsize) {
// if((uint32)addr < 0x9A000000) {
if((uint32)addr >= 0x98000000 && (uint32)addr < 0x9A000000) {
OpenFlash();
}
tcp_puts("%08x", addr);
for(i=0 ; i < 4 ; i++) data.dw[i] = *addr++;
web_conn->udata_start = (uint32)addr;
if(ts_conn->flag.user_option1) { // dword or byte ?
for(i=0 ; i < 4 ; i++) tcp_puts(" %08x", data.dw[i]);
}
else {
for(i=0 ; i < 16 ; i++) tcp_puts(" %02x", data.b[i]);
}
if((uint32)addr >= 0x98000000 && (uint32)addr < 0x9A000000) {
CloseFlash();
}
tcp_put(' '); tcp_put(' ');
for(i=0 ; i < 16 ; i++) tcp_put((data.b[i] >=' ' && data.b[i] != 0x7F)? data.b[i] : '.');
tcp_puts("\r\n");
if((uint32)addr >= web_conn->udata_stop) {
ClrSCB(SCB_RETRYCB);
if(!CheckSCB(SCB_WEBSOC)) SetSCB(SCB_FCLOSE | SCB_DISCONNECT); // connection close
return;
}
// } else {
// tcp_puts("%p = Bad address!\r\n", addr);
// ClrSCB(SCB_RETRYCB);
// if(!CheckSCB(SCB_WEBSOC)) SetSCB(SCB_FCLOSE | SCB_DISCONNECT); // connection close
// return;
// };
}
// repeat in the next call ...
SetSCB(SCB_RETRYCB);
SetNextFunSCB(web_hexdump);
return;
}
/******************************************************************************
* FunctionName : web saved flash
* Description : Processing the flash data send
* Parameters : none (Calback)
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR web_get_flash(TCP_SERV_CONN *ts_conn)
{
WEB_SRV_CONN *web_conn = (WEB_SRV_CONN *)ts_conn->linkd;
// Check if this is a first round call
if(CheckSCB(SCB_RETRYCB)==0) {
if(web_conn->udata_start == web_conn->udata_stop) return;
#if DEBUGSOO > 2
os_printf("file_size:%08x ", web_conn->udata_stop - web_conn->udata_start );
#endif
}
// Get/put as many bytes as possible
unsigned int len = mMIN(web_conn->msgbufsize - web_conn->msgbuflen, web_conn->udata_stop - web_conn->udata_start);
// Read Flash addr = web_conn->webfinc_offsets, len = x, buf = sendbuf
#if DEBUGSOO > 2
os_printf("%08x..%08x ",web_conn->udata_start, web_conn->udata_start + len );
#endif
device_mutex_lock(RT_DEV_LOCK_FLASH);
if(spi_flash_read(web_conn->udata_start, web_conn->msgbuf, len)) {
web_conn->udata_start += len;
web_conn->msgbuflen += len;
if(web_conn->udata_start < web_conn->udata_stop) {
SetNextFunSCB(web_get_flash);
device_mutex_unlock(RT_DEV_LOCK_FLASH);
SetSCB(SCB_RETRYCB);
return;
};
};
device_mutex_unlock(RT_DEV_LOCK_FLASH);
ClrSCB(SCB_RETRYCB);
// SetSCB(SCB_FCLOSE | SCB_DISCONNECT);
return;
}
/******************************************************************************
* FunctionName : web saved flash
* Description : Processing the flash data send
* Parameters : none (Calback)
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR web_get_ram(TCP_SERV_CONN *ts_conn)
{
WEB_SRV_CONN *web_conn = (WEB_SRV_CONN *)ts_conn->linkd;
// Check if this is a first round call
if(CheckSCB(SCB_RETRYCB)==0) { // On initial call, проверка параметров
if(web_conn->udata_start == web_conn->udata_stop) {
// SetSCB(SCB_FCLOSE | SCB_DISCONNECT);
return;
}
#if DEBUGSOO > 2
os_printf("file_size:%08x ", web_conn->udata_stop - web_conn->udata_start );
#endif
}
// Get/put as many bytes as possible
uint32 len = mMIN(web_conn->msgbufsize - web_conn->msgbuflen, web_conn->udata_stop - web_conn->udata_start);
if((uint32)web_conn->udata_start >= 0x98000000 && (uint32)web_conn->udata_start < 0x9A000000) {
OpenFlash();
}
copy_align4(web_conn->msgbuf, (void *)(web_conn->udata_start), len);
if((uint32)web_conn->udata_start >= 0x98000000 && (uint32)web_conn->udata_start < 0x9A000000) {
CloseFlash();
}
web_conn->msgbuflen += len;
web_conn->udata_start += len;
#if DEBUGSOO > 2
os_printf("%08x-%08x ",web_conn->udata_start, web_conn->udata_start + len );
#endif
if(web_conn->udata_start != web_conn->udata_stop) {
SetSCB(SCB_RETRYCB);
SetNextFunSCB(web_get_ram);
return;
};
ClrSCB(SCB_RETRYCB);
// SetSCB(SCB_FCLOSE | SCB_DISCONNECT);
return;
}
/******************************************************************************
* FunctionName : web_callback
* Description : callback
* Parameters : struct TCP_SERV_CONN
* Returns : none
******************************************************************************/
void ICACHE_FLASH_ATTR web_int_callback(TCP_SERV_CONN *ts_conn, uint8 *cstr)
{
WEB_SRV_CONN *web_conn = (WEB_SRV_CONN *)ts_conn->linkd;
// uint8 *cstr = &web_conn->msgbuf[web_conn->msgbuflen];
{
uint8 *vstr = os_strchr(cstr, '=');
if(vstr != NULL) {
*vstr++ = '\0';
web_int_vars(ts_conn, cstr, vstr);
return;
}
}
#if DEBUGSOO > 3
os_printf("[%s]\n", cstr);
#endif
ifcmp("start") tcp_puts("0x%08x", web_conn->udata_start);
else ifcmp("stop") tcp_puts("0x%08x", web_conn->udata_stop);
// **************************************************************************************************** //
// **************************************** User settings ********************************************* //
else ifcmp("ws_")
{
cstr += 3;
ifcmp("filt_")
{
cstr += 5;
ifcmp("rbw_")
{
cstr += 4;
ifcmp("enbl") tcp_puts("%d", filt_rainbow.enabled);
else ifcmp("huesteps") tcp_puts("%d", filt_rainbow.hue_steps);
else ifcmp("cyclesteps") tcp_puts("%d", filt_rainbow.cycle_steps);
}
else ifcmp("fd_")
{
cstr += 3;
ifcmp("enbl") tcp_puts("%d", filt_fade.enabled);
else ifcmp("min") tcp_puts("%d", filt_fade.min);
else ifcmp("max") tcp_puts("%d", filt_fade.max);
else ifcmp("cyclesteps") tcp_puts("%d", filt_fade.steps);
}
}
}
// **************************************************************************************************** //
// **************************************************************************************************** //
#if USE_WEB_AUTH_LEVEL
else ifcmp("realm") tcp_puts("%u", web_conn->auth_realm);
else ifcmp("auth") tcp_puts("%u", web_conn->auth_level);
#endif
else ifcmp("xml_")
{
cstr+=4;
ifcmp("scan") web_wscan_xml(ts_conn);
#if WEB_DEBUG_FUNCTIONS
else
{
#if USE_WEB_AUTH_LEVEL
if(web_conn->auth_level < WEB_AUTH_LEVEL_USER)
return;
else
#endif
{
web_conn->udata_start&=~3;
ifcmp("ram") tcp_puts("0x%08x", *((uint32*)web_conn->udata_start));
else tcp_put('?');
web_conn->udata_start += 4;
}
}
#endif
}
else ifcmp("sys_")
{
cstr+=4;
ifcmp("url") tcp_strcpy(get_new_hostname());
else ifcmp("cid") tcp_puts("%08x", HalGetChipId());
else ifcmp("fid") tcp_puts("%08x", spi_flash_get_id());
else ifcmp("fsize") tcp_puts("%u", spi_flash_real_size()); // flashchip->chip_size
else ifcmp("sdkver") tcp_strcpy_fd(SDK_VERSION);
else ifcmp("sysver") tcp_strcpy_fd(SYS_VERSION);
else ifcmp("webver") tcp_strcpy_fd(WEB_SVERSION);
else ifcmp("heap") tcp_puts("%u", xPortGetFreeHeapSize());
else ifcmp("heapm") tcp_puts("%u", xPortGetMinimumEverFreeHeapSize());
else ifcmp("tcmh") tcp_puts("%u", tcm_heap_freeSpace());
else ifcmp("time") tcp_puts("%u", xTaskGetTickCount());
else ifcmp("mactime") {
if(wifi_mode) {
union {
uint32 dw[2];
uint64 dd;
}ux;
ux.dd = *((uint64_t *)(WIFI_REG_BASE + 0x0560)); // REG_TSFTR -> #include "hal_com_reg.h"
tcp_puts("0x%08x%08x", ux.dw[1], ux.dw[0]);
}
}
else ifcmp("clkcpu") tcp_puts("%u", HalGetCpuClk());
else ifcmp("debug") tcp_put('1' - (print_off & 1)); // rtl_print on/off
#if WEB_DEBUG_FUNCTIONS
else ifcmp("restart") {
#if USE_WEB_AUTH_LEVEL
if(web_conn->auth_level < WEB_AUTH_LEVEL_USER) return;
#endif
webserver_qfn((web_ex_func_cb)sys_reset, NULL, 200);
}
else ifcmp("ram") tcp_puts("0x%08x", *((uint32 *)(ahextoul(cstr+3)&(~3))));
else ifcmp("rdec") tcp_puts("%d", *((uint32 *)(ahextoul(cstr+4)&(~3))));
#endif // #if WEB_DEBUG_FUNCTIONS
else ifcmp("ip") {
uint32 cur_ip;
if(netif_default != NULL) cur_ip = netif_default->ip_addr.addr;
tcp_puts(IPSTR, IP2STR(&cur_ip));
}
#ifdef USE_NETBIOS
else ifcmp("netbios") {
if(syscfg.cfg.b.netbios_ena) tcp_strcpy(netbios_name);
}
#endif
else tcp_put('?');
}
#ifdef WEB_INA219_DRV
else ifcmp("ina219") {
if(CheckSCB(SCB_WEBSOC)) {
extern int ina219_ws(TCP_SERV_CONN *ts_conn, char cmd);
int x = ina219_ws(ts_conn, cstr[6]);
if(x < 0) SetSCB(SCB_FCLOSE|SCB_DISCONNECT);
else tcp_puts("%d", x);
}
}
#endif
#ifdef WEB_MLX90614_DRV
else ifcmp("mlx90614") {
if(CheckSCB(SCB_WEBSOC)) {
extern int mlx90614_ws(TCP_SERV_CONN *ts_conn, char cmd);
int x = mlx90614_ws(ts_conn, cstr[6]);
if(x < 0) SetSCB(SCB_FCLOSE|SCB_DISCONNECT);
else tcp_puts("%d", x);
}
}
#endif
#ifdef WEB_ADC_DRV
else ifcmp("adc")
{
if(CheckSCB(SCB_WEBSOC))
{
extern int adc_ws(TCP_SERV_CONN *ts_conn, char cmd);
int x = adc_ws(ts_conn, cstr[6]);
if(x < 0) SetSCB(SCB_FCLOSE|SCB_DISCONNECT);
else tcp_puts("%d", x);
}
}
#endif
#ifdef WEB_MPU6050
else ifcmp("mpu6050")
{
if (CheckSCB(SCB_WEBSOC))
{
}
}
#endif
else ifcmp("cfg_") {
cstr += 4;
ifcmp("web_") {
cstr += 4;
ifcmp("port") tcp_puts("%u", syscfg.web_port);
else ifcmp("twrec") tcp_puts("%u", syscfg.web_twrec);
else ifcmp("twcls") tcp_puts("%u", syscfg.web_twcls);
else ifcmp("twd") tcp_put((syscfg.cfg.b.web_time_wait_delete)? '1' : '0');
else tcp_put('?');
}
else ifcmp("sleep") tcp_put((syscfg.cfg.b.powersave_enable)? '1' : '0');
else ifcmp("pinclr") tcp_put((syscfg.cfg.b.pin_clear_cfg_enable)? '1' : '0');
else ifcmp("debug") tcp_put((syscfg.cfg.b.debug_print_enable)? '1' : '0');
#ifdef USE_NETBIOS
else ifcmp("netbios") tcp_put((syscfg.cfg.b.netbios_ena)? '1' : '0');
#endif
#ifdef USE_SNTP
else ifcmp("sntp") tcp_put((syscfg.cfg.b.sntp_ena)? '1' : '0');
#endif
#ifdef USE_CAPTDNS
else ifcmp("cdns") tcp_put((syscfg.cfg.b.cdns_ena)? '1' : '0');
#endif
else tcp_put('?');
}
else ifcmp("wifi_") {
cstr+=5;
ifcmp("rdcfg") read_wifi_cfg(-1);
else ifcmp("newcfg") webserver_qfn((web_ex_func_cb)wifi_run, (void *)((uint32)wifi_cfg.mode), 200);
else ifcmp("cmode") tcp_puts("%d", wifi_mode);
else ifcmp("mode") tcp_puts("%d", wifi_cfg.mode);
else ifcmp("bgn") tcp_puts("%d", wifi_cfg.bgn);
else ifcmp("txpow") tcp_puts("%u", wifi_cfg.tx_pwr);
else ifcmp("lflg") tcp_puts("%u", wifi_cfg.load_flg);
else ifcmp("sflg") tcp_puts("%u", wifi_cfg.save_flg);
else ifcmp("adpt") tcp_puts("%u", wifi_cfg.adaptivity);
else ifcmp("country") tcp_puts("%u", wifi_cfg.country_code);
else ifcmp("ap_") {
cstr+=3;
ifcmp("ssid") {
wifi_ap_cfg.ssid[NDIS_802_11_LENGTH_SSID] = '\0';
tcp_strcpy(wifi_ap_cfg.ssid);
}
else ifcmp("psw") {
wifi_ap_cfg.password[IW_PASSPHRASE_MAX_SIZE] = '\0';
tcp_strcpy(wifi_ap_cfg.password);
}
else ifcmp("chl") tcp_puts("%u", wifi_ap_cfg.channel);
else ifcmp("mcns") tcp_puts("%u", wifi_ap_cfg.max_sta);
else ifcmp("auth") tcp_put((wifi_ap_cfg.security) ? '1' : '0');
else ifcmp("hssid") tcp_put((wifi_ap_cfg.ssid_hidden & 1) + '0');
else ifcmp("bint") tcp_puts("%u", wifi_ap_cfg.beacon_interval);
else ifcmp("mac") tcp_puts(MACSTR, MAC2STR(xnetif[WLAN_AP_NETIF_NUM].hwaddr));
else ifcmp("hostname") tcp_strcpy(lwip_host_name[1]);
else ifcmp("dhcp") tcp_puts("%u", wifi_ap_dhcp.mode);
else ifcmp("ip") tcp_puts(IPSTR, IP2STR(&wifi_ap_dhcp.ip));
else ifcmp("gw") tcp_puts(IPSTR, IP2STR(&wifi_ap_dhcp.gw));
else ifcmp("msk") tcp_puts(IPSTR, IP2STR(&wifi_ap_dhcp.mask));
else ifcmp("cip") tcp_puts(IPSTR, IP2STR(&xnetif[WLAN_ST_NETIF_NUM].ip_addr.addr));
// else ifcmp("mac") strtomac(pvar, wifi_ap_cfg.macaddr);
// else ifcmp("sip") tcp_puts(IPSTR, IP2STR(&wifi_ap_dhcp.start_ip));
// else ifcmp("eip") tcp_puts(IPSTR, IP2STR(&wifi_ap_dhcp.end_ip));
#if DEBUGSOO > 2
else os_printf(" - none! ");
#endif
}
else ifcmp("st_") {
cstr+=3;
ifcmp("rssi") {
int rssi;
wifi_get_rssi(&rssi);
tcp_puts("%d", rssi);
}
else ifcmp("status") tcp_puts("%u", wifi_st_status);
else ifcmp("arec") tcp_puts("%u", wifi_st_cfg.autoreconnect);
else ifcmp("rect") tcp_puts("%u", wifi_st_cfg.reconnect_pause);
ifcmp("ssid") {
wifi_st_cfg.ssid[NDIS_802_11_LENGTH_SSID] = '\0';
tcp_strcpy(wifi_st_cfg.ssid);
}
else ifcmp("psw") {
wifi_st_cfg.password[IW_PASSPHRASE_MAX_SIZE] = '\0';
tcp_strcpy(wifi_st_cfg.password);
}
else ifcmp("mac") tcp_puts(MACSTR, MAC2STR(xnetif[WLAN_ST_NETIF_NUM].hwaddr));
else ifcmp("bssid") tcp_puts(MACSTR, MAC2STR(wifi_st_cfg.bssid));
else ifcmp("sbss") tcp_puts("%u", wifi_st_cfg.flg);
else ifcmp("sleep") tcp_puts("%d", wifi_st_cfg.sleep);
else ifcmp("dtim") tcp_puts("%u", wifi_st_cfg.dtim);
#if LWIP_NETIF_HOSTNAME
else ifcmp("hostname") tcp_strcpy(lwip_host_name[0]);
#endif
else ifcmp("auth") tcp_puts("%u", wifi_st_cfg.security);
else ifcmp("dhcp") tcp_puts("%u", wifi_st_dhcp.mode);
else ifcmp("ip") tcp_puts(IPSTR, IP2STR(&wifi_st_dhcp.ip));
else ifcmp("gw") tcp_puts(IPSTR, IP2STR(&wifi_st_dhcp.gw));
else ifcmp("msk") tcp_puts(IPSTR, IP2STR(&wifi_st_dhcp.mask));
#if DEBUGSOO > 5
else os_printf(" - none!\n");
#endif
}
#if DEBUGSOO > 5
else os_printf(" - none!\n");
#endif
}
else ifcmp("bin_") {
#if USE_WEB_AUTH_LEVEL
if(web_conn->auth_level < WEB_AUTH_LEVEL_USER) return;
#endif
cstr+=4;
ifcmp("flash") {
cstr+=5;
if(*cstr == '_') {
cstr++;
#if WEB_DEBUG_FUNCTIONS
ifcmp("all") {
web_conn->udata_start = 0;
web_conn->udata_stop = spi_flash_real_size();
web_get_flash(ts_conn);
}
else ifcmp("sec_") {
web_conn->udata_start = ahextoul(cstr+4) << 12;
web_conn->udata_stop = web_conn->udata_start + FLASH_SECTOR_SIZE;
web_get_flash(ts_conn);
}
else
#endif // #if WEB_DEBUG_FUNCTIONS
ifcmp("disk") {
web_conn->udata_start = WEBFS_base_addr();
web_conn->udata_stop = web_conn->udata_start + WEBFS_curent_size();
web_get_flash(ts_conn);
}
else tcp_put('?');
}
else web_get_flash(ts_conn);
}
#if WEB_DEBUG_FUNCTIONS
else ifcmp("ram") web_get_ram(ts_conn);
#endif // #if WEB_DEBUG_FUNCTIONS
else tcp_put('?');
}
#if WEB_DEBUG_FUNCTIONS
else ifcmp("hexdmp") {
#if USE_WEB_AUTH_LEVEL
if(web_conn->auth_level < WEB_AUTH_LEVEL_USER) return;
#endif
if(cstr[6]=='d') ts_conn->flag.user_option1 = 1;
else ts_conn->flag.user_option1 = 0;
web_hexdump(ts_conn);
}
#endif // #if WEB_DEBUG_FUNCTIONS
else ifcmp("web_") {
cstr+=4;
ifcmp("port") tcp_puts("%u", ts_conn->pcfg->port);
else ifcmp("host") tcp_puts(IPSTR ":%d", IP2STR(&(ts_conn->pcb->local_ip.addr)), ts_conn->pcb->local_port);
else ifcmp("remote") tcp_puts(IPSTR ":%d", IP2STR(&(ts_conn->remote_ip.dw)), ts_conn->remote_port);
else ifcmp("twrec") tcp_puts("%u", ts_conn->pcfg->time_wait_rec);
else ifcmp("twcls") tcp_puts("%u", ts_conn->pcfg->time_wait_cls);
else tcp_put('?');
}
else ifcmp("wfs_") {
cstr+=4;
ifcmp("files") tcp_puts("%u", numFiles);
else ifcmp("addr") tcp_puts("0x%08x", WEBFS_base_addr());
else ifcmp("size") tcp_puts("%u", WEBFS_curent_size());
else ifcmp("max_size") tcp_puts("%u", WEBFS_max_size());
else tcp_put('?');
}
#ifdef USE_OVERLAY
else ifcmp("ovl") {
cstr += 3;
if(*cstr == ':') {
int i = ovl_loader(cstr + 1);
if (i == 0) {
if(CheckSCB(SCB_WEBSOC)) {
tcp_puts("%d", ovl_call(1));
}
else {
web_conn->web_disc_cb = (web_func_disc_cb)ovl_call; // адрес старта оверлея
web_conn->web_disc_par = 1; // параметр функции - инициализация
}
}
tcp_puts("%d", i);
}
else if(*cstr == '$') {
if(ovl_call != NULL) tcp_puts("%d", ovl_call(ahextoul(cstr + 1)));
else tcp_put('?');
}
else if(*cstr == '@') {
if(ovl_call != NULL) tcp_puts("%d", ovl_call((int) cstr + 1));
else tcp_put('?');
}
else tcp_put('?');
}
#endif
#ifdef USE_SNTP
else ifcmp("sntp_") {
cstr += 5;
ifcmp("time") tcp_puts("%u", sntp_gen_system_time(0)); // get_sntp_time
else tcp_put('?');
}
#endif
#ifdef TEST_SEND_WAVE
else ifcmp("test_adc") web_test_adc(ts_conn);
#endif
else ifcmp("hellomsg") tcp_puts_fd("Web on RTL871x!");
else tcp_put('?');
}
#endif // USE_WEB

View file

@ -0,0 +1,427 @@
/******************************************************************************
* FileName: webserver.c
* Description: The web server mode configuration.
*******************************************************************************/
#include "user_config.h"
#ifdef USE_WEB
#include "autoconf.h"
#include "FreeRTOS.h"
#include "freertos_pmu.h"
#include "task.h"
#include "diag.h"
#include "lwip/ip.h"
#include "lwip/ip_addr.h"
#include "lwip/tcp.h"
#include "tcpsrv/tcp_srv_conn.h"
#include "ethernetif.h"
#include "web_srv_int.h"
#include "web_utils.h"
#include "webfs/webfs.h"
#include "flash_eep.h"
#include "device_lock.h"
#include "rtl8195a/rtl_libc.h"
#include "sys_cfg.h"
#include "wifi_api.h"
#include "sys_api.h"
#include "esp_comp.h"
#include "ledeffectsserver.h"
#ifdef USE_NETBIOS
#include "netbios/netbios.h"
#endif
#ifdef USE_SNTP
#include "sntp/sntp.h"
#endif
#ifdef USE_LWIP_PING
#include "lwip/app/ping.h"
struct ping_option pingopt; // for test
#endif
#ifdef USE_CAPTDNS
#include "captdns.h"
#endif
#ifdef USE_MODBUS
#include "modbustcp.h"
#include "mdbtab.h"
#endif
#ifdef USE_RS485DRV
#include "driver/rs485drv.h"
#include "mdbrs485.h"
#endif
#ifdef USE_OVERLAY
#include "overlay.h"
#endif
extern void web_get_ram(TCP_SERV_CONN *ts_conn);
extern void web_get_flash(TCP_SERV_CONN *ts_conn);
extern void web_hexdump(TCP_SERV_CONN *ts_conn);
#define ifcmp(a) if(rom_xstrcmp(cstr, a))
extern int rom_atoi(const char *);
#undef atoi
#define atoi rom_atoi
typedef uint32 (* call_func)(uint32 a, uint32 b, uint32 c);
extern QueueHandle_t xQueueWebSrv;
/******************************************************************************
* FunctionName : parse_url
* Description : parse the received data from the server
* Parameters : CurHTTP -- the result of parsing the url
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR web_int_vars(TCP_SERV_CONN *ts_conn, uint8 *pcmd, uint8 *pvar)
{
WEB_SRV_CONN *web_conn = (WEB_SRV_CONN *)ts_conn->linkd;
uint32 val = ahextoul(pvar);
char *cstr = pcmd;
#if DEBUGSOO > 1
os_printf("[%s=%s]\n", pcmd, pvar);
#endif
ifcmp("start") web_conn->udata_start = val;
else ifcmp("stop") web_conn->udata_stop = val;
// **************************************************************************************************** //
// **************************************** User settings ********************************************* //
else ifcmp("ws_")
{
cstr += 3;
ifcmp("filt_")
{
cstr += 5;
ifcmp("rbw_")
{
cstr += 4;
ifcmp("enbl") filt_rainbow.enabled = (uint8_t)val;
else ifcmp("huesteps") filt_rainbow.hue_steps = (uint8_t)val;
else ifcmp("cyclesteps") filt_rainbow.cycle_steps = (uint8_t)val;
}
else ifcmp("fd_")
{
cstr += 3;
ifcmp("enbl") filt_fade.enabled = (uint8_t)val;
else ifcmp("min") filt_fade.min = (uint8_t)val;
else ifcmp("max") filt_fade.max = (uint8_t)val;
else ifcmp("cyclesteps") filt_fade.steps = (uint8_t)val;
}
}
}
// **************************************************************************************************** //
// **************************************************************************************************** //
#if USE_WEB_AUTH_LEVEL
else ifcmp("user") web_conn->auth_level = UserAuthorization(pvar, strlen(pvar));
else if(web_conn->auth_level < WEB_AUTH_LEVEL_USER) {
if(!web_conn->auth_realm) web_conn->auth_realm = WEB_AUTH_LEVEL_USER;
SetSCB(SCB_AUTH);
return;
}
#endif
#if WEB_DEBUG_FUNCTIONS
else ifcmp("sys_") {
cstr+=4;
ifcmp("restart") {
if(val == 12345) webserver_qfn((web_ex_func_cb)sys_reset, NULL, 200);
}
else ifcmp("ram") { uint32 *ptr = (uint32 *)(ahextoul(cstr+3)&(~3)); str_array(pvar, ptr, 32); }
else ifcmp("debug") print_off = (!val) & 1; // rtl_print on/off
else ifcmp("dsleep") deepsleep_ex(DSLEEP_WAKEUP_BY_TIMER, val);
#ifdef USE_LWIP_PING
else ifcmp("ping") {
// struct ping_option *pingopt = (struct ping_option *)UartDev.rcv_buff.pRcvMsgBuff;
pingopt.ip = ipaddr_addr(pvar);
pingopt.count = 3;
pingopt.recv_function=NULL;
pingopt.sent_function=NULL;
ping_start(&pingopt);
}
#endif
}
#endif // #if WEB_DEBUG_FUNCTIONS
else ifcmp("cfg_") {
cstr += 4;
ifcmp("web_") {
cstr += 4;
ifcmp("port") {
if(syscfg.web_port != val) {
webserver_qfn((web_ex_func_cb)webserver_reinit, (void *)((uint32)syscfg.web_port), 200);
syscfg.web_port = val;
}
}
else ifcmp("twd") {
if(val) {
syscfg.cfg.b.web_time_wait_delete = 1;
ts_conn->pcfg->flag.pcb_time_wait_free = 1;
}
else {
syscfg.cfg.b.web_time_wait_delete = 0;
ts_conn->pcfg->flag.pcb_time_wait_free = 0;
}
}
else ifcmp("twrec") {
syscfg.web_twrec = val;
ts_conn->pcfg->time_wait_rec = val;
}
else ifcmp("twcls") {
syscfg.web_twcls = val;
ts_conn->pcfg->time_wait_cls = val;
}
#if DEBUGSOO > 5
else os_printf(" - none!\n");
#endif
}
else ifcmp("pinclr") syscfg.cfg.b.pin_clear_cfg_enable = (val)? 1 : 0;
else ifcmp("sleep") {
syscfg.cfg.b.powersave_enable = (val)? 1 : 0;
if(val) release_wakelock(~WAKELOCK_WLAN);
else acquire_wakelock(~WAKELOCK_WLAN);
}
else ifcmp("debug") {
syscfg.cfg.b.debug_print_enable = val;
print_off = (!val) & 1; // rtl_print on/off
}
else ifcmp("save") {
if(val == 2) SetSCB(SCB_SYSSAVE); // по закрытию соединения вызвать sys_write_cfg()
else if(val == 1) sys_write_cfg();
}
#ifdef USE_NETBIOS
else ifcmp("netbios") {
syscfg.cfg.b.netbios_ena = (val)? 1 : 0;
if(syscfg.cfg.b.netbios_ena) netbios_init();
else netbios_off();
}
#endif
#ifdef USE_SNTP
else ifcmp("sntp") {
syscfg.cfg.b.sntp_ena = (val)? 1 : 0;
if(syscfg.cfg.b.sntp_ena) sntp_init();
else sntp_stop();
}
#endif
#ifdef USE_CAPTDNS
else ifcmp("cdns") {
syscfg.cfg.b.cdns_ena = (val)? 1 : 0;
if(syscfg.cfg.b.cdns_ena && wifi_softap_get_station_num()) captdns_init();
else captdns_close();
}
#endif
#if DEBUGSOO > 5
else os_printf(" - none!\n");
#endif
// sys_write_cfg();
}
else ifcmp("wifi_") {
cstr+=5;
ifcmp("scan") api_wifi_scan(NULL);
else ifcmp("rdcfg") web_conn->udata_stop = read_wifi_cfg(val);
else ifcmp("newcfg") webserver_qfn((web_ex_func_cb)wifi_run, (void *)((uint32) wifi_cfg.mode), 200);
else ifcmp("mode") wifi_cfg.mode = val;
else ifcmp("bgn") wifi_cfg.bgn = val;
else ifcmp("lflg") wifi_cfg.load_flg = val;
else ifcmp("sflg") wifi_cfg.save_flg = val;
else ifcmp("txpow") wifi_cfg.tx_pwr = val;
else ifcmp("adpt") wifi_cfg.adaptivity = val;
else ifcmp("country") wifi_cfg.country_code = val;
// .. mac wifi_set_mac_address()
// else ifcmp("scan") {
// web_conn->web_disc_par = val;
// web_conn->web_disc_cb = (web_func_disc_cb)wifi_start_scan;
// }
else ifcmp("save") { write_wifi_cfg(val); }
else ifcmp("ap_") {
cstr+=3;
ifcmp("ssid") {
if(pvar[0]!='\0') {
int len = os_strlen(pvar);
if(len > NDIS_802_11_LENGTH_SSID) {
len = NDIS_802_11_LENGTH_SSID;
}
os_memset(wifi_ap_cfg.ssid, 0, sizeof(wifi_ap_cfg.ssid));
os_memcpy(wifi_ap_cfg.ssid, pvar, len);
#ifdef USE_NETBIOS
// netbios_set_name(wlan_ap_netifn, wifi_ap_cfg.ssid);
#endif
}
}
else ifcmp("psw") {
int len = os_strlen(pvar);
if(len > IW_PASSPHRASE_MAX_SIZE) {
len = IW_PASSPHRASE_MAX_SIZE;
}
os_memset(wifi_ap_cfg.password, 0, sizeof(wifi_ap_cfg.password));
os_memcpy(wifi_ap_cfg.password, pvar, len);
}
else ifcmp("chl") wifi_ap_cfg.channel = val;
else ifcmp("mcns") wifi_ap_cfg.max_sta = val;
else ifcmp("auth") wifi_ap_cfg.security = val; // =1 IDX_SECURITY_WPA2_AES_PSK, =0 IDX_SECURITY_OPEN
else ifcmp("hssid") wifi_ap_cfg.ssid_hidden = val;
else ifcmp("bint") wifi_ap_cfg.beacon_interval = val;
#if LWIP_NETIF_HOSTNAME
else ifcmp("hostname") {
int len = os_strlen(pvar);
if(len >= LWIP_NETIF_HOSTNAME_SIZE) {
len = LWIP_NETIF_HOSTNAME_SIZE-1;
}
if(len) {
os_memset(lwip_host_name[1], 0, LWIP_NETIF_HOSTNAME_SIZE);
os_memcpy(lwip_host_name[1], pvar, len);
}
netbios_set_name(WLAN_AP_NETIF_NUM, lwip_host_name[1]);
if(wifi_cfg.save_flg & BID_AP_HOSTNAME) {
WEB_SRV_QFNK x;
x.fnc = write_wifi_cfg;
x.param = (void *)BID_AP_HOSTNAME;
xQueueSendToBack(xQueueWebSrv, &x, 0);
}
}
#endif
else ifcmp("dhcp") wifi_ap_dhcp.mode = val;
else ifcmp("ip") wifi_ap_dhcp.ip = ipaddr_addr(pvar);
else ifcmp("gw") wifi_ap_dhcp.gw = ipaddr_addr(pvar);
else ifcmp("msk") wifi_ap_dhcp.mask = ipaddr_addr(pvar);
// else ifcmp("mac") strtomac(pvar, wifi_ap_cfg.macaddr);
// else ifcmp("sip") wifi_ap_dhcp.start_ip = ipaddr_addr(pvar);
// else ifcmp("eip") wifi_ap_dhcp.end_ip = ipaddr_addr(pvar);
#if DEBUGSOO > 2
else os_printf(" - none! ");
#endif
}
else ifcmp("st_") {
cstr+=3;
ifcmp("arec") wifi_st_cfg.autoreconnect = val;
else ifcmp("rect") wifi_st_cfg.reconnect_pause = val;
else ifcmp("ssid") {
if(pvar[0]!='\0') {
int len = os_strlen(pvar);
if(len > NDIS_802_11_LENGTH_SSID) {
len = NDIS_802_11_LENGTH_SSID;
}
os_memset(wifi_st_cfg.ssid, 0, sizeof(wifi_st_cfg.ssid));
os_memcpy(wifi_st_cfg.ssid, pvar, len);
}
}
else ifcmp("psw") {
int len = os_strlen(pvar);
if(len > IW_PASSPHRASE_MAX_SIZE) {
len = IW_PASSPHRASE_MAX_SIZE;
}
os_memset(wifi_st_cfg.password, 0, sizeof(wifi_st_cfg.password));
os_memcpy(wifi_st_cfg.password, pvar, len);
}
else ifcmp("auth") wifi_st_cfg.security = val;
else ifcmp("bssid") strtomac(pvar, wifi_st_cfg.bssid);
else ifcmp("sbss") wifi_st_cfg.flg = val;
else ifcmp("sleep") wifi_st_cfg.sleep = val;
else ifcmp("dtim") wifi_st_cfg.dtim = val;
#if LWIP_NETIF_HOSTNAME
else ifcmp("hostname") {
int len = os_strlen(pvar);
if(len >= LWIP_NETIF_HOSTNAME_SIZE) {
len = LWIP_NETIF_HOSTNAME_SIZE-1;
}
if(len) {
os_memset(lwip_host_name[0], 0, LWIP_NETIF_HOSTNAME_SIZE);
os_memcpy(lwip_host_name[0], pvar, len);
netbios_set_name(WLAN_ST_NETIF_NUM, lwip_host_name[0]);
}
if(wifi_cfg.save_flg & BID_ST_HOSTNAME) {
WEB_SRV_QFNK x;
x.fnc = write_wifi_cfg;
x.param = (void *)BID_ST_HOSTNAME;
x.pause_ms = 0;
xQueueSendToBack(xQueueWebSrv, &x, 0);
}
}
#endif
else ifcmp("dhcp") wifi_st_dhcp.mode = val;
else ifcmp("ip") wifi_st_dhcp.ip = ipaddr_addr(pvar);
else ifcmp("gw") wifi_st_dhcp.gw = ipaddr_addr(pvar);
else ifcmp("msk") wifi_st_dhcp.mask = ipaddr_addr(pvar);
// else ifcmp("mac") strtomac(pvar, wifi_st_cfg.mac);
// else ifcmp("sbss") wifi_st_cfg.bssidx = val;
#if DEBUGSOO > 5
else os_printf(" - none!\n");
#endif
}
#if DEBUGSOO > 5
else os_printf(" - none!\n");
#endif
}
#if WEB_DEBUG_FUNCTIONS
else if(web_conn->bffiles[0]==WEBFS_WEBCGI_HANDLE && CheckSCB(SCB_GET)) {
ifcmp("hexdmp") {
#if DEBUGSOO > 5
os_printf("hexdmp(%p)\n", val);
#endif
if(val > 0) {
if(cstr[6]=='d') ts_conn->flag.user_option1 = 1;
else ts_conn->flag.user_option1 = 0;
uint32 x = ahextoul(cstr+7);
web_conn->udata_start = x;
web_conn->udata_stop = val + web_conn->udata_start;
#if DEBUGSOO > 5
os_printf("start=%p, stop=%p\n", web_conn->udata_start, web_conn->udata_stop);
#endif
web_conn->fileType = HTTP_TXT;
SetSCB(SCB_RETRYCB | SCB_FCALBACK);
SetNextFunSCB(web_hexdump);
};
}
else ifcmp("flash") {
cstr+=5;
if(*cstr == '_') {
cstr++;
ifcmp("all") {
web_conn->udata_start = 0;
web_conn->udata_stop = spi_flash_real_size();
web_conn->fileType = HTTP_BIN;
SetSCB(SCB_RETRYCB | SCB_FCALBACK);
SetNextFunSCB(web_get_flash);
}
else ifcmp("sec_") {
web_conn->udata_start = ahextoul(cstr+4) << 12;
web_conn->udata_stop = web_conn->udata_start + FLASH_SECTOR_SIZE*val;
web_conn->fileType = HTTP_BIN;
SetSCB(SCB_RETRYCB | SCB_FCALBACK);
SetNextFunSCB(web_get_flash);
}
else ifcmp("disk") {
web_conn->udata_start = WEBFS_base_addr();
web_conn->udata_stop = web_conn->udata_start + WEBFS_curent_size();
web_conn->fileType = HTTP_BIN;
SetSCB(SCB_RETRYCB | SCB_FCALBACK);
SetNextFunSCB(web_get_flash);
}
else tcp_put('?');
}
else {
web_conn->fileType = HTTP_BIN;
SetSCB(SCB_RETRYCB | SCB_FCALBACK);
SetNextFunSCB(web_get_flash);
}
}
else ifcmp("bin_ram") {
web_conn->fileType = HTTP_BIN;
SetSCB(SCB_RETRYCB | SCB_FCALBACK);
SetNextFunSCB(web_get_ram);
}
#if DEBUGSOO > 5
else os_printf(" - none! ");
#endif
}
#endif // #if WEB_DEBUG_FUNCTIONS
#if DEBUGSOO > 5
else os_printf(" - none! ");
#endif
}
#endif // USE_WEB

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,210 @@
/*
* File: web_srv.h
* Description: The web server configration.
* Small WEB server ESP8266EX
* Author: PV`
*/
#ifndef _INCLUDE_WEB_SRV_H_
#define _INCLUDE_WEB_SRV_H_
#include "tcpsrv/tcp_srv_conn.h"
#ifdef WEBSOCKET_ENA
#include "websock.h"
#endif
#define WEB_SVERSION "0.2.0"
#define DEFAULT_WEB_PORT USE_WEB // 80
#define USE_WEB_AUTH_LEVEL 0 // 1
/****************************************************************************
***************************************************************************/
typedef enum
{
WEB_AUTH_NONE = 0,
WEB_AUTH_LEVEL_USER,
WEB_AUTH_LEVEL_USER1,
WEB_AUTH_LEVEL_WEBFS,
WEB_AUTH_LEVEL_OTA,
WEB_AUTH_LEVEL_SUPERVISOR
} WEB_AUTH_LEVEL_TYPE;
// File type definitions
typedef enum
{
HTTP_TXT = 0, // File is a text document
HTTP_HTML, // File is HTML (extension .htm)
HTTP_CGI, // File is HTML (extension .cgi)
HTTP_XML, // File is XML (extension .xml)
HTTP_CSS, // File is stylesheet (extension .css)
HTTP_ICO, // File is ICO vnd.microsoft.icon
HTTP_GIF, // File is GIF image (extension .gif)
HTTP_PNG, // File is PNG image (extension .png)
HTTP_JPG, // File is JPG image (extension .jpg)
HTTP_SVG, // File is SVG image (extension .svg)
HTTP_JAVA, // File is java (extension .js)
HTTP_SWF, // File is ShockWave-Flash (extension .swf)
HTTP_WAV, // File is audio (extension .wav)
HTTP_PDF, // File is PDF (extension .pdf)
HTTP_ZIP, // File is ZIP (extension .zip)
HTTP_BIN, // File is BIN (extension .bin)
HTTP_UNKNOWN // File type is unknown
} HTTP_FILE_TYPE;
// extended state data for each connection
#define FileNameSize 64
#define VarNameSize 64
#define CmdNameSize 32
typedef struct
{
uint16 httpStatus; // Request method/status
uint16 uri_len;
uint16 head_len;
uint16 cookie_len;
uint8 pFilename[FileNameSize];
uint8 *puri; // указатель на строку с переменными запроса к файлу
uint8 *phead; // HTTP Headers
uint8 *pcookie; // cookie
uint8 *pcontent; // content
uint32 content_len; //
uint8 httpver; // версия HTTP клиента в BCD (0x00 = неизвестен; 0x09 = HTTP/0.9; 0x10 = HTTP/1.0; 0x11 = HTTP/1.1)
uint8 fileType; // File type to return with Content-Type
} HTTP_CONN;
typedef void (* web_func_cb)(TCP_SERV_CONN *ts_conn);
typedef uint32 (* web_ex_func_cb)(uint32 flg); // внешняя или отложенная функция
typedef struct
{
web_ex_func_cb fnc;
void * param;
uint16 pause_ms;
} WEB_SRV_QFNK;
typedef struct
{
uint32 webflag; // флаги для http/web сервера
uint8 bffiles[4]; // четыре Files pointers для оработки вложенных файлов include
uint32 udata_start; // udata "start=0x..."
uint32 udata_stop; // udata "stop=0x..."
uint8 *msgbuf; // указатель на текущий буфер вывода
uint16 msgbuflen; // кол-во занятых байт в буфере msgbuf
uint16 msgbufsize; // размер буфера
web_func_cb func_web_cb; // calback функция у httpd для обработки приема/передачи кусками
uint32 content_len; // размер файла для передачи (GET/POST) или приема, если принимается внешний файл (POST + SCB_RXDATA)
#ifdef WEBSOCKET_ENA
WS_FRSTAT ws; // параметры websoc
#endif
#if USE_WEB_AUTH_LEVEL
uint8 auth_level; // Уровень авторизации пользователя по паролю WEB_AUTH_LEVEL_TYPE
uint8 auth_realm; // Требуемый уровень авторизации (минимальный уровень) WEB_AUTH_LEVEL_TYPE
#endif
uint8 fileType; // File type to return with Content-Type (if SCB_FCALBACK)
} WEB_SRV_CONN;
typedef enum
{
WEBFS_MAX_HANDLE = 251,
WEBFS_NODISK_HANDLE,
WEBFS_WEBCGI_HANDLE,
WEBFS_UPLOAD_HANDLE
} WEBFS_NUM_HANDLE;
// webflag:
#define SCB_CLOSED 0x000001 // соединение закрыто
#define SCB_DISCONNECT 0x000002 // выход на DISCONNECT
#define SCB_FCLOSE 0x000004 // закрыть файлы
#define SCB_FOPEN 0x000008 // файл(ы) открыт(ы)
#define SCB_FCALBACK 0x000010 // file use ~calback~
#define SCB_FGZIP 0x000020 // файл GZIP
#define SCB_CHUNKED 0x000040 // передача шинковкой
#define SCB_RETRYCB 0x000080 // вызвать повтор CalBack
#define SCB_POST 0x000100 // POST
#define SCB_GET 0x000200 // GET
#define SCB_AUTH 0x000400 // необходима авторизация
#define SCB_FINDCB 0x000800 // используется парсингом ~calback~
#define SCB_RXDATA 0x001000 // прием данных (файла)
#define SCB_HEAD_OK 0x002000 // заголовок HTTP принят и обработан
#define SCB_BNDR 0x004000 // прилеплен Content-Type: multipart/form-data; boundary="..."
#define SCB_REDIR 0x008000 // Redirect 302
#define SCB_WEBSOC 0x010000 // WebSocket
#define SCB_WSDATA 0x020000 // WebSocket data
#define SCB_SYSSAVE 0x040000 // по закрытию соединения вызвать sys_write_cfg()
#define SCB_OPEN 0
#define SetSCB(a) web_conn->webflag |= a
#define FreeSCB() web_conn->webflag = SCB_FREE
#define SetNextFunSCB(a) web_conn->func_web_cb = a
#define ClrSCB(a) web_conn->webflag &= ~(a)
#define CheckSCB(a) (web_conn->webflag & (a))
#define FreeSCB() web_conn->webflag = SCB_FREE
#define OpenSCB() web_conn->webflag = SCB_OPEN
#define MAXLENBOUNDARY 64
typedef struct s_http_upload
{
uint16 status;
uint16 sizeboundary;
uint8 boundary[MAXLENBOUNDARY+1];
uint8 name[VarNameSize];
uint8 filename[VarNameSize];
#ifdef USE_OVERLAY
uint32 segs; // кол-во сегментов оверлея // пока в web_conn->web_disc_par
uint32 start; // адрес запуска оверлея
#endif
uint32 fsize;
uint32 faddr;
uint8 *pbndr;
uint8 *pnext;
} HTTP_UPLOAD;
typedef struct s_http_response
{
uint32 status;
uint32 flag;
const char * headers;
const char * default_content;
} HTTP_RESPONSE;
// HTTP_RESPONSE.flags:
#define HTTP_RESP_FLG_END 0x8000
#define HTTP_RESP_FLG_NONE 0x0000
#define HTTP_RESP_FLG_FINDFILE 0x0001
#define HTTP_RESP_FLG_REDIRECT 0x0002
#define tcp_put(a) web_conn->msgbuf[web_conn->msgbuflen++] = a
#define tcp_htmlstrcpy(str, len) web_conn->msgbuflen += htmlcode(&web_conn->msgbuf[web_conn->msgbuflen], str, web_conn->msgbufsize - web_conn->msgbuflen - 1, len)
//#define tcp_urlstrcpy(str, len) web_conn->msgbuflen += urlencode(&web_conn->msgbuf[web_conn->msgbuflen], str, web_conn->msgbufsize - web_conn->msgbuflen - 1, len)
#define tcp_puts(...) web_conn->msgbuflen += rtl_sprintf((char *)&web_conn->msgbuf[web_conn->msgbuflen], __VA_ARGS__)
#define tcp_puts_fd(...) web_conn->msgbuflen += rtl_sprintf((char *)&web_conn->msgbuf[web_conn->msgbuflen], __VA_ARGS__)
/*
#define tcp_puts_fd(fmt, ...) do { \
static const char flash_str[] ICACHE_RODATA_ATTR = fmt; \
web_conn->msgbuflen += rtl_sprintf((char *)&web_conn->msgbuf[web_conn->msgbuflen], (char *)flash_str, ##__VA_ARGS__); \
} while(0)
*/
//#define tcp_strcpy(a) web_conn->msgbuflen += ets_strlen((char *)ets_strcpy((char *)&web_conn->msgbuf[web_conn->msgbuflen], (char *)a))
#define tcp_strcpy(a) web_conn->msgbuflen += rom_xstrcpy((char *)&web_conn->msgbuf[web_conn->msgbuflen], (const char *)a)
#define tcp_strcpy_fd(a) web_conn->msgbuflen += rom_xstrcpy((char *)&web_conn->msgbuf[web_conn->msgbuflen], (const char *)a)
/*
#define tcp_strcpy_fd(fmt) do { \
static const char flash_str[] ICACHE_RODATA_ATTR = fmt; \
web_conn->msgbuflen += rom_xstrcpy((char *)&web_conn->msgbuf[web_conn->msgbuflen], (char *)flash_str); \
} while(0)
*/
uint32 ahextoul(uint8 *s);
err_t webserver_init(uint16 portn);
err_t webserver_close(uint16 portn);
err_t webserver_reinit(uint16 portn);
BaseType_t webserver_qfn(web_ex_func_cb fnc, void * param, uint16 pause_ms); // вызов функции из task с low priority
#endif /* _INCLUDE_WEB_SRV_H_ */

View file

@ -0,0 +1,48 @@
/*
* File: web_srv_int.h
* Description: The web server configration.
* Small WEB server ESP8266EX
*
* Author: PV` 12/2014
*/
#ifndef _INCLUDE_WEB_SRV_INT_H_
#define _INCLUDE_WEB_SRV_INT_H_
#include "web_srv.h"
#define WEB_NAME_VERSION "PVs/0.2"
// lifetime (sec) of static responses as string 60*60*24*14=1209600"
#define FILE_CACHE_MAX_AGE_SEC 3600 // время для кеша файлов, ставить 0 пока тест!
#define MAX_HTTP_HEAD_BUF TCP_SRV_SERVER_MAX_RXBUF // максимальный размер HTTP запроса (GET)
#define RESCHKS_SEND_SIZE 16
#define RESCHKE_SEND_SIZE 8
#define RESCHK_SEND_SIZE (RESCHKS_SEND_SIZE + RESCHKE_SEND_SIZE)
#define MIN_SEND_SIZE (256 + RESCHK_SEND_SIZE) // минимальный размер буфера для передачи файла
#define MAX_SEND_SIZE ((TCP_SND_BUF) + RESCHK_SEND_SIZE) // ((TCP_MSS*4) + RESCHK_SEND_SIZE) // максимальный размер буфера для передачи 4*MSS = 5840 (MSS=1460)
#define HTTP_SEND_SIZE 384 // минимальный размер буфера для передачи заголовка HTTP
#define SCB_SEND_SIZE 128 // минимальный резерв в буфере для callback
#define webfile bffiles[0] // File pointer for main file
//-----------------------------------------------------------------------------
void web_int_vars(TCP_SERV_CONN *ts_conn, uint8 *pcmd, uint8 *pvar);
void web_int_cookie(HTTP_CONN *CurHTTP, TCP_SERV_CONN *ts_conn);
void web_int_callback(TCP_SERV_CONN *ts_conn, uint8 *cstr);
void web_hexdump(TCP_SERV_CONN *ts_conn);
bool web_inc_fopen(TCP_SERV_CONN *ts_conn, uint8 *cFile);
bool web_inc_fclose(WEB_SRV_CONN *web_conn);
bool web_trim_bufi(TCP_SERV_CONN *ts_conn, uint8 *pdata, uint32 data_len);
bool web_feee_bufi(TCP_SERV_CONN *ts_conn);
//uint8 * head_find_ctr(HTTP_CONN *CurHTTP, const uint8 * c, int clen, int dlen);
uint8 UserAuthorization(uint8 *pbuf, size_t declen);
#endif /* _INCLUDE_WEB_SRV_INT_H_ */

View file

@ -0,0 +1,680 @@
/*
* web_utils.c
*
* Created on: 25 дек. 2014 г.
* Author: PV`
*/
#include "user_config.h"
#include "autoconf.h"
#include "FreeRTOS.h"
#include "task.h"
#include "diag.h"
//#include "bios.h"
//#include "sdk/add_func.h"
//#include "ets_sys.h"
//#include "os_type.h"
//#include "osapi.h"
//#include "user_interface.h"
#include "web_utils.h"
#include "esp_comp.h"
#define mMIN(a, b) ((a<b)?a:b)
/******************************************************************************
* xstrcpy() из сегментов flash и IRAM с возвратом размера строки:
* на выходе размер строки, без учета терминатора '\0'
*******************************************************************************/
int ICACHE_RAM_ATTR rom_xstrcpy(char * pd, const char * ps)
{
#if 0
union {
unsigned char uc[4];
unsigned int ud;
}tmp;
if(ps == 0 || pd == 0) return (0);
*pd = 0;
unsigned int len = 0;
unsigned int *p = (unsigned int *)((unsigned int)ps & (~3));
unsigned int xlen = (unsigned int)ps & 3;
while(1) {
tmp.ud = *p++;
do {
if((*pd++ = tmp.uc[xlen++]) == 0) return len;
len++;
xlen &= 3;
} while(xlen);
}
#else
int len = 0;
while((*pd++ = *ps++) != 0) len++;
return len;
#endif
}
/******************************************************************************
* сравнение строки в ram со строкой в сегменте flash и IRAM
* = 1 если шаблон совпадает
*******************************************************************************/
int ICACHE_RAM_ATTR rom_xstrcmp(char * pd, const char * ps)
{
#if 0
union {
unsigned char uc[4];
unsigned int ud;
}tmp;
if(ps == 0 || pd == 0) return 0;
unsigned int *p = (unsigned int *)((unsigned int)ps & (~3));
unsigned int xlen = (unsigned int)ps & 3;
while(1) {
tmp.ud = *p++;
do {
if(tmp.uc[xlen] == 0) return 1;
if(tmp.uc[xlen++] != *pd || *pd++ == 0) return 0;
xlen &= 3;
} while(xlen);
}
#else
while(*ps) {
if(*pd++ != *ps++) return 0;
}
return 1;
#endif
}
/******************************************************************************
* rom_atoi
*******************************************************************************/
int ICACHE_FLASH_ATTR rom_atoi(const char *s)
{
int n=0, neg=0;
while (*s == ' ') s++;
switch (*s) {
case '-': neg=1;
case '+': s++;
}
/* Compute n as a negative number to avoid overflow on INT_MIN */
while (*s >= '0' && *s <= '9')
n = 10*n - (*s++ - '0');
return neg ? n : -n;
}
/******************************************************************************
* get_seg_id()
*******************************************************************************/
const char * const txt_tab_seg[] = {
"ROM" // 0
"SRAM", // 1
"TCM", // 2
"FLASH", // 3 // -> flash On
"SDRAM", // 4 // -> Test ChipID or HAL_PERI_ON_WRITE32(REG_SOC_FUNC_EN, HAL_PERI_ON_READ32(REG_SOC_FUNC_EN) | BIT(21)); // Flag SDRAM Off
"SOC", // 5 // protected !
"CPU", // 6 // protected !
"UNK", // 7
};
const uint32 tab_seg_def[] = {
0x00000000, 0x00050000,
0x10000000, 0x10070000,
0x1fff0000, 0x20000000,
0x98000000, 0xA0000000,
0x30000000, 0x30200000,
0x40000000, 0x40800000,
0xE0000000, 0xE0010000,
0x00000000, 0xFFFFFFFF
};
SEG_ID get_seg_id(uint32 addr, int32 size) {
SEG_ID ret = SEG_ID_ERR;
uint32 * ptr = (uint32 *) &tab_seg_def;
if (size > 0) {
do {
ret++;
if (addr >= ptr[0] && addr + size <= ptr[1]) {
return ret;
};
ptr += 2;
} while (ret < SEG_ID_MAX);
};
return 0;
}
/******************************************************************************
* copy_align4
* копирует данные из области кеширования flash и т.д.
*******************************************************************************/
void ICACHE_FLASH_ATTR copy_align4(void *ptrd, void *ptrs, uint32 len)
{
union {
uint8 uc[4];
uint32 ud;
}tmp;
uint8 *pd = ptrd;
uint32 *p = (uint32 *)((uint32)ptrs & (~3));
uint32 xlen = ((uint32)ptrs) & 3;
if(xlen) {
if(((uint32)p >= 0x10000000)&&((uint32)p < 0x9A002000)) tmp.ud = *p++;
else {
tmp.ud = 0;
p++;
}
while (len) {
*pd++ = tmp.uc[xlen++];
len--;
if(xlen >= 4) break;
}
}
xlen = len >> 2;
while(xlen) {
if(((uint32)p >= 0x10000000)&&((uint32)p < 0x9A002000)) tmp.ud = *p++;
else {
tmp.ud = 0;
p++;
}
*pd++ = tmp.uc[0];
*pd++ = tmp.uc[1];
*pd++ = tmp.uc[2];
*pd++ = tmp.uc[3];
xlen--;
}
len &= 3;
if(len) {
if(((uint32)p >= 0x10000000)&&((uint32)p < 0x9A002000)) tmp.ud = *p;
else tmp.ud = 0;
uint8 * ptmp = tmp.uc;
while (len--) *pd++ = *ptmp++;
}
}
/******************************************************************************
* FunctionName : hextoul
*******************************************************************************/
// bool conv_str_hex(uint32 * dest, uint8 *s);
uint32 ICACHE_FLASH_ATTR hextoul(uint8 *s)
{
/*
uint32 val;
if(!conv_str_hex(&val, s)) return 0;
return val;
*/
uint32 val = 0;
while (*s)
{
if (*s >= '0' && *s <= '9')
{
val <<= 4;
val |= *s - '0';
}
else if (*s >= 'A' && *s <= 'F')
{
val <<= 4;
val |= *s - 'A' + 10;
}
else if (*s >= 'a' && *s <= 'f')
{
val <<= 4;
val |= *s - 'a' + 10;
}
else break;
s++;
};
return val;
}
/******************************************************************************
* FunctionName : ahextoul
*******************************************************************************/
// bool convert_para_str(uint32 * dest, uint8 *s);
uint32 ICACHE_FLASH_ATTR ahextoul(uint8 *s)
{
/*
uint32 ret;
if(!convert_para_str(&ret, s)) return 0;
return ret;
*/
if((s[0]=='0') && ((s[1] | 0x20) =='x')) return hextoul(s+2);
return rom_atoi(s);
}
/******************************************************************************
* FunctionName : cmpcpystr
* Description : выбирает слово из строки текста с заданными начальным символом
* и конечным терминатором. Терминатор и стартовый символ не копирует, если заданы.
* Parameters : При задании начального символа = '\0' берется любой символ (>' ').
Копирует до символа <' ' или терминатора.
Задается ограничение размера буфера для копируемого слова (с дописыванием в буфер '\0'!).
* Returns : Зависит от значения терминатора, указывает на терминатор в строке,
если терминатор найден.
Если NULL, то начальный или конечный терминатор не найден.
*******************************************************************************/
uint8 * ICACHE_FLASH_ATTR cmpcpystr(uint8 *pbuf, uint8 *pstr, uint8 a, uint8 b, uint16 len)
{
if(len == 0) pbuf = NULL;
if(pstr == NULL) {
if(pbuf != NULL) *pbuf='\0';
return NULL;
};
uint8 c;
do {
c = *pstr;
if(c < ' ') { // строка кончилась
if(pbuf != NULL) *pbuf='\0';
return NULL; // id не найден
};
if((a == '\0')&&(c > ' ')) break; // не задан -> любой символ
pstr++;
if(c == a) break; // нашли стартовый символ (некопируемый в буфер)
}while(1);
if(pbuf != NULL) {
while(len--) {
c = *pstr;
if(c == b) { // нашли терминирующий символ (некопируемый в буфер)
*pbuf='\0';
return pstr; // конечный терминатор найден
};
// if(c <= ' ') { // строка кончилась или пробел
if(c < ' ') { // строка кончилась или пробел
*pbuf='\0';
return NULL; // конечный терминатор не найден
};
pstr++;
*pbuf++ = c;
};
*--pbuf='\0'; // закрыть буфер
};
do {
c = *pstr;
if(c == b) return pstr; // нашли терминирующий символ
// if(c <= ' ') return NULL; // строка кончилась
if(c < ' ') return NULL; // строка кончилась
pstr++;
}while(1);
}
/******************************************************************************
* FunctionName : str_array
* Набирает из строки s массив слов в buf в кол-ве до max_buf
* возврат - кол-во переменных в строке
* Разделитель переменных в строке ','
* Если нет переменной, то пропускает изменение в buf
* Примеры:
* Строка "1,2,3,4" -> buf = 0x01 0x02 0x03 0x04
* Строка "1,,3," -> buf = 0x01 (не изменено) 0x03 (не изменено)
*******************************************************************************/
uint32 ICACHE_FLASH_ATTR str_array(uint8 *s, uint32 *buf, uint32 max_buf)
{
uint32 ret = 0;
uint8 *sval = NULL;
while(max_buf > ret) {
if(sval == NULL) {
if (*s == '-' && s[1] >= '0' && s[1] <= '9') {
sval = s;
s++;
}
else if (*s >= '0' && *s <= '9') sval = s;
}
if(*s == ',' || *s <= ')') {
if(sval != NULL) {
*buf = ahextoul(sval);
sval = NULL;
}
buf++;
ret++;
if(*s < ')') return ret;
}
s++;
}
return ret;
}
uint32 ICACHE_FLASH_ATTR str_array_w(uint8 *s, uint16 *buf, uint32 max_buf)
{
uint32 ret = 0;
uint8 *sval = NULL;
while(max_buf > ret) {
if(sval == NULL) {
if (*s == '-' && s[1] >= '0' && s[1] <= '9') {
sval = s;
s++;
}
else if (*s >= '0' && *s <= '9') sval = s;
}
if(*s == ',' || *s <= ')') {
if(sval != NULL) {
*buf = ahextoul(sval);
sval = NULL;
}
buf++;
ret++;
if(*s < ')') return ret;
}
s++;
}
return ret;
}
uint32 ICACHE_FLASH_ATTR str_array_b(uint8 *s, uint8 *buf, uint32 max_buf)
{
uint32 ret = 0;
uint8 *sval = NULL;
while(max_buf > ret) {
if(sval == NULL) {
if (*s == '-' && s[1] >= '0' && s[1] <= '9') {
sval = s;
s++;
}
else if (*s >= '0' && *s <= '9') sval = s;
}
if(*s == ',' || *s == '.' || *s <= ')') {
if(sval != NULL) {
*buf = ahextoul(sval);
sval = NULL;
}
buf++;
ret++;
if(*s < ')') return ret;
}
s++;
}
return ret;
}
/******************************************************************************
* FunctionName : strtmac
*******************************************************************************/
void ICACHE_FLASH_ATTR strtomac(uint8 *s, uint8 *macaddr)
{
uint8 pbuf[4];
s = cmpcpystr(pbuf, s, 0, ':', 3);
*macaddr++ = hextoul(pbuf);
int i = 4;
while(i--) {
s = cmpcpystr(pbuf, s, ':', ':', 3);
*macaddr++ = hextoul(pbuf);
}
s = cmpcpystr(pbuf, s, ':', ' ', 3);
*macaddr++ = hextoul(pbuf);
}
/******************************************************************************
* FunctionName : urldecode
*******************************************************************************/
int ICACHE_FLASH_ATTR urldecode(uint8 *d, uint8 *s, uint16 lend, uint16 lens)
{
uint16 ret = 0;
if(s != NULL) while ((lens--) && (lend--) && (*s > ' ')) {
if ((*s == '%')&&(lens > 1)) {
s++;
int i = 2;
uint8 val = 0;
while(i--) {
if (*s >= '0' && *s <= '9') {
val <<= 4;
val |= *s - '0';
} else if (*s >= 'A' && *s <= 'F') {
val <<= 4;
val |= *s - 'A' + 10;
} else if (*s >= 'a' && *s <= 'f') {
val <<= 4;
val |= *s - 'a' + 10;
} else
break;
s++;
lens--;
};
s--;
*d++ = val;
} else if (*s == '+')
*d++ = ' ';
else
*d++ = *s;
ret++;
s++;
}
*d = '\0';
return ret;
}
/******************************************************************************
* FunctionName : urlencode
*******************************************************************************/
/*int ICACHE_FLASH_ATTR urlencode(uint8 *d, uint8 *s, uint16 lend, uint16 lens)
{
uint16 ret = 0;
if(s != NULL) while ((lens--) && (lend--) && (*s != '\0')) {
if ( (48 <= *s && *s <= 57) //0-9
|| (65 <= *s && *s <= 90) //abc...xyz
|| (97 <= *s && *s <= 122) //ABC...XYZ
|| (*s == '~' || *s == '!' || *s == '*' || *s == '(' || *s == ')' || *s == '\'')) {
*d++ = *s++;
ret++;
} else {
if(lend >= 3) {
ret += 3;
lend -= 3;
*d++ = '%';
uint8 val = *s >> 4;
if(val <= 9) val += '0';
else val += 0x41 - 10;
*d++ = val;
val = *s++ & 0x0F;
if(val <= 9) val += '0';
else val += 0x41 - 10;
*d++ = val;
}
else break;
}
}
*d = '\0';
return ret;
}*/
/******************************************************************************
* FunctionName : htmlcode
*******************************************************************************/
int ICACHE_FLASH_ATTR htmlcode(uint8 *d, uint8 *s, uint16 lend, uint16 lens)
{
uint16 ret = 0;
if(s != NULL) while ((lens--) && (lend--) && (*s != '\0')) {
if ( *s == 0x27 ) { // "'" &apos;
if(lend >= 6) {
ret += 6;
lend -= 6;
s++;
*d++ = '&';
*d++ = 'a';
*d++ = 'p';
*d++ = 'o';
*d++ = 's';
*d++ = ';';
}
else break;
} else if ( *s == '"' ) { // &quot;
if(lend >= 6) {
ret += 6;
lend -= 6;
s++;
*d++ = '&';
*d++ = 'q';
*d++ = 'u';
*d++ = 'o';
*d++ = 't';
*d++ = ';';
}
else break;
} else if ( *s == '&' ) { // &amp;
if(lend >= 5) {
ret += 5;
lend -= 5;
s++;
*d++ = '&';
*d++ = 'a';
*d++ = 'm';
*d++ = 'p';
*d++ = ';';
}
else break;
} else if ( *s == '<' ) { // &lt;
if(lend >= 4) {
ret += 4;
lend -= 4;
s++;
*d++ = '&';
*d++ = 'l';
*d++ = 't';
*d++ = ';';
}
else break;
} else if ( *s == '>' ) { // &gt;
if(lend >= 4) {
ret += 4;
lend -= 4;
s++;
*d++ = '&';
*d++ = 'g';
*d++ = 't';
*d++ = ';';
}
else break;
} else {
*d++ = *s++;
ret++;
}
}
*d = '\0';
return ret;
}
//=============================================================================
extern size_t rtl_strlen(const char *str);
extern int rtl_strncmp(const char *s1, const char *s2, size_t n);
uint8* ICACHE_FLASH_ATTR
web_strnstr(const uint8* buffer, const uint8* token, int len)
{
const uint8* p;
int tokenlen = rtl_strlen(token);
if (tokenlen == 0) {
return (uint8 *)buffer;
};
for (p = buffer; *p && (p + tokenlen <= buffer + len); p++) {
if ((*p == *token) && (rtl_strncmp(p, token, tokenlen) == 0)) {
return (uint8 *)p;
};
};
return NULL;
}
//=============================================================================
static const uint8_t base64map[128] ICACHE_RODATA_ATTR =
{
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255,
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255
};
//=============================================================================
bool ICACHE_FLASH_ATTR base64decode(const uint8 *in, int len, uint8_t *out, int *outlen)
{
// uint8 *map = (uint8 *)UartDev.rcv_buff.pRcvMsgBuff;
// ets_memcpy(map, base64map, 128);
uint8 *map = (uint8 *) base64map;
int g, t, x, y, z;
uint8_t c;
g = 3;
for (x = y = z = t = 0; x < len; x++) {
if ((c = map[in[x]&0x7F]) == 0xff) continue;
if (c == 254) { /* this is the end... */
c = 0;
if (--g < 0) return false;
}
else if (g != 3) return false; /* only allow = at end */
t = (t<<6) | c;
if (++y == 4) {
out[z++] = (uint8_t)((t>>16)&255);
if (g > 1) out[z++] = (uint8_t)((t>>8)&255);
if (g > 2) out[z++] = (uint8_t)(t&255);
y = t = 0;
}
/* check that we don't go past the output buffer */
if (z > *outlen) return false;
}
if (y != 0) return false;
*outlen = z;
return true;
}
//=============================================================================
/* Table 6-bit-index-to-ASCII used for base64-encoding */
const uint8_t base64_table[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'+', '/'
};
// ld: PROVIDE ( base64_table = 0x3FFFD600 );
//extern const uint8_t base64_table[];
//=============================================================================
/** Base64 encoding */
size_t ICACHE_FLASH_ATTR base64encode(char* target, size_t target_len, const char* source, size_t source_len)
{
size_t i;
sint8 j;
size_t target_idx = 0;
size_t longer = 3 - (source_len % 3);
size_t source_len_b64 = source_len + longer;
size_t len = (((source_len_b64) * 4) / 3);
uint8 x = 5;
uint8 current = 0;
if(target == NULL || target_len < len) return 0;
for (i = 0; i < source_len_b64; i++) {
uint8 b = (i < source_len ? source[i] : 0);
for (j = 7; j >= 0; j--, x--) {
uint8 shift = ((b & (1 << j)) != 0) ? 1 : 0;
current |= shift << x;
if (x == 0) {
target[target_idx++] = base64_table[current];
x = 6;
current = 0;
}
}
}
for (i = len - longer; i < len; i++) {
target[i] = '=';
}
return len;
}
/*
//=============================================================================
void ICACHE_FLASH_ATTR print_hex_dump(uint8 *buf, uint32 len, uint8 k)
{
if(!system_get_os_print()) return; // if(*((uint8 *)(0x3FFE8000)) == 0) return;
uint32 ss[2];
ss[0] = 0x78323025; // "%02x"
ss[1] = k; // ","...'\0'
uint8* ptr = buf;
while(len--) {
if(len == 0) ss[1] = 0;
ets_printf((uint8 *)&ss[0], *ptr++);
}
}
*/
//=============================================================================
#define LowerCase(a) ((('A' <= a) && (a <= 'Z')) ? a + 32 : a)
char* ICACHE_FLASH_ATTR word_to_lower_case(char* text) {
for(; *text ==' '; text++);
char* p = text;
for (; *p >= ' '; p++) {
*p = LowerCase(*p);
}
return text;
}
#if 0
//=============================================================================
/* char UpperCase(char ch) {
return (('a' <= ch) && (ch <= 'z')) ? ch - 32 : ch; }*/
#define UpperCase(a) ((('a' <= a) && (a <= 'z')) ? a - 32 : a)
char* ICACHE_FLASH_ATTR str_to_upper_case(char* text) {
char* p = text;
for (; *p; ++p) {
*p = UpperCase(*p);
}
return text;
}
#endif

View file

@ -0,0 +1,48 @@
/******************************************************************************
* FileName: web_utils.h
* Alternate SDK
* Author: PV`
* (c) PV` 2015
*******************************************************************************/
#ifndef _INCLUDE_WEB_UTILS_H_
#define _INCLUDE_WEB_UTILS_H_
typedef enum {
SEG_ID_ROM = 0,
SEG_ID_SRAM,
SEG_ID_TCM,
SEG_ID_FLASH,
SEG_ID_SDRAM,
SEG_ID_SOC,
SEG_ID_CPU,
SEG_ID_ERR,
SEG_ID_MAX
} SEG_ID;
extern const uint32 tab_seg_def[];
SEG_ID get_seg_id(uint32 addr, int32 size);
int rom_atoi(const char *s);
void copy_align4(void *ptrd, void *ptrs, uint32 len);
uint32 hextoul(uint8 *s);
uint32 ahextoul(uint8 *s);
uint8 * cmpcpystr(uint8 *pbuf, uint8 *pstr, uint8 a, uint8 b, uint16 len);
uint8 * web_strnstr(const uint8* buffer, const uint8* token, int n);
bool base64decode(const uint8 *in, int len, uint8_t *out, int *outlen);
size_t base64encode(char* target, size_t target_len, const char* source, size_t source_len);
void strtomac(uint8 *s, uint8 *macaddr);
//uint32 strtoip(uint8 *s); // ipaddr_addr();
int urldecode(uint8 *d, uint8 *s, uint16 lend, uint16 lens);
//int urlencode(uint8 *d, uint8 *s, uint16 lend, uint16 lens);
int htmlcode(uint8 *d, uint8 *s, uint16 lend, uint16 lens);
void print_hex_dump(uint8 *buf, uint32 len, uint8 k);
// char* str_to_upper_case(char* text);
uint32 str_array(uint8 *s, uint32 *buf, uint32 max_buf);
uint32 str_array_w(uint8 *s, uint16 *buf, uint32 max_buf);
uint32 str_array_b(uint8 *s, uint8 *buf, uint32 max_buf);
char* word_to_lower_case(char* text);
int rom_xstrcmp(char * pd, const char * ps);
int rom_xstrcpy(char * pd, const char * ps);
#endif /* _INCLUDE_WEB_UTILS_H_ */

View file

@ -0,0 +1,352 @@
/******************************************************************************
* FileName: web_websocket.c
* Description: websocket for web
* Author: pvvx
* 2016
*******************************************************************************/
#include "user_config.h"
#ifdef WEBSOCKET_ENA
#include "autoconf.h"
#include "FreeRTOS.h"
#include "task.h"
#include "diag.h"
//#include "bios.h"
//#include "osapi.h"
//#include "sdk/rom2ram.h"
#include "lwip/tcp.h"
#include "tcpsrv/tcp_srv_conn.h"
#include "web_srv_int.h"
#include "web_srv.h"
#include "web_utils.h"
#include "web_websocket.h"
#include "websock.h"
#include "rtl8195a/rtl_libc.h"
#include "esp_comp.h"
#if 0
#undef DEBUGSOO
#define DEBUGSOO 4
#endif
#define copy_s4d1 rtl_memcpy
//#define mMIN(a, b) ((a<b)?a:b)
#define MAX_RX_BUF_SIZE 8192
const char txt_wsping[] ICACHE_RODATA_ATTR = "ws:ping";
const char txt_wspong[] ICACHE_RODATA_ATTR = "ws:pong";
//=============================================================================
// websock_tx_frame() - передача фрейма
//=============================================================================
err_t ICACHE_FLASH_ATTR
websock_tx_frame(TCP_SERV_CONN *ts_conn, uint32 opcode, uint8 *raw_data, uint32 raw_len)
{
err_t err = WebsocketTxFrame(ts_conn, opcode, raw_data, raw_len);
if(err != ERR_OK) {
#if DEBUGSOO > 3
os_printf("ws%utx[%u] error %d!\n", opcode, raw_len, err);
#endif
((WEB_SRV_CONN *)ts_conn->linkd)->webflag |= SCB_DISCONNECT;
}
else {
if((opcode & WS_OPCODE_BITS) == WS_OPCODE_CLOSE) {
((WEB_SRV_CONN *)ts_conn->linkd)->ws.flg |= WS_FLG_CLOSE;
}
}
return err;
}
//=============================================================================
// websock_tx_close_err() - вывод сообщения закрытия или ошибки
//=============================================================================
err_t ICACHE_FLASH_ATTR
websock_tx_close_err(TCP_SERV_CONN *ts_conn, uint32 err)
{
uint8 uc[2];
uc[1] = err;
uc[0] = err>>8;
return websock_tx_frame(ts_conn, WS_OPCODE_CLOSE | WS_FRAGMENT_FIN, uc, 2);
}
//=============================================================================
// websock_rx_data() прием данных
//=============================================================================
#define MAX_WS_DATA_BLK_SIZE (tcp_sndbuf(ts_conn->pcb)-8) // (TCP_MSS - 8)
//=============================================================================
bool ICACHE_FLASH_ATTR
websock_rx_data(TCP_SERV_CONN *ts_conn)
{
// HTTP_CONN *CurHTTP;
WEB_SRV_CONN *web_conn = (WEB_SRV_CONN *)ts_conn->linkd;
if(web_conn == NULL) return false;
WS_FRSTAT *ws = &web_conn->ws;
uint16 len;
uint8 *pstr;
#if DEBUGSOO > 3
os_printf("ws_rx[%u]%u ", ts_conn->sizei, ts_conn->cntri);
#endif
if(ts_conn->sizei == 0) return true; // докачивать
tcpsrv_unrecved_win(ts_conn);
if((ws->flg & WS_FLG_CLOSE) != 0) {
// убить буфер ts_conn->pbufi, конец давно :)
web_feee_bufi(ts_conn);
SetSCB(SCB_DISCONNECT);
return false;
}
if(ts_conn->sizei > MAX_RX_BUF_SIZE) {
#if DEBUGSOO > 0
os_printf("ws:rxbuf_full! ");
#endif
// убить буфер ts_conn->pbufi и ответить ошибкой WS_CLOSE_UNEXPECTED_ERROR
web_feee_bufi(ts_conn);
websock_tx_close_err(ts_conn, WS_CLOSE_MESSAGE_TOO_BIG); // WS_CLOSE_UNEXPECTED_ERROR);
SetSCB(SCB_DISCONNECT);
return false;
}
pstr = ts_conn->pbufi;// + ts_conn->cntri;
len = ts_conn->sizei;// - ts_conn->cntri;
while(ts_conn->cntri < ts_conn->sizei || (ws->flg & WS_FLG_FIN) != 0) {
pstr = ts_conn->pbufi;// + ts_conn->cntri;
len = ts_conn->sizei;// - ts_conn->cntri;
if((ws->flg & WS_FLG_FIN) != 0 // обработка
|| ws->frame_len > ws->cur_len) {
ws->flg &= ~WS_FLG_FIN;
len = mMIN(ws->frame_len - ws->cur_len, mMIN(MAX_WS_DATA_BLK_SIZE, len));
// размаскировать
if((ws->flg & WS_FLG_MASK) != 0) WebsocketMask(ws, pstr, len);
#if DEBUGSOO > 3
os_printf("wsfr[%u]blk[%u]at:%u ", ws->frame_len, len, ws->cur_len);
#endif
switch(ws->status) {
case sw_frs_binary:
#if DEBUGSOO > 1
os_printf("ws:bin ");
#endif
if(ws->frame_len != 0) {
// пока просто эхо
uint32 opcode = WS_OPCODE_BINARY;
if(ws->cur_len != 0) opcode = WS_OPCODE_CONTINUE;
if(ws->frame_len == ws->cur_len + len) opcode |= WS_FRAGMENT_FIN;
if(websock_tx_frame(ts_conn, opcode, pstr, len) != ERR_OK) {
return false; // не докачивать, ошибка или закрытие
}
}
ws->cur_len += len;
ts_conn->cntri += len;
break;
case sw_frs_text:
#if DEBUGSOO > 1
os_printf("ws:txt ");
#if DEBUGSOO > 2
if(ws->frame_len != 0) {
uint8 tt = pstr[len];
pstr[len] = 0;
os_printf("'%s' ", pstr);
pstr[len] = tt;
}
#endif
#endif
if(ws->frame_len == ws->cur_len + len && ws->frame_len != 0) { // полное соо
web_conn->msgbufsize = tcp_sndbuf(ts_conn->pcb); // сколько можем выввести сейчас?
if (web_conn->msgbufsize < MIN_SEND_SIZE) {
#if DEBUGSOO > 0
os_printf("ws:sndbuf=%u! ", web_conn->msgbufsize);
#endif
websock_tx_close_err(ts_conn, WS_CLOSE_UNEXPECTED_ERROR);
SetSCB(SCB_FCLOSE|SCB_DISCONNECT);
return false;
}
web_conn->msgbufsize -= 16;
if(ws->frame_len == (sizeof(txt_wsping)-1) && rom_xstrcmp(pstr, txt_wsping) != 0){
copy_s4d1(pstr, (void *)txt_wspong, sizeof(txt_wspong) - 1);
if(websock_tx_frame(ts_conn, WS_OPCODE_TEXT | WS_FRAGMENT_FIN, pstr, sizeof(txt_wspong) - 1) != ERR_OK) {
return false; // не докачивать, ошибка или закрытие
}
}
else {
if(web_conn->msgbuf) os_free(web_conn->msgbuf);
web_conn->msgbuf = (uint8 *) os_malloc(web_conn->msgbufsize);
if (web_conn->msgbuf == NULL) {
#if DEBUGSOO > 0
os_printf("ws:mem!\n");
#endif
websock_tx_close_err(ts_conn, WS_CLOSE_UNEXPECTED_ERROR);
SetSCB(SCB_FCLOSE|SCB_DISCONNECT);
return false;
};
web_conn->msgbuflen = 0;
uint32 opcode;
if(CheckSCB(SCB_RETRYCB)) { // повторный callback? да
if(web_conn->func_web_cb != NULL) web_conn->func_web_cb(ts_conn);
if(!CheckSCB(SCB_RETRYCB)) {
// ClrSCB(SCB_FCLOSE | SCB_DISCONNECT);
opcode = WS_OPCODE_CONTINUE | WS_FRAGMENT_FIN;
}
else opcode = WS_OPCODE_CONTINUE;
}
else {
pstr[len] = '\0';
uint8 *vstr = os_strchr(pstr, '=');
if(vstr != NULL) {
*vstr++ = '\0';
web_int_vars(ts_conn, pstr, vstr);
}
else {
web_conn->msgbuf[0] = 0;
web_int_callback(ts_conn, pstr);
}
if(CheckSCB(SCB_RETRYCB)) opcode = WS_OPCODE_TEXT;
else {
// ClrSCB(SCB_FCLOSE | SCB_DISCONNECT);
opcode = WS_OPCODE_TEXT | WS_FRAGMENT_FIN;
}
}
if(web_conn->msgbuflen != 0) {
if(websock_tx_frame(ts_conn, opcode, web_conn->msgbuf, web_conn->msgbuflen) != ERR_OK) {
if(web_conn->msgbuf) os_free(web_conn->msgbuf);
web_conn->msgbuf = NULL;
return false; // не докачивать, ошибка или закрытие
}
}
if(web_conn->msgbuf) os_free(web_conn->msgbuf);
web_conn->msgbuf = NULL;
if(CheckSCB(SCB_RETRYCB)) return false;
}
}
/*
if(0) {
uint32 opcode = WS_OPCODE_TEXT;
if(ws->cur_len != 0) opcode = WS_OPCODE_CONTINUE;
if(ws->frame_len == ws->cur_len + len) opcode |= WS_FRAGMENT_FIN;
if(websock_tx_frame(ts_conn, opcode, pstr, len) != ERR_OK) {
return false; // не докачивать, ошибка или закрытие
}
}
*/
ws->cur_len += len;
ts_conn->cntri += len;
return true; // докачивать
// break;
// break;
case sw_frs_ping:
#if DEBUGSOO > 1
os_printf("ws:ping ");
#endif
{
uint32 opcode = WS_OPCODE_PONG;
if(ws->cur_len != 0) opcode = WS_OPCODE_CONTINUE;
if(ws->frame_len == ws->cur_len + len) opcode |= WS_FRAGMENT_FIN;
if(websock_tx_frame(ts_conn, opcode, pstr, len) != ERR_OK) {
return false; // не докачивать, ошибка или закрытие
}
}
ws->cur_len += len;
ts_conn->cntri += len;
return true; // докачивать
// break;
case sw_frs_pong:
#if DEBUGSOO > 1
os_printf("ws:pong ");
#endif
ws->cur_len += len;
ts_conn->cntri += len;
break;
// return true;
case sw_frs_close:
#if DEBUGSOO > 1
os_printf("ws:close ");
#endif
// if((ws->flg & WS_FLG_CLOSE) == 0) {
{
if(len >= 2) {
uint32 close_code = (pstr[0]<<8) | pstr[1];
#if DEBUGSOO > 1
os_printf("code:%d ", close_code);
#endif
if(close_code == WS_CLOSE_NORMAL) websock_tx_close_err(ts_conn, WS_CLOSE_NORMAL);
// else websock_tx_frame(ts_conn, WS_OPCODE_CLOSE | WS_FRAGMENT_FIN, NULL, 0);
}
else
{
websock_tx_close_err(ts_conn, WS_CLOSE_NORMAL);
// websock_tx_frame(ts_conn, WS_OPCODE_CLOSE | WS_FRAGMENT_FIN, NULL, 0);
}
}
ts_conn->flag.pcb_time_wait_free = 1;
SetSCB(SCB_DISCONNECT);
// ts_conn->cntri = ts_conn->sizei;
/* ws->cur_len += len;
ts_conn->cntri += len; */
return false;
default:
#if DEBUGSOO > 0
os_printf("ws:f?! ");
#endif
websock_tx_close_err(ts_conn, WS_CLOSE_UNEXPECTED_ERROR);
SetSCB(SCB_DISCONNECT);
// ts_conn->cntri = ts_conn->sizei;
return false;
}
}
else
if(ws->cur_len >= ws->frame_len) { // прием и разбор нового фрейма
if((ws->flg & WS_FLG_FIN) != 0) { // обработка
#if DEBUGSOO > 3
os_printf("ws_rx:fin=%u ", ws->cur_len);
#endif
}
else {
uint32 ret = WebsocketHead(ws, pstr, len);
if(ret >= WS_CLOSE_NORMAL) { // error или close
#if DEBUGSOO > 0
os_printf("ws:txerr=%u ", ret);
#endif
websock_tx_close_err(ts_conn, ret);
// ts_conn->cntri = ts_conn->sizei; // убить буфер ts_conn->pbufi
return false; // error
}
else if(ret == 0) {
#if DEBUGSOO > 3
os_printf("ws_rx... ");
#endif
return true; // докачивать
}
ts_conn->cntri += ws->head_len; // вычесть заголовок
/*
switch(ws->status) {
case sw_frs_binary:
break;
case sw_frs_text:
if(ws->frame_len > MAX_RX_BUF_SIZE) {
websock_tx_close_err(ts_conn, WS_CLOSE_MESSAGE_TOO_BIG);
return false;
}
break;
}
*/
}
}
#if DEBUGSOO > 3
os_printf("trim%u-%u ", ts_conn->sizei, ts_conn->sizei - ts_conn->cntri );
#endif
if(!web_trim_bufi(ts_conn, &ts_conn->pbufi[ts_conn->cntri], ts_conn->sizei - ts_conn->cntri)) {
#if DEBUGSOO > 0
os_printf("ws:trim_err! ");
#endif
// убить буфер ts_conn->pbufi и ответить ошибкой WS_CLOSE_UNEXPECTED_ERROR
websock_tx_close_err(ts_conn, WS_CLOSE_UNEXPECTED_ERROR);
SetSCB(SCB_DISCONNECT);
// ts_conn->cntri = ts_conn->sizei;
return false;
};
}
return false; // не докачивать, ошибка или закрытие
}
//=============================================================================
//=============================================================================
#endif // WEBSOCKET_ENA

View file

@ -0,0 +1,18 @@
#ifndef _WEB_WEBSOCKET_H_
/******************************************************************************
* FileName: web_websocket.h
* Description: websocket for web ESP8266
* Author: PV`
* (c) PV` 2016
*******************************************************************************/
#define _WEB_WEBSOCKET_H_
#include "user_config.h"
#ifdef WEBSOCKET_ENA
#include "websock.h"
err_t websock_tx_close_err(TCP_SERV_CONN *ts_conn, uint32 err);
bool websock_rx_data(TCP_SERV_CONN *ts_conn);
err_t websock_tx_frame(TCP_SERV_CONN *ts_conn, uint32 opcode, uint8 *raw_data, uint32 raw_len);
#endif // WEBSOCKET_ENA
#endif /* _WEB_WEBSOCKET_H_ */

View file

@ -0,0 +1,245 @@
/******************************************************************************
* 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

View file

@ -0,0 +1,110 @@
/*
* File: websock.h
* Small WEB server ESP8266EX
* Author: PV`
*/
#ifndef _WEBSOCK_H_
#define _WEBSOCK_H_
#include "lwip/err.h"
#include "tcpsrv/tcp_srv_conn.h"
//#define WS_NONBLOCK 0x02
/*
0 1 2 3
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| опкод |М| Длина тела | Расширенная длина тела |
|I|S|S|S|(4бита)|А| (7бит) | (2 байта) |
|N|V|V|V| |С| |(если длина тела==126 или 127) |
| |1|2|3| |К| | |
| | | | | |А| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|4 5 6 7 |
| Продолжение расширенной длины тела, если длина тела = 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
|8 9 10 11 |
| | Ключ маски, если МАСКА = 1 |
+-------------------------------+-------------------------------+
|12 13 14 15 |
| Ключ маски (продолжение) | Данные фрейма ("тело") |
+-------------------------------- - - - - - - - - - - - - - - - +
|16 17 18 19 |
: Данные продолжаются ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Данные продолжаются ... |
+---------------------------------------------------------------+
*/
#define WS_FRAGMENT_FIN 0x80
//#define WS_RSVD_BITS (7 << 4)
#define WS_OPCODE_BITS 0x7F
#define WS_OPCODE_CONTINUE 0x0 // фрейм-продолжение для фрагментированного сообщения
#define WS_OPCODE_TEXT 0x1 // текстовый фрейм
#define WS_OPCODE_BINARY 0x2 // двоичный фрейм
#define WS_OPCODE_CLOSE 0x8 // закрытие соединения
#define WS_OPCODE_PING 0x9
#define WS_OPCODE_PONG 0xa
#define WS_MASK_FLG (1 << 7)
#define WS_SIZE1_BITS 0x7F
#define WS_CLOSE_NORMAL 1000
#define WS_CLOSE_GOING_AWAY 1001
#define WS_CLOSE_PROTOCOL_ERROR 1002
#define WS_CLOSE_NOT_ALLOWED 1003
#define WS_CLOSE_RESERVED 1004
#define WS_CLOSE_NO_CODE 1005
#define WS_CLOSE_DIRTY 1006
#define WS_CLOSE_WRONG_TYPE 1007
#define WS_CLOSE_POLICY_VIOLATION 1008
#define WS_CLOSE_MESSAGE_TOO_BIG 1009
#define WS_CLOSE_UNEXPECTED_ERROR 1011
typedef struct _WS_FRSTAT
{
uint32 frame_len; // размер данных в заголовке фрейма
uint32 cur_len; // счетчик обработанных данных
union {
unsigned char uc[4];
unsigned int ud;
} mask; // маска принимаемых данных
uint8 status;
uint8 flg;
uint8 head_len;
} WS_FRSTAT; // __attribute__((packed))
#define WS_FLG_MASK 0x01
#define WS_FLG_FIN 0x02
#define WS_FLG_CLOSE 0x04 // уже передано WS_CLOSE
enum WS_FRAME_STATE {
sw_frs_none = 0,
sw_frs_text,
sw_frs_binary,
sw_frs_close,
sw_frs_ping,
sw_frs_pong
};
extern const uint8 WebSocketHTTPOkKey[]; // ICACHE_RODATA_ATTR = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept:%s\r\n\r\n"
extern const uint8 WebSocketAddKey[]; // ICACHE_RODATA_ATTR = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
#define sizeWebSocketAddKey 36
#define maxsizeWebSocketKey 64
#define minsizeWebSocketKey 8
extern const uint8 *HTTPUpgrade; // = "Upgrade:";
#define sizeHTTPUpgrade 8
extern const uint8 *HTTPwebsocket; // = "websocket";
#define sizeHTTPwebsocket 9
extern const uint8 *HTTPSecWebSocketKey; // = "Sec-WebSocket-Key:";
#define sizeHTTPSecWebSocketKey 18
bool WebSocketAcceptKey(uint8* dkey, uint8* skey);
void WebsocketMask(WS_FRSTAT *ws, uint8 *raw_data, uint32 raw_len);
uint32 WebsocketHead(WS_FRSTAT *ws, uint8 *raw_data, uint32 raw_len);
err_t WebsocketTxFrame(TCP_SERV_CONN *ts_conn, uint32 opcode, uint8 *raw_data, uint32 raw_len);
#endif /* _WEBSOCK_H_ */