From 228a3ff0f06ce9cac110b2d8fb1fe39bfe2d9dc3 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Fri, 19 Jun 2015 23:35:23 -0700 Subject: [PATCH] fix crash due to weird espconn switcharoo --- httpd/httpd.c | 109 +++++++++++++++++++++++++++++------------------ httpd/httpd.h | 3 ++ user/cgiflash.c | 1 + user/user_main.c | 11 +++++ 4 files changed, 82 insertions(+), 42 deletions(-) diff --git a/httpd/httpd.c b/httpd/httpd.c index 85ffc8c..28a3f84 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -82,14 +82,37 @@ const char ICACHE_FLASH_ATTR *httpdGetMimetype(char *url) { return mimeTypes[i].mimetype; } +// debug string to identify connection (ip address & port) +// a static string works because callbacks don't get interrupted... +static char connStr[24]; + +static void debugConn(void *arg, char *what) { + struct espconn *espconn = arg; + esp_tcp *tcp = espconn->proto.tcp; + os_sprintf(connStr, "%d.%d.%d.%d:%d", + tcp->remote_ip[0], tcp->remote_ip[1], tcp->remote_ip[2], tcp->remote_ip[3], + tcp->remote_port); + //os_printf("%s %s\n", connStr, what); +} + //Looks up the connData info for a specific esp connection static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(void *arg) { - int i; - for (i=0; iproto.tcp->remote_port && + os_memcmp(connData[i].remote_ip, espconn->proto.tcp->remote_ip, 4) == 0) + { +#if 0 + os_printf("FindConn: 0x%p->0x%p", arg, &connData[i]); + if (arg == connData[i].conn) os_printf("\n"); + else os_printf(" *** was 0x%p\n", connData[i].conn); +#endif + if (arg != connData[i].conn) connData[i].conn = arg; // yes, this happens!? + return &connData[i]; + } } //Shouldn't happen. - os_printf("FindConnData: Huh? Couldn't find connection for %p\n", arg); + os_printf("%s *** Unknown connection 0x%p\n", connStr, arg); return NULL; } @@ -97,12 +120,14 @@ static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(void *arg) { static void ICACHE_FLASH_ATTR httpdRetireConn(HttpdConnData *conn) { uint32 dt = conn->startTime; if (dt > 0) dt = (system_get_time() - dt)/1000; - os_printf("Closed %p, took %ums, heap=%ld\n", conn->conn, dt, + os_printf("%s Closed, took %ums, heap=%ld\n", connStr, dt, (unsigned long)system_get_free_heap_size()); if (conn->post->buff!=NULL) os_free(conn->post->buff); conn->post->buff=NULL; conn->cgi=NULL; conn->conn=NULL; + conn->remote_port = 0; + conn->remote_ip[0] = 0; } //Stupid li'l helper function that returns the value of a hex char. @@ -243,7 +268,8 @@ int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) { int ICACHE_FLASH_ATTR httpdSend(HttpdConnData *conn, const char *data, int len) { if (len<0) len=strlen(data); if (conn->priv->sendBuffLen+len>MAX_SENDBUFF_LEN) { - os_printf("ERROR! httpdSend full (%d of %d)\n", conn->priv->sendBuffLen, MAX_SENDBUFF_LEN); + os_printf("%s ERROR! httpdSend full (%d of %d)\n", + connStr, conn->priv->sendBuffLen, MAX_SENDBUFF_LEN); return 0; } os_memcpy(conn->priv->sendBuff+conn->priv->sendBuffLen, data, len); @@ -256,15 +282,15 @@ static void ICACHE_FLASH_ATTR xmitSendBuff(HttpdConnData *conn) { if (conn->priv->sendBuffLen!=0) { sint8 status = espconn_sent(conn->conn, (uint8_t*)conn->priv->sendBuff, conn->priv->sendBuffLen); if (status != 0) { - os_printf("ERROR! espconn_sent returned %d\n", status); + os_printf("%s ERROR! espconn_sent returned %d\n", connStr, status); } conn->priv->sendBuffLen=0; } } -//Callback called when the data on a socket has been successfully -//sent. +//Callback called when the data on a socket has been successfully sent. static void ICACHE_FLASH_ATTR httpdSentCb(void *arg) { + debugConn(arg, "httpdSentCb"); int r; HttpdConnData *conn=httpdFindConnData(arg); char sendBuff[MAX_SENDBUFF_LEN]; @@ -274,9 +300,9 @@ static void ICACHE_FLASH_ATTR httpdSentCb(void *arg) { conn->priv->sendBuffLen=0; if (conn->cgi==NULL) { //Marked for destruction? - //os_printf("Conn %p is done. Closing.\n", conn->conn); + //os_printf("Closing 0x%p/0x%p->0x%p\n", arg, conn->conn, conn); espconn_disconnect(conn->conn); - httpdRetireConn(conn); + //httpdRetireConn(conn); // can't call this, we will get a diconnect callback! return; //No need to call xmitSendBuff. } @@ -285,7 +311,7 @@ static void ICACHE_FLASH_ATTR httpdSentCb(void *arg) { conn->cgi=NULL; //mark for destruction. } if (r==HTTPD_CGI_NOTFOUND || r==HTTPD_CGI_AUTHENTICATED) { - os_printf("ERROR! CGI fn returns code %d after sending data! Bad CGI!\n", r); + os_printf("%s ERROR! CGI fn returns code %d after sending data! Bad CGI!\n", connStr, r); conn->cgi=NULL; //mark for destruction. } xmitSendBuff(conn); @@ -301,7 +327,7 @@ static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) { int r; int i=0; if (conn->url==NULL) { - os_printf("WtF? url = NULL\n"); + os_printf("%s WtF? url = NULL\n", connStr); return; //Shouldn't happen } //See if we can find a CGI that's happy to handle the request. @@ -326,7 +352,7 @@ static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) { if (builtInUrls[i].url==NULL) { //Drat, we're at the end of the URL table. This usually shouldn't happen. Well, just //generate a built-in 404 to handle this. - os_printf("%s not found. 404!\n", conn->url); + os_printf("%s %s not found. 404!\n", connStr, conn->url); httpdSend(conn, httpNotFoundHeader, -1); xmitSendBuff(conn); conn->cgi=NULL; //mark for destruction @@ -379,18 +405,14 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) { if (e==NULL) return; //wtf? *e=0; //terminate url part - os_printf("%s %s (%p) %d.%d.%d.%d:%d\n", - conn->requestType == HTTPD_METHOD_GET ? "GET" : "POST", - conn->url, conn->conn, - conn->conn->proto.tcp->remote_ip[0], conn->conn->proto.tcp->remote_ip[1], - conn->conn->proto.tcp->remote_ip[2], conn->conn->proto.tcp->remote_ip[3], - conn->conn->proto.tcp->remote_port); + os_printf("%s %s %s\n", connStr, + conn->requestType == HTTPD_METHOD_GET ? "GET" : "POST", conn->url); //Parse out the URL part before the GET parameters. conn->getArgs=(char*)os_strstr(conn->url, "?"); if (conn->getArgs!=0) { *conn->getArgs=0; conn->getArgs++; - os_printf("GET args = %s\n", conn->getArgs); + os_printf("%s GET args = %s\n", connStr, conn->getArgs); } else { conn->getArgs=NULL; } @@ -409,7 +431,7 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) { } else { conn->post->buffSize = conn->post->len; } - os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->post->buffSize); + //os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->post->buffSize); conn->post->buff=(char*)os_malloc(conn->post->buffSize + 1); conn->post->buffLen=0; } else if (os_strncmp(h, "Content-Type: ", 14)==0) { @@ -420,7 +442,7 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) { conn->post->multipartBoundary = b + 7; // move the pointer 2 chars before boundary then fill them with dashes conn->post->multipartBoundary[0] = '-'; conn->post->multipartBoundary[1] = '-'; - os_printf("boundary = %s\n", conn->post->multipartBoundary); + //os_printf("boundary = %s\n", conn->post->multipartBoundary); } } } @@ -429,6 +451,7 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) { //Callback called when there's data available on a socket. static void ICACHE_FLASH_ATTR httpdRecvCb(void *arg, char *data, unsigned short len) { + debugConn(arg, "httpdRecvCb"); int x; char *p, *e; char sendBuff[MAX_SENDBUFF_LEN]; @@ -484,45 +507,47 @@ static void ICACHE_FLASH_ATTR httpdRecvCb(void *arg, char *data, unsigned short } static void ICACHE_FLASH_ATTR httpdDisconCb(void *arg) { - //The esp sdk passes through wrong arg here, namely the one of the *listening* socket. - //That is why we can't use (HttpdConnData)arg->sock here. - //Just look at all the sockets and kill the slot if needed. - int i; - for (i=0; i=ESPCONN_CLOSE and not ==? Well, seems the stack sometimes de-allocates - //espconns under our noses, especially when connections are interrupted. The memory - //is then used for something else, and we can use that to capture *most* of the - //disconnect cases. - if (connData[i].conn->state==ESPCONN_NONE || connData[i].conn->state>=ESPCONN_CLOSE) { - if (connData[i].cgi!=NULL) connData[i].cgi(&connData[i]); //flush cgi data - httpdRetireConn(&connData[i]); - } - } - } + debugConn(arg, "httpdDisconCb"); + HttpdConnData *conn = httpdFindConnData(arg); + if (conn == NULL) return; + if (conn->cgi != NULL) conn->cgi(conn); // free cgi data + httpdRetireConn(conn); } // Callback indicating a failure in the connection. "Recon" is probably intended in the sense // of "you need to reconnect". Sigh... static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) { - os_printf("Connection %p died, err=%d\n", arg, err); - httpdDisconCb(arg); // no different from close... + debugConn(arg, "httpdReconCb"); + HttpdConnData *conn = httpdFindConnData(arg); + os_printf("%s reset, err=%d\n", connStr, err); + if (conn == NULL) return; + conn->conn = NULL; // don't tr to send anything, the SDK crashes... + if (conn->cgi != NULL) conn->cgi(conn); // free cgi data + httpdRetireConn(conn); } static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) { + debugConn(arg, "httpdConnectCb"); struct espconn *conn=arg; int i; //Find empty conndata in pool for (i=0; iproto.tcp->remote_port; + os_memcpy(connData[i].remote_ip, conn->proto.tcp->remote_ip, 4); connData[i].priv->headPos=0; connData[i].post=&connPostData[i]; connData[i].post->buff=NULL; diff --git a/httpd/httpd.h b/httpd/httpd.h index adab463..5ceb1aa 100644 --- a/httpd/httpd.h +++ b/httpd/httpd.h @@ -21,6 +21,9 @@ typedef int (* cgiSendCallback)(HttpdConnData *connData); //A struct describing a http connection. This gets passed to cgi functions. struct HttpdConnData { struct espconn *conn; + int remote_port; + uint8 remote_ip[4]; + uint32 startTime; char requestType; char *url; diff --git a/user/cgiflash.c b/user/cgiflash.c index 5e1cb63..0706695 100644 --- a/user/cgiflash.c +++ b/user/cgiflash.c @@ -92,6 +92,7 @@ int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) { int code = 400; // check overall size + //os_printf("FW: %d (max %d)\n", connData->post->len, FIRMWARE_SIZE); if (connData->post->len > FIRMWARE_SIZE) err = "Firmware image too large"; // check that data starts with an appropriate header diff --git a/user/user_main.c b/user/user_main.c index 974db49..5471faf 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -109,6 +109,10 @@ void user_rf_pre_init(void) { // address of espfs binary blob extern uint32_t _binary_espfs_img_start; +static char *rst_codes[] = { + "normal", "wdt reset", "exception", "soft wdt", "restart", "deep sleep", "???", +}; + //Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done. void user_init(void) { // init gpio pins used to reset&reprogram attached microcontrollers @@ -144,5 +148,12 @@ void user_init(void) { os_timer_setfn(&prHeapTimer, prHeapTimerCb, NULL); os_timer_arm(&prHeapTimer, 3000, 1); #endif + + struct rst_info *rst_info = system_get_rst_info(); + os_printf("Reset cause: %d=%s\n", rst_info->reason, rst_codes[rst_info->reason]); + os_printf("exccause=%d epc1=0x%x epc2=0x%x epc3=0x%x excvaddr=0x%x depc=0x%x\n", + rst_info->exccause, rst_info->epc1, rst_info->epc2, rst_info->epc3, + rst_info->excvaddr, rst_info->depc); + os_printf("** esp-link ready\n"); }