You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1277 lines
31 KiB
1277 lines
31 KiB
/*
|
|
* libwebsockets - small server side websockets and web server implementation
|
|
*
|
|
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
* IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <nvs.h>
|
|
#include <esp_ota_ops.h>
|
|
|
|
typedef enum {
|
|
SCAN_STATE_NONE,
|
|
SCAN_STATE_INITIAL,
|
|
SCAN_STATE_INITIAL_MANIFEST,
|
|
SCAN_STATE_KNOWN,
|
|
SCAN_STATE_LIST,
|
|
SCAN_STATE_FINAL
|
|
} scan_state;
|
|
|
|
struct store_json {
|
|
const char *j;
|
|
const char *nvs;
|
|
};
|
|
|
|
struct per_session_data__esplws_scan {
|
|
struct per_session_data__esplws_scan *next;
|
|
scan_state scan_state;
|
|
struct timeval last_send;
|
|
|
|
struct lws_spa *spa;
|
|
char filename[32];
|
|
char result[LWS_PRE + 512];
|
|
unsigned char buffer[4096];
|
|
int result_len;
|
|
int filename_length;
|
|
long file_length;
|
|
nvs_handle nvh;
|
|
|
|
char ap_record;
|
|
unsigned char subsequent:1;
|
|
unsigned char changed_partway:1;
|
|
};
|
|
|
|
#define max_aps 12
|
|
|
|
struct per_vhost_data__esplws_scan {
|
|
wifi_ap_record_t ap_records[10];
|
|
TimerHandle_t timer, reboot_timer;
|
|
struct per_session_data__esplws_scan *live_pss_list;
|
|
struct lws_context *context;
|
|
struct lws_vhost *vhost;
|
|
const struct lws_protocols *protocol;
|
|
struct lws_wifi_scan *known_aps_list;
|
|
|
|
const esp_partition_t *part;
|
|
esp_ota_handle_t otahandle;
|
|
long file_length;
|
|
long content_length;
|
|
|
|
int cert_remaining_days;
|
|
|
|
struct lws *cwsi;
|
|
char json[2048];
|
|
int json_len;
|
|
|
|
int acme_state;
|
|
char acme_msg[256];
|
|
|
|
uint16_t count_ap_records;
|
|
char count_live_pss;
|
|
unsigned char scan_ongoing:1;
|
|
unsigned char completed_any_scan:1;
|
|
unsigned char reboot:1;
|
|
unsigned char changed_settings:1;
|
|
unsigned char checked_updates:1;
|
|
unsigned char autonomous_update:1;
|
|
unsigned char autonomous_update_sampled:1;
|
|
};
|
|
|
|
static const struct store_json store_json[] = {
|
|
{ "\"ssid0\":\"", "0ssid" },
|
|
{ ",\"pw0\":\"", "0password" },
|
|
{ "\"ssid1\":\"", "1ssid" },
|
|
{ ",\"pw1\":\"", "1password" },
|
|
{ "\"ssid2\":\"", "2ssid" },
|
|
{ ",\"pw2\":\"", "2password" },
|
|
{ "\"ssid3\":\"", "3ssid" },
|
|
{ ",\"pw3\":\"", "3password" },
|
|
{ ",\"access_pw\":\"", "access_pw" },
|
|
{ "{\"group\":\"", "group" },
|
|
{ "{\"role\":\"", "role" },
|
|
{ ",\"region\":\"", "region" },
|
|
};
|
|
|
|
static wifi_scan_config_t scan_config = {
|
|
.ssid = 0,
|
|
.bssid = 0,
|
|
.channel = 0,
|
|
.show_hidden = true
|
|
};
|
|
|
|
const esp_partition_t *
|
|
ota_choose_part(void);
|
|
|
|
static const char * const param_names[] = {
|
|
"text",
|
|
"pub",
|
|
"pri",
|
|
"serial",
|
|
"opts",
|
|
"group",
|
|
"role",
|
|
"updsettings",
|
|
};
|
|
|
|
enum enum_param_names {
|
|
EPN_TEXT,
|
|
EPN_PUB,
|
|
EPN_PRI,
|
|
EPN_SERIAL,
|
|
EPN_OPTS,
|
|
EPN_GROUP,
|
|
EPN_ROLE,
|
|
EPN_UPDSETTINGS,
|
|
};
|
|
|
|
|
|
static void
|
|
scan_finished(uint16_t count, wifi_ap_record_t *recs, void *v);
|
|
|
|
static int
|
|
esplws_simple_arg(char *dest, int len, const char *in, const char *match)
|
|
{
|
|
const char *p = strstr(in, match);
|
|
int n = 0;
|
|
|
|
if (!p)
|
|
return 1;
|
|
|
|
p += strlen(match);
|
|
while (*p && *p != '\"' && n < len - 1)
|
|
dest[n++] = *p++;
|
|
dest[n] = '\0';
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
scan_start(struct per_vhost_data__esplws_scan *vhd)
|
|
{
|
|
int n;
|
|
|
|
if (vhd->reboot)
|
|
esp_restart();
|
|
|
|
if (vhd->scan_ongoing)
|
|
return;
|
|
|
|
if (lws_esp32.acme)
|
|
return;
|
|
|
|
if (lws_esp32.upload)
|
|
return;
|
|
|
|
vhd->scan_ongoing = 1;
|
|
lws_esp32.scan_consumer = scan_finished;
|
|
lws_esp32.scan_consumer_arg = vhd;
|
|
n = esp_wifi_scan_start(&scan_config, false);
|
|
if (n != ESP_OK)
|
|
lwsl_err("scan start failed %d\n", n);
|
|
}
|
|
|
|
static int scan_defer;
|
|
|
|
static void timer_cb(TimerHandle_t t)
|
|
{
|
|
struct per_vhost_data__esplws_scan *vhd = pvTimerGetTimerID(t);
|
|
|
|
// if (!lws_esp32.inet && ((scan_defer++) & 1))
|
|
/*
|
|
* AP mode + scan does not work well on ESP32... if we didn't connect to an AP
|
|
* ourselves, just scan once at boot. Then leave us on the AP channel.
|
|
*
|
|
* Do the callback for everyone to keep the heartbeat alive.
|
|
*/
|
|
if (!lws_esp32.inet && scan_defer++) {
|
|
lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
|
|
|
|
return;
|
|
}
|
|
|
|
scan_start(vhd);
|
|
}
|
|
|
|
static void reboot_timer_cb(TimerHandle_t t)
|
|
{
|
|
esp_restart();
|
|
}
|
|
|
|
static int
|
|
client_connection(struct per_vhost_data__esplws_scan *vhd, const char *file)
|
|
{
|
|
#if defined(CONFIG_LWS_IS_FACTORY_APPLICATION) && defined(CONFIG_LWS_OTA_SERVER_BASE_URL) && \
|
|
defined(CONFIG_LWS_OTA_SERVER_FQDN)
|
|
static struct lws_client_connect_info i;
|
|
char path[256];
|
|
|
|
memset(&i, 0, sizeof i);
|
|
|
|
snprintf(path, sizeof(path) - 1, CONFIG_LWS_OTA_SERVER_BASE_URL "/" CONFIG_LWS_MODEL_NAME "/%s", file);
|
|
|
|
lwsl_notice("Fetching %s\n", path);
|
|
|
|
i.port = 443;
|
|
i.context = vhd->context;
|
|
i.address = CONFIG_LWS_OTA_SERVER_FQDN;
|
|
i.ssl_connection = 1;
|
|
i.host = i.address;
|
|
i.origin = i.host;
|
|
i.vhost = vhd->vhost;
|
|
i.method = "GET";
|
|
i.path = path;
|
|
i.protocol = "esplws-scan";
|
|
i.pwsi = &vhd->cwsi;
|
|
|
|
vhd->cwsi = lws_client_connect_via_info(&i);
|
|
if (!vhd->cwsi) {
|
|
lwsl_notice("NULL return\n");
|
|
return 1; /* fail */
|
|
}
|
|
#endif
|
|
return 0; /* ongoing */
|
|
}
|
|
|
|
static int
|
|
lws_wifi_scan_rssi(struct lws_wifi_scan *p)
|
|
{
|
|
if (!p->count)
|
|
return -127;
|
|
|
|
return p->rssi / p->count;
|
|
}
|
|
|
|
/*
|
|
* Insert new lws_wifi_scan into linkedlist in rssi-sorted order, trimming the
|
|
* list if needed to keep it at or below max_aps entries.
|
|
*/
|
|
|
|
static int
|
|
lws_wifi_scan_insert_trim(struct lws_wifi_scan **list, struct lws_wifi_scan *ns)
|
|
{
|
|
int count = 0, ins = 1, worst;
|
|
struct lws_wifi_scan *newlist, **pworst, *pp1;
|
|
|
|
lws_start_foreach_llp(struct lws_wifi_scan **, pp, *list) {
|
|
/* try to find existing match */
|
|
if (!strcmp((*pp)->ssid, ns->ssid) &&
|
|
!memcmp((*pp)->bssid, ns->bssid, 6)) {
|
|
if ((*pp)->count > 127) {
|
|
(*pp)->count /= 2;
|
|
(*pp)->rssi /= 2;
|
|
}
|
|
(*pp)->rssi += ns->rssi;
|
|
(*pp)->count++;
|
|
ins = 0;
|
|
break;
|
|
}
|
|
} lws_end_foreach_llp(pp, next);
|
|
|
|
if (ins) {
|
|
lws_start_foreach_llp(struct lws_wifi_scan **, pp, *list) {
|
|
/* trim any excess guys */
|
|
if (count++ >= max_aps - 1) {
|
|
pp1 = *pp;
|
|
*pp = (*pp)->next;
|
|
free(pp1);
|
|
continue; /* stay where we are */
|
|
}
|
|
} lws_end_foreach_llp(pp, next);
|
|
|
|
/* we are inserting... so alloc a copy of him */
|
|
pp1 = malloc(sizeof(*pp1));
|
|
if (!pp1)
|
|
return -1;
|
|
|
|
memcpy(pp1, ns, sizeof(*pp1));
|
|
pp1->next = *list;
|
|
*list = pp1;
|
|
}
|
|
|
|
/* sort the list ... worst first, but added at the newlist head */
|
|
|
|
newlist = NULL;
|
|
|
|
/* while anybody left on the old list */
|
|
while (*list) {
|
|
worst = 0;
|
|
pworst = NULL;
|
|
|
|
/* who is the worst guy still left on the old list? */
|
|
lws_start_foreach_llp(struct lws_wifi_scan **, pp, *list) {
|
|
if (lws_wifi_scan_rssi(*pp) <= worst) {
|
|
worst = lws_wifi_scan_rssi(*pp);
|
|
pworst = pp;
|
|
}
|
|
} lws_end_foreach_llp(pp, next);
|
|
|
|
if (pworst) {
|
|
/* move the worst to the head of the new list */
|
|
pp1 = *pworst;
|
|
*pworst = (*pworst)->next;
|
|
pp1->next = newlist;
|
|
newlist = pp1;
|
|
}
|
|
}
|
|
|
|
*list = newlist;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
scan_finished(uint16_t count, wifi_ap_record_t *recs, void *v)
|
|
{
|
|
struct per_vhost_data__esplws_scan *vhd = v;
|
|
struct per_session_data__esplws_scan *p = vhd->live_pss_list;
|
|
struct lws_wifi_scan lws;
|
|
wifi_ap_record_t *r;
|
|
int m;
|
|
|
|
lwsl_notice("%s: count %d\n", __func__, count);
|
|
|
|
vhd->scan_ongoing = 0;
|
|
|
|
if (count < LWS_ARRAY_SIZE(vhd->ap_records))
|
|
vhd->count_ap_records = count;
|
|
else
|
|
vhd->count_ap_records = LWS_ARRAY_SIZE(vhd->ap_records);
|
|
|
|
memcpy(vhd->ap_records, recs, vhd->count_ap_records * sizeof(*recs));
|
|
|
|
while (p) {
|
|
if (p->scan_state != SCAN_STATE_INITIAL &&
|
|
p->scan_state != SCAN_STATE_NONE)
|
|
p->changed_partway = 1;
|
|
else
|
|
p->scan_state = SCAN_STATE_INITIAL;
|
|
p = p->next;
|
|
}
|
|
|
|
/* convert to generic, cumulative scan results */
|
|
|
|
for (m = 0; m < vhd->count_ap_records; m++) {
|
|
|
|
r = &vhd->ap_records[m];
|
|
|
|
lws.authmode = r->authmode;
|
|
lws.channel = r->primary;
|
|
lws.rssi = r->rssi;
|
|
lws.count = 1;
|
|
memcpy(&lws.bssid, r->bssid, 6);
|
|
lws_strncpy(lws.ssid, (const char *)r->ssid, sizeof(lws.ssid));
|
|
|
|
lws_wifi_scan_insert_trim(&vhd->known_aps_list, &lws);
|
|
}
|
|
|
|
lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
|
|
|
|
if (lws_esp32.inet && !vhd->cwsi && !vhd->checked_updates)
|
|
client_connection(vhd, "manifest.json");
|
|
|
|
if (vhd->changed_settings) {
|
|
lws_esp32_wlan_nvs_get(1);
|
|
vhd->changed_settings = 0;
|
|
} else
|
|
esp_wifi_connect();
|
|
}
|
|
|
|
static const char *ssl_names[] = { "ap-cert.pem", "ap-key.pem" };
|
|
|
|
static int
|
|
file_upload_cb(void *data, const char *name, const char *filename,
|
|
char *buf, int len, enum lws_spa_fileupload_states state)
|
|
{
|
|
struct per_session_data__esplws_scan *pss =
|
|
(struct per_session_data__esplws_scan *)data;
|
|
int n;
|
|
|
|
switch (state) {
|
|
case LWS_UFS_OPEN:
|
|
if (lws_esp32_get_reboot_type() != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON)
|
|
return -1;
|
|
|
|
lwsl_notice("LWS_UFS_OPEN Filename %s\n", filename);
|
|
lws_strncpy(pss->filename, filename, sizeof(pss->filename));
|
|
if (!strcmp(name, "pub") || !strcmp(name, "pri")) {
|
|
if (nvs_open("lws-station", NVS_READWRITE, &pss->nvh))
|
|
return 1;
|
|
} else
|
|
return 1;
|
|
pss->file_length = 0;
|
|
break;
|
|
|
|
case LWS_UFS_FINAL_CONTENT:
|
|
case LWS_UFS_CONTENT:
|
|
if (len) {
|
|
/* if the file length is too big, drop it */
|
|
if (pss->file_length + len > sizeof(pss->buffer))
|
|
return 1;
|
|
|
|
memcpy(pss->buffer + pss->file_length, buf, len);
|
|
}
|
|
pss->file_length += len;
|
|
|
|
if (state == LWS_UFS_CONTENT)
|
|
break;
|
|
|
|
lwsl_notice("LWS_UFS_FINAL_CONTENT\n");
|
|
n = 0;
|
|
if (!strcmp(name, "pri"))
|
|
n = 1;
|
|
lwsl_notice("writing %s\n", ssl_names[n]);
|
|
n = nvs_set_blob(pss->nvh, ssl_names[n], pss->buffer, pss->file_length);
|
|
if (n == ESP_OK)
|
|
nvs_commit(pss->nvh);
|
|
nvs_close(pss->nvh);
|
|
if (n != ESP_OK)
|
|
return 1;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
|
|
void *user, void *in, size_t len)
|
|
{
|
|
struct per_session_data__esplws_scan *pss =
|
|
(struct per_session_data__esplws_scan *)user;
|
|
struct per_vhost_data__esplws_scan *vhd =
|
|
(struct per_vhost_data__esplws_scan *)
|
|
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
|
|
lws_get_protocol(wsi));
|
|
unsigned char *start = pss->buffer + LWS_PRE - 1, *p = start,
|
|
*end = pss->buffer + sizeof(pss->buffer) - 1;
|
|
union lws_tls_cert_info_results ir;
|
|
struct lws_wifi_scan *lwscan;
|
|
char subject[64];
|
|
int n, m;
|
|
nvs_handle nvh;
|
|
size_t s;
|
|
|
|
|
|
switch (reason) {
|
|
|
|
case LWS_CALLBACK_PROTOCOL_INIT:
|
|
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
|
|
lws_get_protocol(wsi),
|
|
sizeof(struct per_vhost_data__esplws_scan));
|
|
vhd->context = lws_get_context(wsi);
|
|
vhd->protocol = lws_get_protocol(wsi);
|
|
vhd->vhost = lws_get_vhost(wsi);
|
|
vhd->timer = xTimerCreate("x", pdMS_TO_TICKS(10000), 1, vhd,
|
|
(TimerCallbackFunction_t)timer_cb);
|
|
vhd->scan_ongoing = 0;
|
|
strcpy(vhd->json, " { }");
|
|
// scan_start(vhd);
|
|
break;
|
|
|
|
case LWS_CALLBACK_PROTOCOL_DESTROY:
|
|
if (!vhd)
|
|
break;
|
|
xTimerStop(vhd->timer, 0);
|
|
xTimerDelete(vhd->timer, 0);
|
|
break;
|
|
|
|
case LWS_CALLBACK_ESTABLISHED:
|
|
lwsl_notice("%s: ESTABLISHED\n", __func__);
|
|
if (!vhd->live_pss_list) {
|
|
// scan_start(vhd);
|
|
xTimerStart(vhd->timer, 0);
|
|
}
|
|
vhd->count_live_pss++;
|
|
pss->next = vhd->live_pss_list;
|
|
vhd->live_pss_list = pss;
|
|
/* if we have scan results, update them. Otherwise wait */
|
|
// if (vhd->count_ap_records) {
|
|
pss->scan_state = SCAN_STATE_INITIAL;
|
|
lws_callback_on_writable(wsi);
|
|
// }
|
|
break;
|
|
|
|
case LWS_CALLBACK_SERVER_WRITEABLE:
|
|
if (vhd->autonomous_update_sampled) {
|
|
p += snprintf((char *)p, end - p,
|
|
" {\n \"auton\":\"1\",\n \"pos\": \"%ld\",\n"
|
|
" \"len\":\"%ld\"\n}\n",
|
|
vhd->file_length,
|
|
vhd->content_length);
|
|
|
|
n = LWS_WRITE_TEXT;
|
|
goto issue;
|
|
}
|
|
|
|
switch (pss->scan_state) {
|
|
struct timeval t;
|
|
uint8_t mac[6];
|
|
struct lws_esp32_image i;
|
|
char img_factory[384], img_ota[384], group[16], role[16];
|
|
int grt;
|
|
|
|
case SCAN_STATE_NONE:
|
|
|
|
/* fallthru */
|
|
|
|
case SCAN_STATE_INITIAL:
|
|
|
|
gettimeofday(&t, NULL);
|
|
// if (t.tv_sec - pss->last_send.tv_sec < 10)
|
|
// return 0;
|
|
|
|
pss->last_send = t;
|
|
|
|
if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
|
|
lwsl_err("unable to open nvs\n");
|
|
return -1;
|
|
}
|
|
n = 0;
|
|
if (nvs_get_blob(nvh, "ap-cert.pem", NULL, &s) == ESP_OK)
|
|
n = 1;
|
|
if (nvs_get_blob(nvh, "ap-key.pem", NULL, &s) == ESP_OK)
|
|
n |= 2;
|
|
s = sizeof(group) - 1;
|
|
group[0] = '\0';
|
|
role[0] = '\0';
|
|
nvs_get_str(nvh, "group", group, &s);
|
|
nvs_get_str(nvh, "role", role, &s);
|
|
|
|
nvs_close(nvh);
|
|
|
|
ir.ns.name[0] = '\0';
|
|
subject[0] = '\0';
|
|
|
|
if (t.tv_sec > 1464083026 &&
|
|
!lws_tls_vhost_cert_info(vhd->vhost,
|
|
LWS_TLS_CERT_INFO_VALIDITY_TO, &ir, 0)) {
|
|
vhd->cert_remaining_days =
|
|
(ir.time - t.tv_sec) / (24 * 3600);
|
|
ir.ns.name[0] = '\0';
|
|
lws_tls_vhost_cert_info(vhd->vhost,
|
|
LWS_TLS_CERT_INFO_COMMON_NAME, &ir,
|
|
sizeof(ir.ns.name));
|
|
lws_strncpy(subject, ir.ns.name, sizeof(subject));
|
|
|
|
ir.ns.name[0] = '\0';
|
|
lws_tls_vhost_cert_info(vhd->vhost,
|
|
LWS_TLS_CERT_INFO_ISSUER_NAME, &ir,
|
|
sizeof(ir.ns.name));
|
|
}
|
|
|
|
/*
|
|
* this value in the JSON is just
|
|
* used for UI indication. Each conditional feature confirms
|
|
* it itself before it allows itself to be used.
|
|
*/
|
|
|
|
grt = lws_esp32_get_reboot_type();
|
|
|
|
esp_efuse_mac_get_default(mac);
|
|
strcpy(img_factory, " { \"date\": \"Empty\" }");
|
|
strcpy(img_ota, " { \"date\": \"Empty\" }");
|
|
|
|
// if (grt != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON) {
|
|
lws_esp32_get_image_info(esp_partition_find_first(ESP_PARTITION_TYPE_APP,
|
|
ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL), &i,
|
|
img_factory, sizeof(img_factory) - 1);
|
|
img_factory[sizeof(img_factory) - 1] = '\0';
|
|
if (img_factory[0] == 0xff || strlen(img_factory) < 8)
|
|
strcpy(img_factory, " { \"date\": \"Empty\" }");
|
|
|
|
lws_esp32_get_image_info(esp_partition_find_first(ESP_PARTITION_TYPE_APP,
|
|
ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL), &i,
|
|
img_ota, sizeof(img_ota) - 1);
|
|
img_ota[sizeof(img_ota) - 1] = '\0';
|
|
if (img_ota[0] == 0xff || strlen(img_ota) < 8)
|
|
strcpy(img_ota, " { \"date\": \"Empty\" }");
|
|
// }
|
|
|
|
p += snprintf((char *)p, end - p,
|
|
"{ \"model\":\"%s\",\n"
|
|
" \"forced_button\":\"%d\",\n"
|
|
" \"serial\":\"%s\",\n"
|
|
" \"opts\":\"%s\",\n"
|
|
" \"host\":\"%s-%s\",\n"
|
|
" \"region\":\"%d\",\n"
|
|
" \"ssl_pub\":\"%d\",\n"
|
|
" \"ssl_pri\":\"%d\",\n"
|
|
" \"mac\":\"%02X%02X%02X%02X%02X%02X\",\n"
|
|
" \"ssid\":\"%s\",\n"
|
|
" \"conn_ip\":\"%s\",\n"
|
|
" \"conn_mask\":\"%s\",\n"
|
|
" \"conn_gw\":\"%s\",\n"
|
|
" \"certdays\":\"%d\",\n"
|
|
" \"unixtime\":\"%llu\",\n"
|
|
" \"certissuer\":\"%s\",\n"
|
|
" \"certsubject\":\"%s\",\n"
|
|
" \"le_dns\":\"%s\",\n"
|
|
" \"le_email\":\"%s\",\n"
|
|
" \"acme_state\":\"%d\",\n"
|
|
" \"acme_msg\":\"%s\",\n"
|
|
" \"button\":\"%d\",\n"
|
|
" \"group\":\"%s\",\n"
|
|
" \"role\":\"%s\",\n",
|
|
lws_esp32.model,
|
|
grt == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON,
|
|
lws_esp32.serial,
|
|
lws_esp32.opts,
|
|
lws_esp32.model, lws_esp32.serial,
|
|
lws_esp32.region,
|
|
n & 1, (n >> 1) & 1,
|
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] | 1,
|
|
lws_esp32.active_ssid,
|
|
lws_esp32.sta_ip,
|
|
lws_esp32.sta_mask,
|
|
lws_esp32.sta_gw,
|
|
vhd->cert_remaining_days,
|
|
(unsigned long long)t.tv_sec,
|
|
ir.ns.name, subject,
|
|
lws_esp32.le_dns,
|
|
lws_esp32.le_email,
|
|
vhd->acme_state,
|
|
vhd->acme_msg,
|
|
((volatile struct lws_esp32 *)(&lws_esp32))->button_is_down,
|
|
group, role);
|
|
p += snprintf((char *)p, end - p,
|
|
" \"img_factory\": %s,\n"
|
|
" \"img_ota\": %s,\n",
|
|
img_factory,
|
|
img_ota
|
|
);
|
|
|
|
|
|
n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;
|
|
pss->scan_state = SCAN_STATE_INITIAL_MANIFEST;
|
|
pss->ap_record = 0;
|
|
pss->subsequent = 0;
|
|
break;
|
|
|
|
case SCAN_STATE_INITIAL_MANIFEST:
|
|
p += snprintf((char *)p, end - p,
|
|
" \"latest\": %s,\n"
|
|
" \"inet\":\"%d\",\n",
|
|
vhd->json,
|
|
lws_esp32.inet
|
|
);
|
|
|
|
p += snprintf((char *)p, end - p,
|
|
" \"known\":[\n");
|
|
|
|
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
|
|
pss->scan_state = SCAN_STATE_KNOWN;
|
|
break;
|
|
|
|
case SCAN_STATE_KNOWN:
|
|
if (nvs_open("lws-station", NVS_READONLY, &nvh)) {
|
|
lwsl_notice("unable to open nvh\n");
|
|
return -1;
|
|
}
|
|
|
|
for (m = 0; m < 4; m++) {
|
|
char name[10], ssid[65];
|
|
unsigned int pp = 0, use = 0;
|
|
|
|
if (m)
|
|
*p++ = ',';
|
|
|
|
s = sizeof(ssid) - 1;
|
|
ssid[0] = '\0';
|
|
lws_snprintf(name, sizeof(name) - 1, "%dssid", m);
|
|
nvs_get_str(nvh, name, ssid, &s);
|
|
lws_snprintf(name, sizeof(name) - 1, "%dpassword", m);
|
|
s = 10;
|
|
nvs_get_str(nvh, name, NULL, &s);
|
|
pp = !!s;
|
|
lws_snprintf(name, sizeof(name) - 1, "%duse", m);
|
|
nvs_get_u32(nvh, name, &use);
|
|
|
|
p += snprintf((char *)p, end - p,
|
|
"{\"ssid\":\"%s\",\n"
|
|
" \"pp\":\"%u\",\n"
|
|
"\"use\":\"%u\"}\n",
|
|
ssid, pp, use);
|
|
}
|
|
nvs_close(nvh);
|
|
pss->ap_record = 0;
|
|
|
|
p += snprintf((char *)p, end - p,
|
|
"], \"aps\":[\n");
|
|
|
|
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
|
|
pss->scan_state = SCAN_STATE_LIST;
|
|
break;
|
|
|
|
case SCAN_STATE_LIST:
|
|
lwscan = vhd->known_aps_list;
|
|
|
|
n = pss->ap_record;
|
|
while (lwscan && n--)
|
|
lwscan = lwscan->next;
|
|
|
|
for (m = 0; m < 6; m++) {
|
|
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
|
|
if (!lwscan)
|
|
goto scan_state_final;
|
|
|
|
if (pss->subsequent)
|
|
*p++ = ',';
|
|
pss->subsequent = 1;
|
|
pss->ap_record++;
|
|
|
|
p += snprintf((char *)p, end - p,
|
|
"{\"ssid\":\"%s\",\n"
|
|
"\"bssid\":\"%02X:%02X:%02X:%02X:%02X:%02X\",\n"
|
|
"\"rssi\":\"%d\",\n"
|
|
"\"chan\":\"%d\",\n"
|
|
"\"auth\":\"%d\"}\n",
|
|
lwscan->ssid,
|
|
lwscan->bssid[0], lwscan->bssid[1], lwscan->bssid[2],
|
|
lwscan->bssid[3], lwscan->bssid[4], lwscan->bssid[5],
|
|
lws_wifi_scan_rssi(lwscan),
|
|
lwscan->channel, lwscan->authmode);
|
|
|
|
lwscan = lwscan->next;
|
|
if (!lwscan)
|
|
pss->scan_state = SCAN_STATE_FINAL;
|
|
}
|
|
break;
|
|
|
|
case SCAN_STATE_FINAL:
|
|
scan_state_final:
|
|
n = LWS_WRITE_CONTINUATION;
|
|
p += sprintf((char *)p, "]\n}\n");
|
|
if (pss->changed_partway) {
|
|
pss->changed_partway = 0;
|
|
pss->subsequent = 0;
|
|
pss->scan_state = SCAN_STATE_INITIAL;
|
|
} else {
|
|
pss->scan_state = SCAN_STATE_NONE;
|
|
vhd->autonomous_update_sampled = vhd->autonomous_update;
|
|
}
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
issue:
|
|
m = lws_write(wsi, (unsigned char *)start, p - start, n);
|
|
if (m < 0) {
|
|
lwsl_err("ERROR %d writing to di socket\n", m);
|
|
return -1;
|
|
}
|
|
|
|
if (pss->scan_state != SCAN_STATE_NONE)
|
|
lws_callback_on_writable(wsi);
|
|
|
|
break;
|
|
|
|
case LWS_CALLBACK_VHOST_CERT_UPDATE:
|
|
lwsl_notice("LWS_CALLBACK_VHOST_CERT_UPDATE: %d\n", (int)len);
|
|
vhd->acme_state = (int)len;
|
|
if (in) {
|
|
lws_strncpy(vhd->acme_msg, in, sizeof(vhd->acme_msg));
|
|
lwsl_notice("acme_msg: %s\n", (char *)in);
|
|
}
|
|
lws_callback_on_writable_all_protocol_vhost(vhd->vhost, vhd->protocol);
|
|
break;
|
|
|
|
case LWS_CALLBACK_RECEIVE:
|
|
{
|
|
const char *sect = "\"app\": {", *b;
|
|
nvs_handle nvh;
|
|
char p[64], use[6];
|
|
int n, si = -1;
|
|
|
|
if (strstr((const char *)in, "identify")) {
|
|
lws_esp32_identify_physical_device();
|
|
break;
|
|
}
|
|
|
|
if (vhd->json_len && strstr((const char *)in, "update-factory")) {
|
|
sect = "\"factory\": {";
|
|
goto auton;
|
|
}
|
|
if (vhd->json_len && strstr((const char *)in, "update-ota"))
|
|
goto auton;
|
|
|
|
if (strstr((const char *)in, "\"reset\""))
|
|
goto sched_reset;
|
|
|
|
if (!strncmp((const char *)in, "{\"job\":\"start-le\"", 17))
|
|
goto start_le;
|
|
|
|
|
|
if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
|
|
lwsl_err("Unable to open nvs\n");
|
|
break;
|
|
}
|
|
|
|
if (!esplws_simple_arg(p, sizeof(p), in, ",\"slot\":\""))
|
|
si = atoi(p);
|
|
|
|
lwsl_notice("si %d\n", si);
|
|
|
|
for (n = 0; n < LWS_ARRAY_SIZE(store_json); n++) {
|
|
if (esplws_simple_arg(p, sizeof(p), in, store_json[n].j))
|
|
continue;
|
|
|
|
/* only change access password if he has physical access to device */
|
|
if (n == 8 && lws_esp32_get_reboot_type() != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON)
|
|
continue;
|
|
|
|
if (lws_nvs_set_str(nvh, store_json[n].nvs, p) != ESP_OK) {
|
|
lwsl_err("Unable to store %s in nvm\n", store_json[n].nvs);
|
|
goto bail_nvs;
|
|
}
|
|
|
|
if (si != -1 && n < 8) {
|
|
if (!(n & 1)) {
|
|
lws_strncpy(lws_esp32.ssid[(n >> 1) & 3], p,
|
|
sizeof(lws_esp32.ssid[0]));
|
|
lws_snprintf(use, sizeof(use) - 1, "%duse", si);
|
|
lwsl_notice("resetting %s to 0\n", use);
|
|
nvs_set_u32(nvh, use, 0);
|
|
|
|
} else
|
|
lws_strncpy(lws_esp32.password[(n >> 1) & 3], p,
|
|
sizeof(lws_esp32.password[0]));
|
|
}
|
|
|
|
}
|
|
|
|
nvs_commit(nvh);
|
|
nvs_close(nvh);
|
|
|
|
if (strstr((const char *)in, "\"factory-reset\"")) {
|
|
if (lws_esp32_get_reboot_type() ==
|
|
LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON) {
|
|
|
|
lwsl_notice("Doing factory reset\n");
|
|
ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
|
|
n = nvs_erase_all(nvh);
|
|
if (n)
|
|
lwsl_notice("erase_all failed %d\n", n);
|
|
nvs_commit(nvh);
|
|
nvs_close(nvh);
|
|
|
|
goto sched_reset;
|
|
} else
|
|
lwsl_notice("failed on factory button boot\n");
|
|
}
|
|
|
|
if (vhd->scan_ongoing)
|
|
vhd->changed_settings = 1;
|
|
else
|
|
lws_esp32_wlan_nvs_get(1);
|
|
|
|
lwsl_notice("set Join AP info\n");
|
|
break;
|
|
|
|
bail_nvs:
|
|
nvs_close(nvh);
|
|
|
|
return 1;
|
|
|
|
sched_reset:
|
|
vhd->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(250), 0, vhd,
|
|
(TimerCallbackFunction_t)reboot_timer_cb);
|
|
xTimerStart(vhd->reboot_timer, 0);
|
|
|
|
return 1;
|
|
|
|
auton:
|
|
lwsl_notice("Autonomous upload\n");
|
|
b = strstr(vhd->json, sect);
|
|
if (!b) {
|
|
lwsl_notice("Can't find %s in JSON\n", sect);
|
|
return 1;
|
|
}
|
|
b = strstr(b, "\"file\": \"");
|
|
if (!b) {
|
|
lwsl_notice("Can't find \"file\": JSON\n");
|
|
return 1;
|
|
}
|
|
vhd->autonomous_update = 1;
|
|
if (pss->scan_state == SCAN_STATE_NONE)
|
|
vhd->autonomous_update_sampled = 1;
|
|
b += 9;
|
|
n = 0;
|
|
while ((*b != '\"') && n < sizeof(p) - 1)
|
|
p[n++] = *b++;
|
|
|
|
p[n] = '\0';
|
|
|
|
vhd->part = ota_choose_part();
|
|
if (!vhd->part)
|
|
return 1;
|
|
|
|
if (client_connection(vhd, p))
|
|
vhd->autonomous_update = 0;
|
|
|
|
break;
|
|
|
|
start_le:
|
|
lws_esp32.acme = 1; /* hold off scanning */
|
|
puts(in);
|
|
/*
|
|
* {"job":"start-le","cn":"home.warmcat.com",
|
|
* "email":"andy@warmcat.com", "staging":"true"}
|
|
*/
|
|
|
|
if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
|
|
lwsl_err("Unable to open nvs\n");
|
|
break;
|
|
}
|
|
|
|
n = 0;
|
|
b = strstr(in, ",\"cn\":\"");
|
|
if (b) {
|
|
b += 7;
|
|
while (*b && *b != '\"' && n < sizeof(lws_esp32.le_dns) - 1)
|
|
lws_esp32.le_dns[n++] = *b++;
|
|
}
|
|
lws_esp32.le_dns[n] = '\0';
|
|
|
|
lws_nvs_set_str(nvh, "acme-cn", lws_esp32.le_dns);
|
|
n = 0;
|
|
b = strstr(in, ",\"email\":\"");
|
|
if (b) {
|
|
b += 10;
|
|
while (*b && *b != '\"' && n < sizeof(lws_esp32.le_email) - 1)
|
|
lws_esp32.le_email[n++] = *b++;
|
|
}
|
|
lws_esp32.le_email[n] = '\0';
|
|
lws_nvs_set_str(nvh, "acme-email", lws_esp32.le_email);
|
|
nvs_commit(nvh);
|
|
|
|
nvs_close(nvh);
|
|
|
|
n = 1;
|
|
b = strstr(in, ",\"staging\":\"");
|
|
if (b)
|
|
lwsl_notice("staging: %s\n", b);
|
|
if (b && b[12] == 'f')
|
|
n = 0;
|
|
|
|
lwsl_notice("cn: %s, email: %s, staging: %d\n", lws_esp32.le_dns, lws_esp32.le_email, n);
|
|
|
|
{
|
|
struct lws_acme_cert_aging_args caa;
|
|
|
|
memset(&caa, 0, sizeof(caa));
|
|
caa.vh = vhd->vhost;
|
|
|
|
caa.element_overrides[LWS_TLS_REQ_ELEMENT_COMMON_NAME] = lws_esp32.le_dns;
|
|
caa.element_overrides[LWS_TLS_REQ_ELEMENT_EMAIL] = lws_esp32.le_email;
|
|
|
|
if (n)
|
|
caa.element_overrides[LWS_TLS_SET_DIR_URL] =
|
|
"https://acme-staging.api.letsencrypt.org/directory"; /* staging */
|
|
else
|
|
caa.element_overrides[LWS_TLS_SET_DIR_URL] =
|
|
"https://acme-v01.api.letsencrypt.org/directory"; /* real */
|
|
|
|
lws_callback_vhost_protocols_vhost(vhd->vhost,
|
|
LWS_CALLBACK_VHOST_CERT_AGING,
|
|
(void *)&caa, 0);
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LWS_CALLBACK_CLOSED:
|
|
{
|
|
struct per_session_data__esplws_scan **p = &vhd->live_pss_list;
|
|
|
|
while (*p) {
|
|
if ((*p) == pss) {
|
|
*p = pss->next;
|
|
continue;
|
|
}
|
|
|
|
p = &((*p)->next);
|
|
}
|
|
|
|
vhd->count_live_pss--;
|
|
}
|
|
if (!vhd->live_pss_list)
|
|
xTimerStop(vhd->timer, 0);
|
|
break;
|
|
|
|
/* "factory" POST handling */
|
|
|
|
case LWS_CALLBACK_HTTP_BODY:
|
|
/* create the POST argument parser if not already existing */
|
|
if (!pss->spa) {
|
|
pss->spa = lws_spa_create(wsi, param_names,
|
|
LWS_ARRAY_SIZE(param_names), 1024,
|
|
file_upload_cb, pss);
|
|
if (!pss->spa)
|
|
return -1;
|
|
|
|
pss->filename[0] = '\0';
|
|
pss->file_length = 0;
|
|
}
|
|
//puts((const char *)in);
|
|
/* let it parse the POST data */
|
|
if (lws_spa_process(pss->spa, in, len))
|
|
return -1;
|
|
break;
|
|
|
|
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
|
|
lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION (scan)\n");
|
|
/* call to inform no more payload data coming */
|
|
lws_spa_finalize(pss->spa);
|
|
|
|
for (n = 0; n < LWS_ARRAY_SIZE(param_names); n++)
|
|
if (lws_spa_get_string(pss->spa, n))
|
|
lwsl_notice(" Param %s: %s\n", param_names[n],
|
|
lws_spa_get_string(pss->spa, n));
|
|
else
|
|
lwsl_notice(" Param %s: (none)\n",
|
|
param_names[n]);
|
|
|
|
if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
|
|
lwsl_err("Unable to open nvs\n");
|
|
break;
|
|
}
|
|
|
|
if (lws_esp32_get_reboot_type() == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON) {
|
|
|
|
if (lws_spa_get_string(pss->spa, EPN_SERIAL)) {
|
|
if (lws_nvs_set_str(nvh, "serial", lws_spa_get_string(pss->spa, EPN_SERIAL)) != ESP_OK) {
|
|
lwsl_err("Unable to store serial in nvm\n");
|
|
goto bail_nvs;
|
|
}
|
|
|
|
nvs_commit(nvh);
|
|
}
|
|
|
|
if (lws_spa_get_string(pss->spa, EPN_OPTS)) {
|
|
if (lws_nvs_set_str(nvh, "opts", lws_spa_get_string(pss->spa, EPN_OPTS)) != ESP_OK) {
|
|
lwsl_err("Unable to store options in nvm\n");
|
|
goto bail_nvs;
|
|
}
|
|
|
|
nvs_commit(nvh);
|
|
}
|
|
}
|
|
|
|
if (lws_spa_get_string(pss->spa, EPN_GROUP)) {
|
|
if (lws_nvs_set_str(nvh, "group", lws_spa_get_string(pss->spa, EPN_GROUP)) != ESP_OK) {
|
|
lwsl_err("Unable to store group in nvm\n");
|
|
goto bail_nvs;
|
|
}
|
|
|
|
nvs_commit(nvh);
|
|
}
|
|
|
|
if (lws_spa_get_string(pss->spa, EPN_ROLE)) {
|
|
if (lws_nvs_set_str(nvh, "role", lws_spa_get_string(pss->spa, EPN_ROLE)) != ESP_OK) {
|
|
lwsl_err("Unable to store group in nvm\n");
|
|
goto bail_nvs;
|
|
}
|
|
|
|
nvs_commit(nvh);
|
|
}
|
|
|
|
nvs_close(nvh);
|
|
|
|
pss->result_len = snprintf(pss->result + LWS_PRE, sizeof(pss->result) - LWS_PRE - 1,
|
|
"<html>OK</html>");
|
|
|
|
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
|
|
goto bail;
|
|
|
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
|
(unsigned char *)"text/html", 9, &p, end))
|
|
goto bail;
|
|
if (lws_add_http_header_content_length(wsi, pss->result_len, &p, end))
|
|
goto bail;
|
|
if (lws_finalize_http_header(wsi, &p, end))
|
|
goto bail;
|
|
|
|
n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
|
goto bail;
|
|
|
|
case LWS_CALLBACK_HTTP_WRITEABLE:
|
|
lwsl_debug("LWS_CALLBACK_HTTP_WRITEABLE: sending %d\n",
|
|
pss->result_len);
|
|
if (!pss->result_len)
|
|
break;
|
|
n = lws_write(wsi, (unsigned char *)pss->result + LWS_PRE,
|
|
pss->result_len, LWS_WRITE_HTTP);
|
|
if (n < 0)
|
|
return 1;
|
|
|
|
vhd->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(3000), 0, vhd,
|
|
(TimerCallbackFunction_t)reboot_timer_cb);
|
|
xTimerStart(vhd->reboot_timer, 0);
|
|
|
|
return 1; // hang up since we will reset
|
|
|
|
/* ----- client handling ----- */
|
|
|
|
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
|
lwsl_notice("Client connection error %s\n", (char *)in);
|
|
vhd->cwsi = NULL;
|
|
break;
|
|
|
|
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
|
|
if (!vhd->autonomous_update)
|
|
break;
|
|
|
|
{
|
|
char pp[20];
|
|
|
|
if (lws_hdr_copy(wsi, pp, sizeof(pp) - 1, WSI_TOKEN_HTTP_CONTENT_LENGTH) < 0)
|
|
return -1;
|
|
|
|
vhd->content_length = atoi(pp);
|
|
if (vhd->content_length <= 0 ||
|
|
vhd->content_length > vhd->part->size)
|
|
return -1;
|
|
|
|
if (esp_ota_begin(vhd->part, (long)-1, &vhd->otahandle) != ESP_OK) {
|
|
lwsl_err("OTA: Failed to begin\n");
|
|
return 1;
|
|
}
|
|
|
|
vhd->file_length = 0;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
|
|
//lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: %ld\n",
|
|
// (long)len);
|
|
|
|
if (!vhd->autonomous_update) {
|
|
if (sizeof(vhd->json) - vhd->json_len - 1 < len)
|
|
len = sizeof(vhd->json) - vhd->json_len - 1;
|
|
memcpy(vhd->json + vhd->json_len, in, len);
|
|
vhd->json_len += len;
|
|
vhd->json[vhd->json_len] = '\0';
|
|
break;
|
|
}
|
|
|
|
/* autonomous download */
|
|
|
|
|
|
if (vhd->file_length + len > vhd->part->size) {
|
|
lwsl_err("OTA: incoming file too large\n");
|
|
goto abort_ota;
|
|
}
|
|
|
|
lwsl_debug("writing 0x%lx... 0x%lx\n",
|
|
vhd->part->address + vhd->file_length,
|
|
vhd->part->address + vhd->file_length + len);
|
|
if (esp_ota_write(vhd->otahandle, in, len) != ESP_OK) {
|
|
lwsl_err("OTA: Failed to write\n");
|
|
goto abort_ota;
|
|
}
|
|
vhd->file_length += len;
|
|
|
|
lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
|
|
break;
|
|
|
|
abort_ota:
|
|
esp_ota_end(vhd->otahandle);
|
|
vhd->otahandle = 0;
|
|
vhd->autonomous_update = 0;
|
|
|
|
return 1;
|
|
|
|
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
|
|
{
|
|
char *px = (char *)pss->buffer + LWS_PRE;
|
|
int lenx = sizeof(pss->buffer) - LWS_PRE - 1;
|
|
|
|
//lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: %d\n", len);
|
|
|
|
if (lws_http_client_read(wsi, &px, &lenx) < 0)
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
|
|
lwsl_notice("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
|
|
vhd->cwsi = NULL;
|
|
if (!vhd->autonomous_update) {
|
|
|
|
vhd->checked_updates = 1;
|
|
puts(vhd->json);
|
|
return -1;
|
|
}
|
|
|
|
/* autonomous download */
|
|
|
|
lwsl_notice("auton complete\n");
|
|
|
|
if (esp_ota_end(vhd->otahandle) != ESP_OK) {
|
|
lwsl_err("OTA: end failed\n");
|
|
return 1;
|
|
}
|
|
|
|
if (esp_ota_set_boot_partition(vhd->part) != ESP_OK) {
|
|
lwsl_err("OTA: set boot part failed\n");
|
|
return 1;
|
|
}
|
|
vhd->otahandle = 0;
|
|
vhd->autonomous_update = 0;
|
|
|
|
vhd->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(250), 0, vhd,
|
|
(TimerCallbackFunction_t)reboot_timer_cb);
|
|
xTimerStart(vhd->reboot_timer, 0);
|
|
return -1;
|
|
|
|
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
|
|
lwsl_notice("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n");
|
|
break;
|
|
|
|
case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
|
|
/* called when our wsi user_space is going to be destroyed */
|
|
if (pss->spa) {
|
|
lws_spa_destroy(pss->spa);
|
|
pss->spa = NULL;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
|
|
bail:
|
|
return 1;
|
|
}
|
|
|
|
#define LWS_PLUGIN_PROTOCOL_ESPLWS_SCAN \
|
|
{ \
|
|
"esplws-scan", \
|
|
callback_esplws_scan, \
|
|
sizeof(struct per_session_data__esplws_scan), \
|
|
1024, 0, NULL, 900 \
|
|
}
|
|
|