Closed wilberforce closed 8 years ago
http - same result, -2
seems like these codes come from the network stack. If I put a non-existent hostname (e.g. blaafdiafi.com, it returns -6. If I put a host which has doesn't have the TCP port open (e.g. face.com), we get -0xb.
Perhaps it's worth increasing the buffer size - you have it 2K right? MBEDTLS_SSL_MAX_CONTENT_LEN to 2048
BTW - how did you get further so that it actually creates the socket?
I removed the IF statement in https://github.com/espruino/Espruino/blob/dc5cd0df3cc7e72c806980fe3d27298f8bd118e8/libs/network/network.c#L554
checking now with 2K
ahhh - its a decimal to hex hiding the details: https://github.com/espruino/Espruino/blob/4f40dcceba401e46c296b524990b6e98dabfd884/libs/network/socketerrors.h
typedef enum {
SOCKET_ERR_CLOSED = -1,
SOCKET_ERR_MEM = -2,
SOCKET_ERR_TIMEOUT = -3,
SOCKET_ERR_NO_ROUTE = -4,
SOCKET_ERR_BUSY = -5,
SOCKET_ERR_NOT_FOUND = -6,
SOCKET_ERR_MAX_SOCK = -7,
SOCKET_ERR_UNSENT_DATA = -8,
SOCKET_ERR_RESET = -9,
SOCKET_ERR_UNKNOWN = -10,
SOCKET_ERR_NO_CONN = -11,
SOCKET_ERR_BAD_ARG = -12,
SOCKET_ERR_SSL_HAND = -13,
SOCKET_ERR_SSL_INVALID = -14,
SOCKET_ERR_NO_RESP = -15,
SOCKET_ERR_LAST = -15, // not an error, just value of last error
} SocketError;
SOCKET_ERR_MEM = -2,
good work :)
>[tls.connect({host:'www.google.com',port:443}),process.memory(),esp.getState().freeHeap]
Connecting with TLS...
Performing the SSL/TLS handshake...
=[
{ "type": 4,
"opt": {
"host": "www.google.com",
"port": 443 },
"sckt": 15 },
{ "free": 133, "usage": 667, "total": 800, "history": 59 },
2240 ]
ERROR: Failed! mbedtls_ssl_handshake returned -0x2
Now need to guess which one is missing - heap or js vars
I removed the IF statement in
if (jsvIsObject(options)) {
if (!ssl_load_cacert(sd, options) ||
!ssl_load_owncert(sd, options) ||
!ssl_load_key(sd, options)) {
ssl_freeSocketData(sckt);
return false;
}
}
Looks like at least one is required in the or.. I think the forum post mentions these options...
tls.connect(options, callback) Description Create a socket connection using TLS Options can have ca, key and cert fields, which should be the decoded content of the certificate.
To use https:// you should not need to use the cert options... did you try:
require("http").get("https://www.google.com", function(res) {
res.on('data', function(data) { console.log(data); });
});
Now need to guess which one is missing - heap or js vars
Looks like heap:
https://github.com/espruino/Espruino/search?utf8=%E2%9C%93&q=SOCKET_ERR_MEM
507 int err = code; 508 switch (code) { 509 case ESPCONN_MEM: err = SOCKET_ERR_MEM; break; 510 case ESPCONN_ABRT: err = SOCKET_ERR_RESET; break; … 1001 releaseSocket(pSocketData); 1002 return SOCKET_ERR_MEM; 1003 }
Yup, seems like it is heap - less js vars, and now we are getting -0x7200
nearly all the time.
Well, after playing with esp-open-rtos for a while, it seems like MBEDTLS_SSL_MAX_CONTENT_LEN
has to be somewhere around 3900 bytes (or larger), otherwise the handshake fails.
@gfwilliams is there a way to allocate a big buffer off the js-vars space?
@urish all the memory needed for TLS comes straight out of the JsVars space already - so you need to increase the amount of variables as much as possible.
If you want to change that, you'll have to modify config.h
again to replace calls to Espruino's jsvar malloc implementation with malloc and free.
@gfwilliams thanks for the response! I will look into it further, some more questions that come into my head:
root@dd700b1d591e:/c/Users/Uri/Documents/esp-ssl# cat topstrings
10989 ./espruino_esp8266_partial.o
2493 ./libs/crypto/mbedtls/library/oid.o
1717 ./libs/crypto/mbedtls/library/x509_crt.o
Where can I find information how to move those strings into the Flash so they won't consume any RAM?
Thanks!
But actually without much success, so I'm not 100% sure what's going on there. There should be a bunch of stuff on the net about moving ESP8266 stuff from RAM into flash though
@tve already did a whole bunch here: 294f3ff
It involves #define to wrap the strings.
Yikes . The oid.c is full of strings! Are you sure you need it for tls v 1.2? Might be worth looking into the switches you need for a minimum build, I reference a minimum config.h above that might be worth a shot..
Actually you should note that some of this stuff works by first copying the string from flash into RAM - but you don't need to do that (and probably shouldn't in the case of the crypto). It'd be better to read directly from flash
following on what @gfwilliams is saying, here are the macro's that pack into iRom, and then read from it: https://github.com/espruino/Espruino/issues/770#issuecomment-181502608
Progress report - oid.c
is indeed needed for TLS, and I believe that so is x509_crt.c
.
So far, the only module that I was able to disable without impacting the ability to establish TLS connection is MBEDTLS_SSL_SRV_C
.
I tried to move the big tables into the ROM by adding __attribute__((section(".irom.literal")))
:
static const oid_x520_attr_t oid_x520_attr_type[] __attribute__((section(".irom.literal")) =
{
{
{ ADD_LEN( MBEDTLS_OID_AT_CN ), "id-at-commonName", "Common Name" },
"CN",
},
...
}
But this seems to have no affect on the size in topstrings (whereas commenting the entire struct content definitely reduces the size of the module in topstrings). Am I doing it right?
check object file with
xtensa-lx106-elf-objdump -h path/name_of_object_file.o
for a line with .irom.literal to make sure that it will be stored in flash
here is the definition of the macro:
https://github.com/espruino/Espruino/blob/b61d388fabfdc916892f66bef5b0029badd4a6ec/src/jsutils.h#L49
#define FLASH_STR(name, x) static char name[] __attribute__((section(".irom.literal"))) __attribute__((aligned(4))) = x
It also aligns of 4 byte boundarys which is required to read from flash.
and here is example use in the simple case: https://github.com/espruino/Espruino/blob/d7bfdaf0394ed9e3b242e9301cce59ebb045a0e3/libs/network/esp8266/jswrap_esp8266_network.c#L71
FLASH_STR(expect_cb, "Expecting callback function but got %v");
#define EXPECT_CB_EXCEPTION(jsCB) jsExceptionHere_flash(JSET_ERROR, expect_cb, jsCB)
I think in this case you are declaring arrays of strings, so this would need to be modified.... I don't see why your addition (with the aligned(4) would not work now for proof of concept...
Also here is using an array of strings, but there has got to be a better way! https://github.com/espruino/Espruino/blob/d7bfdaf0394ed9e3b242e9301cce59ebb045a0e3/libs/network/esp8266/jswrap_esp8266_network.c#L119
Looks like this is done a cunning way with arduino build: http://www.esp8266.com/viewtopic.php?f=9&t=5446
lfaustini wrote:how can I push the WString.cpp.o into the .irom0.text section? I believe that ESP8266-Arduino IDE uses a special linker script that puts many functions that are marked for the .text section into .irom0.text. The excerpt below comes from esp8266/Arduino on GitHub: CODE: SELECT ALL .irom0.text : ALIGN(4) { _irom0_text_start = ABSOLUTE(.); core_esp8266_.o(.literal, .text_) spiffs.o(.literal, .text) .cpp.o(.literal, .text) libm.a:(.literal .text .literal. .text.) libsmartconfig.a:(.literal .text .literal._ .text.) (.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) _irom0_text_end = ABSOLUTE(.); _flash_code_end = ABSOLUTE(.); } >irom0_0_seg :irom0_0_phdr
So this ld file moves stuff into flash, without having to use macros.
I think it works on functions too.... Looks promising..
You could try it. I wonder if that's program code only though - He's talking about WString.o - not WStrings in general :)
The issue is that accesses to flash need to word-only and word-aligned. Just dumping a string into ROM will be fine until you go to access a character from it. Hence the macros.
Until the compiler is smart enough to auto-generate only word accesses for stuff in ROM, you will have no choice but to manually modify code.
@tve @gfwilliams
This technique installs an exception handler that catches the mis-aligned reads, and corrects them.
https://github.com/cesanta/smart.js/blob/master/smartjs/platforms/esp8266/user/esp_flash_bytes.c
It looks a lot simpler that having to copy all the ROM strings from iRom to ram before use...
What is the performance impact of this, though?
I have no idea - convenience vs performance?
well, the performance already isn't all that great. At some point it just sucks. You're gonna have to use some macro to put the strings into flash anyhow, is there that much to be gained by not having a macro that does the copy? How many bytes of strings are left? How many of those could possibly be moved to flash?
Top 20 from ./topstrings: 7250 ./espruino_esp8266_partial.o 765 ./src/jsinteractive.o 542 ./libs/network/socketserver.o 512 ./gen/jswrapper.o 438 ./libs/network/esp8266/jswrap_esp8266_network.o 387 ./libs/network/esp8266/ota.o 295 ./src/jslex.o 245 ./src/jsvar.o 225 ./src/jsparse.o 216 ./libs/network/telnet/jswrap_telnet.o 214 ./src/jswrap_process.o 207 ./targets/esp8266/esp8266_board_utils.o 207 ./src/jswrap_json.o 196 ./src/jswrap_io.o 196 ./libs/network/socketerrors.o 176 ./libs/network/esp8266/network_esp8266.o 151 ./targets/esp8266/user_main.o 146 ./src/jswrap_object.o 137 ./src/jswrap_espruino.o 132 ./src/jswrap_pipe.o
If the constants in jswrapper were aligned on 4 byte boundaries we could keep the reference tables in flash... That would save a heap of space".
The non- string tables might be any easy target, as they are generated - these are not showing in the top strings that you have kindly written.
we will probably also be able to get mbedTLS working on the ESP :-)
Assuming we could catch unaligned accesses, we could just copy all the const data to flash and remove the irom
defines completely. It sounds very tempting.
the performance already isn't all that great
I guess it depends how you look at it. It's not great, so would people notice if it got a bit worse? :) The main complaint at the moment actually seems to be lack of RAM, which this might help with.
If someone has some free time/inclination, maybe they could try this just dump everything into ROM, removing all the ESP8266-specific flash copying/etc, and using that exception handler. The only way to know for sure is to do some benchmarks and see how much it hits performance.
If it's loads then I think it'd be a bad idea, but if it's a few percent I think it's a hit worth taking.
From my point of view, it'd be nice to remove the slightly iffy preprocessor stuff around print statements, and I think if you're printing/making error messages then you don't really care about performance either.
The one thing I think could hit performance is the symbol table, but then a few very simple ESP8266-specific tweaks in jswrapper.c
could fix that.
Perhaps some of the mbedTLS stuff could end up being quite slow, but then if it's a choice of having it slow or not fitting it in at all, I think it's worth having it in.
@gfwilliams has merged the build with sha crypto for the esp8266 - so now the standard build will support web sockets:
In aes.c there is a save-to-rom macro, however in the esp8266 case the tables still end up in ram.
There is still not enough heap space for the buffers, so unless more code is moved from ram to irom, TLS support for https can't work without reducing jsvars.
My initial aim of supporting web sockets via SHA1 is done, so closing issue.
Adding the the Makefile:
The issue appears to be the flash_str #define:
I tried changing:
#define FLASH_STR(name, x) static char name[] __attribute__((section(".irom.literal"))) __attribute__((aligned(4))) = x
to
#define FLASH_STR(name, x) static char * name __attribute__((section(".irom.literal"))) __attribute__((aligned(4))) = x
libs/network/esp8266/jswrap_esp8266_network.c:151:3: error: initializer element is not constant wr0, wr1, wr2, wr3, wr4, wr5, wr6, wr7, wr8, wr9, __wr10, ^ libs/network/esp8266/jswrap_esp8266_network.c:151:3: error: (near initialization for 'wifiReasons[0]')
However then it fails here:
What is the best way to solve this?