-
-
-
-
@Gordon Thanks for the tip, but it did not help.
I still get this at server startup:
Inactivity detected restarting webserver... Webserver restarted. >Uncaught Error: CIPSERVER failed (Timeout) at line 1 col 53 throw Error("CIPSERVER failed ("+(a?a:"Timeout")+")"); ^ in function called from system
Here is the inactivity checker with 2 sec delay for server start:
function checkInactivity() { if (Date.now() - lastPageHandled > 60000) { clearInterval(checkInactivityIntervalId); lastPageHandled = Date.now(); // Close server and reopen it. console.log("Inactivity detected restarting webserver..."); if (server) { server.close(); } server=undefined; setTimeout(function() { server = http.createServer(pageHandler); if (server) { console.log("Webserver restarted."); checkInactivityIntervalId = setInterval(checkInactivity, 2000); server.listen(80); } else { console.log("ERROR createServer() returned false."); console.log(err); setTimeout(function() { reboot(); }, 5000); return; } }, 2000); } }
-
@Gordon : Closing and creating the server does not seem to resolve the jam.
I made the inactivity checker like this:function checkInactivity() { if (Date.now() - lastPageHandled > 20000) { clearInterval(checkInactivityIntervalId); lastPageHandled = Date.now(); console.log("Inactivity detected restarting webserver..."); if (server) { server.close(); } server = http.createServer(pageHandler); if (server) { console.log("Webserver restarted."); checkInactivityIntervalId = setInterval(checkInactivity, 2000); server.listen(80); } else { console.log("ERROR createServer() returned false."); console.log(err); setTimeout(function() { reboot(); }, 5000); return; } } }
Should I do some deeper cleanup/reset/disconnection than just recreating the http server?
Also I get these errors during the restart:
>Uncaught Error: CIPSERVER failed (Timeout) at line 1 col 53 throw Error("CIPSERVER failed ("+(a?a:"Timeout")+")"); ^ in function called from system
-
@Gordon Faster timeout on client side makes the situation worse since the request that has gone out from client cannot be aborted in a way that it would go away from the buffers on network or sever side. Therefore issuing new request after timeout just adds to the pile. The request can be aborted on the client side ajax but I think that has no effect on server side.
Of course after timeout I could wait longer before issuing next request, but that is handled kind of automatically by waiting the timeout longer.
Using WebSockets is a bit more complicated (not done that before and I like the idea of stateless and client agnostic server) so I would not like to go there now that the requests actually work :-)
How should I close and reopen the server in a sound way (code example)?
By the way, thank you so much for helping me out!
-
@Gordon Unfortunately no help or different behavior in this case.
The 60 second timeout helps to give Espruino time to answer if several requests are buffered to be handled. The server already responds with Connection:close header, but that does not help when the request is not completed properly.Yes indeed the situation is like a DOS attack, but it should recover after the spam is over and that is not the case at the moment.
Next I will try the wifi disconnect trick. But how the server knows when to do that since everything seems fine on that side?
-
One difficulty is that on client side ajax I cannot make HTTP request with "Connection:Close" headers since they are forced to keep-alive.
Here is my client side request function:
var xhr; function httpGetAsync(theUrl, jsonpcb, ok, err) { if (xhr && xhr.readyState != 4) { xhr.abort(); } xhr = jQuery.ajax({ type:'GET', headers: {Connection: close}, // No effect url:theUrl, cache:false, timeout: (60000), jsonpCallback: jsonpcb, crossDomain: true, dataType: 'jsonp', error: err, success: ok, beforeSend: function( xhr, settings ) { xhr.setRequestHeader( "Connection", "close" ); // No effect settings.headers = {Connection: close}; // No effect } }); }
But still in wireshark I can see the request has "Connection : Keep-alive" in HTTP headers.
-
Yes @Gordon I removed the at.debug() and added the AT.CIPSTO like this:
console.log("Web server at: " + JSON.stringify(ip)); var http = require("http"); // E.enableWatchdog(2); wifi.at.cmd("AT+CIPSTO=2\r\n",1000,function(d) { print(d); var server = http.createServer(pageHandler); if (server) { server.listen(80) } else { console.log("ERROR createServer() returned false."); console.log(err); setTimeout(function() {reboot();}, 5000); return; } }
But it made no difference..
-
@Gordon Yes during the dump the clients failed to receive anything and wireshark showed only HTTP requests but not replies. I can reproduce the situation by first adding clients and in a few seconds it jams so that I can remove all the clients but one (once a second) and still it does not recover.
Now while testing I got E.getErrorFlags: BUFFER_FULL before it got stuck
And at restart of the Espruino I got FIFO_FULL, but then it recovered.In any error scenario I would like the node to restart, clear and continue to operate. How that could be done?
There are also many situations where the requests are not coming into the page handler at all. The EspruinoWifi server just sits there and does nothing while all the requests fail with timeout. It recovers when I upload the code and reset with the Web IDE when it is stuck it recovers.
-
If you look closely I am actually using B0 and B1 to replace A2 and A3 in the code so that is not the culprit.
And yes you are right hat the "rand" is for faking the actual analog readings with random number for testing client side views. That part works and I get good readings before it jams when overloaded by multiple clients. Client is a web page with jQuery ajax calls rendering values with highcharts to gauges and charts. The situation is easily reproduced by having several web pages requesting the Espruino simultaneously.What should be the timeout on the client side? I use 5 seconds. And 500 ms repeat interval.
After the Espruino server is flooded and stops responding in timely fashion, all the clients start to time out and they all have to be removed until it recovers. Still some requests go through slowly every now and then (the capture above). Those requests are seen in wireshark, but no reply. -
Here is my code:
function getA(pin, randomize) { if (randomize) return Math.round(100*Math.random()); else return Math.round(100*analogRead(pin)); } function returnJsonStr(res, json) { res.writeHead(200, {'Content-Type': 'application/json', 'Connection' : 'close', 'Content-Length': json.length}); res.write(json); //console.log("Returned JSON: " + json); } function returnError(res, msg) { res.writeHead(400, {'Content-Type': 'text/plain', 'Connection' : 'close', 'Content-Length': msg.length}); res.write(msg); //console.log("Returned error: " + msg); } var next_state = 1; function swap() { LED1.write(next_state); next_state = !next_state; } function pageHandler(req, res) { //console.log("Client request: " + JSON.stringify(req)); if (req.url == "/favicon.ico") { res.writeHead(200, {'Content-Type': 'image/x-icon'}); res.write(favicon); //console.log("Client served with favicon.ico"); } else if (req.url == "/led") { swap(); res.writeHead(200, {'Content-Type': 'text/plain'}); res.write("Led toggled."); console.log("Client toggled LED"); } else { var r = false; if (req.url.substring(0, 5) == "/rand") r = true; var content = "sensors(" + JSON.stringify([ { sensor : "A0", value : getA(A0, r) }, { sensor : "A1", value : getA(A1, r) }, { sensor : "A2", value : getA(B0, r) }, { sensor : "A3", value : getA(B1, r) }, { sensor : "A4", value : getA(A4, r) }, { sensor : "A5", value : getA(A5, r) }, { sensor : "A6", value : getA(A6, r) }, { sensor : "A7", value : getA(A7, r) } ]) + ")"; returnJsonStr(res, content); // console.log("Client served. (rand:"+r+") E.getErrorFlags: " + E.getErrorFlags()); } res.end(); } function reboot() { console.log("Restarting to recover error.."); E.enableWatchdog(1); while(1); } var favicon = "\0\0\x01\0\x01\0\x10\x10\x10\0\x01\0\x04\x00\xf0\0\0\0\x16\0\0\x00\x89PNG\x0d\x0a\x1a\x0a\0\0\0\x0dIHDR\0\0\0\x10\0\0\0\x10\x08\x06\0\0\0\x1f\xf3\xffa\0\0\x00\xb7IDAT8\x8d\xa5S\xc1\x0d\x03!\x0csN\xb7\x91w\xcaP\xde)3\xd1G\x09\x0a\x85\xab\xa8\xea\x0f\x02\x82c\x1b0\x92x\x82\xbb\xb7:\x8f\x08D\x84\xd5\xb5\x1b\x00H\xb6>N\x04uN\x12\x92\x10\x11S\xcd]\x0b\xbf\xa9\xe9\x8a\x00\xa0I\x1a*\x06A\x97\xb7\x90\xd4\x8e$A\x12\xee\xde\xb2vR\x90$\xc8q\xf6\x03\xbc\x15Ldw]\x88zpc\xab*\x8c\x08H\xb2A\x90\x1e\x97\xce\x1bd3\x00\xb8v\x9b\xa7p\xf7\xb6\x10\x9cb\xc9\xe0Wd\x06\x17\x80v\xe2\xfb\x09\x17\x00H\xfa\x8b\xc0\xba\x9c\xe3CU\xf1\xc8@\xd2\x08fW\xf8i3?U\x12\x18z\x16\xf5A\x9ddc_\xee\xbd~e{*z\x01|\xcdnfT\x03\x0an\0\0\0\x00IEND\xaeB`\x82"; var WIFI_NAME = "xxx"; var WIFI_OPTIONS = { password : "xxx" }; function onInit() { console.log("Connecting to WiFi"); var wifi = require("EspruinoWiFi"); wifi.connect(WIFI_NAME, WIFI_OPTIONS, function(err) { if (err) { console.log("ERROR connect():"); console.log(err); setTimeout(function() {reboot();}, 5000); return; } else { console.log("Connected"); wifi.getIP(function (err, ip) { if (err) { console.log("ERROR getIP():"); console.log(err); setTimeout(function() {reboot();}, 5000); return; } wifi.at.debug(); console.log("Web server at: " + JSON.stringify(ip)); var http = require("http"); // E.enableWatchdog(2); http.createServer(pageHandler).listen(80); }); } }); } save();
-
During the capture above the clients timed out and did not receive anything although some requests came through and were "handled" by the Espruino but not sent to network. Or then the client timed out before the reply was ready and sent too late. So it seems there is some request queue that is longer than client side timeout.
-
Yes its Espruino Wifi with embedded ESP8266.
The previous with wifi.at.debug() capture was indeed wrong and from the startup.Here is better one from the failure case:
["AT+CIPSEND=3,339\r\n" ] "2," <--- "2," ] "2,CLOSED\r\n" <--- "CLOSED\r\n" ] "2,CONNECT\r\n\r\n+IPD,2,367:GET /rand?c" <--- "2,CONNECT\r\n\r\n+IPD,2,367:GET /rand?c" ] "+IPD,2,356:allback=sensors&_=1475779474639 HTTP/1.1\r\nHost: 192.168.100.184\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW" <--- "allback=sensors&_=1475779474639 HTTP/1.1\r\nHost: 192.168.100.184\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW" ] "+IPD,2,222:64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\nAccept: */*\r\nReferer: http://192.168.100.97:8081/gauge.html\r\nAccept" <--- "64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\nAccept: */*\r\nReferer: http://192.168.100.97:8081/gauge.html\r\nAccept" ] "+IPD,2,76:-Encoding: gzip, deflate, sdch\r\nAccept-Language: en-US,en;q=0.8,fi;q=0.6\r\n\r\n" <--- "-Encoding: gzip, deflate, sdch\r\nAccept-Language: en-US,en;q=0.8,fi;q=0.6\r\n\r\n" ["AT+CIPSEND=2,339\r\n" ] "4,CL" <--- "4,CL" ] "4,CLOSED\r\n0,CLOSED\r\n" <--- "OSED\r\n0,CLOSED\r\n" ] "0,CON" <--- "0,CON" ] "0,CONNECT\r\n\r\n+IPD,0,367:GET /rand?callback=sensors&_=147" <--- "NECT\r\n\r\n+IPD,0,367:GET /rand?callback=sensors&_=147" ] "+IPD,0,335:5779474640 HTTP/1.1\r\nHost: 192.168.100.184\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36" <--- "5779474640 HTTP/1.1\r\nHost: 192.168.100.184\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36" ] "+IPD,0,200: (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\nAccept: */*\r\nReferer: http://192.168.100.97:8081/gauge.html\r\nAccept-Encoding: gzip, deflat" <--- " (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\nAccept: */*\r\nReferer: http://192.168.100.97:8081/gauge.html\r\nAccept-Encoding: gzip, deflat" ] "+IPD,0,53:e, sdch\r\nAccept-Language: en-US,en;q=0.8,fi;q=0.6\r\n\r\n4,CONNECT\r\n\r\n+IPD,4,367:GET /rand?callback=sensors&_=1475779456262 HTTP/1.1\r\nHost: 192.168.100.184\r\nConnection" <--- "e, sdch\r\nAccept-Language: en-US,en;q=0.8,fi;q=0.6\r\n\r\n4,CONNECT\r\n\r\n+IPD,4,367:GET /rand?callback=sensors&_=1475779456262 HTTP/1.1\r\nHost: 192.168.100.184\r\nConnection" ] "+IPD,4,281:: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\nAccept: */*\r\nReferer: http://192.168.100.97:8081/gauge.html\r\nAccept-Encoding: gzip, deflate, sdch\r\nAccept-Language: en-US,en;q=0.8,fi;q=0.6\r\n\r\n" <--- ": keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\nAccept: */*\r\nReferer: http://192.168.100.97:8081/gauge.html\r\nAccept-Encoding: gzip, deflate, sdch\r\nAccept-Language: en-US,en;q=0.8,fi;q=0.6\r\n\r\n" ["AT+CIPSEND=0,340\\r\n" ] "1,CLOSED\r\n" <--- "1,CLOSED\r\n" ] "1,CONNECT\r\n\r\n+IPD,1,367:GET /rand?callback=sensors&_=1475779474641 HTTP/1.1\r\nHost: 192.168.100.184\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (K" <--- "1,CONNECT\r\n\r\n+IPD,1,367:GET /rand?callback=sensors&_=1475779474641 HTTP/1.1\r\nHost: 192.168.100.184\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (K" ["AT+CIPSEND=4,339\r\n" ] "+IPD,1,197:HTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\nAccept: */*\r\nReferer: http://192.168.100.97:8081/gauge.html\r\nAccept-Encoding: gzip, deflate, sdch\r\nAccept-Language: en-US,en;q=0.8,fi;q=0.6\r\n\r\n" <--- "HTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\r\nAccept: */*\r\nReferer: http://192.168.100.97:8081/gauge.html\r\nAccept-Encoding: gzip, deflate, sdch\r\nAccept-Language: en-US,en;q=0.8,fi;q=0.6\r\n\r\n" ] "3,CL" <--- "3,CL" ] "3,CLOSED\r\n" <--- "OSED\r\n" ] "3,CONNECT\r\n\r\n+IPD,3,367:GET /rand?callback=sensors&_=1475779447035 HTTP/1.1\r\nHost: 192.168.100.184\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari" <--- "3,CONNECT\r\n\r\n+IPD,3,367:GET /rand?callback=sensors&_=1475779447035 HTTP/1.1\r\nHost: 192.168.100.184\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari" ["AT+CIPSEND=1,339\r\n" ] "+IPD,3,152:/537.36\r\nAccept: */*\r\nReferer: http://192.168.100.97:8081/gauge.html\r\nAccept-Encoding: gzip, deflate, sdch\r\nAccept-Language: en-US,en;q=0.8,fi;q=0.6\r\n\r\n" <--- "/537.36\r\nAccept: */*\r\nReferer: http://192.168.100.97:8081/gauge.html\r\nAccept-Encoding: gzip, deflate, sdch\r\nAccept-Language: en-US,en;q=0.8,fi;q=0.6\r\n\r\n" ["AT+CIPSEND=3,339\r\n" >
The issue is that since I cannot control the requests the server should fail gracefully, restart and not jam.
-
Before the hand E.getErrorFlags() returned LOW_MEMORY once.
The max frequency it still works is about 5 to 10 times per second.
Also the open connection might be one cause, but how to force them to close?wifi.at.debug() provided this lead:
["AT+CIPSERVER==1,80\r\n" >Uncaught Error: CIPSERVER failed (Timeout) at line 1 col 53 throw Error("CIPSERVER failed ("+(a?a:"Timeout")+")"); ^ in function called from system
-
With 270 Ohm resistor can I use all the analog pins?
What would be good step-down converter for 3.3V output? The DC voltage available may vary a lot from 9V to 16V (around 12V) or from 18V to 30V (around 24V), so I need converter that accepts wide input voltage range and stable 3.3V output.
With external power can the GND pin sink the current without overheating? -
Hi @Gordon, I was able to make a simple web server on Espruino Wifi board, but it stops responding http requests after awhile. It seems to depend on the http request frequency (overload); if there are several parallel requests coming the server stops output after awhile. I can still see requests coming in and handled by the web server on console window, but the response dot not go to network looking at Wireshark. And ping still goes through during the "outage". Sometimes it recovers after several minutes if the request frequency dropped.
What might cause this weird behavior? And how to make it fail gracefully without jamming totally? -
Thanks for the reply and support!
I used the pico shim v1 with the ESP8266.The plan is to support old standard zero to 180 ohm analog fuel tank level gauges. (I did the same with Arduino, but it was not reliable enough and hang after awhile and even watchdog did not work.)
To measure the resistor sensor it would be connected like this:
|------Sensor-----A1 pin
|
|----------------GND pin
|
|------Rref------+3.3v pinThe idea was to use 20 ohm resistor as Rref to give enough value range for analog measurement as the sensor resistance varies between 0 and 180 ohms.
Do you see any problems in this plan or ideas for improvement?
The same wiring would be done for all ADC pins available to enable several sensors to be read.Now I would like to know if there is the resistor sensor connected or not.
And then make another standard sensor that works from 30 to 240 ohms range as an alternative option that would be selected with e.g. dip switch for changing the Rref or telling the option to Espruino as digital input so that the values can be scaled accordingly.
-
-
-
-
-
@Gordon Now it recovers! Great! Thanks!
Of course that does not resolve the root cause..