mirror of
https://github.com/jeelabs/esp-link.git
synced 2026-03-13 04:36:47 +01:00
fix crash due to weird espconn switcharoo
This commit is contained in:
109
httpd/httpd.c
109
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; i<MAX_CONN; i++) {
|
||||
if (connData[i].conn==(struct espconn *)arg) return &connData[i];
|
||||
struct espconn *espconn = arg;
|
||||
for (int i=0; i<MAX_CONN; i++) {
|
||||
if (connData[i].remote_port == espconn->proto.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<MAX_CONN; i++) {
|
||||
if (connData[i].conn!=NULL) {
|
||||
//Why the >=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; i<MAX_CONN; i++) if (connData[i].conn==NULL) break;
|
||||
//os_printf("Con req, conn=%p, pool slot %d\n", conn, i);
|
||||
if (i==MAX_CONN) {
|
||||
os_printf("Aiee, conn pool overflow!\n");
|
||||
os_printf("%s Aiee, conn pool overflow!\n", connStr);
|
||||
espconn_disconnect(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
int num = 0;
|
||||
for (int j=0; j<MAX_CONN; j++) if (connData[j].conn != NULL) num++;
|
||||
os_printf("%s Connect (%d open)\n", connStr, num+1);
|
||||
|
||||
connData[i].priv=&connPrivData[i];
|
||||
connData[i].conn=conn;
|
||||
connData[i].remote_port = conn->proto.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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user