From 0fe09527ed512e2a5733dd0d2c06bf89955e0927 Mon Sep 17 00:00:00 2001 From: vsky Date: Sat, 2 Sep 2017 00:00:26 +0200 Subject: [PATCH 1/4] Net_info module exposing ping function initial commit --- app/include/user_modules.h | 1 + app/modules/net_info.c | 147 +++++++++++++++++++++++++++++++++++++ docs/modules/net_info.md | 57 ++++++++++++++ mkdocs.yml | 1 + 4 files changed, 206 insertions(+) create mode 100644 app/modules/net_info.c create mode 100644 docs/modules/net_info.md diff --git a/app/include/user_modules.h b/app/include/user_modules.h index c04a6bdbbf..9cc5c60a98 100644 --- a/app/include/user_modules.h +++ b/app/include/user_modules.h @@ -39,6 +39,7 @@ //#define LUA_USE_MODULES_MDNS #define LUA_USE_MODULES_MQTT #define LUA_USE_MODULES_NET +//#define LUA_USE_MODULES_NET_INFO #define LUA_USE_MODULES_NODE #define LUA_USE_MODULES_OW //#define LUA_USE_MODULES_PCM diff --git a/app/modules/net_info.c b/app/modules/net_info.c new file mode 100644 index 0000000000..c0eda0f0fb --- /dev/null +++ b/app/modules/net_info.c @@ -0,0 +1,147 @@ +// *************************************************************************** +// net_info module for ESP8266 with nodeMCU +// +// Written by Lukas Voborsky (@voborsky) with great help by TerryE +// *************************************************************************** + +// #define NODE_DEBUG +#define LUA_USE_MODULES_NET_INFO + +#include "module.h" +#include "lauxlib.h" + +#include "lwip/ip_addr.h" +#include "espconn.h" +#include "lwip/dns.h" +#include "lwip/app/ping.h" + +/* +ping_opt needs to be the first element of the structure. It is a workaround to pass the +callback reference and self_ref to the ping_received function. Pointer the ping_option +structure is equal to the pointer to net_info_ping_t structure. +*/ +typedef struct { + struct ping_option ping_opt; + uint32_t ping_callback_ref; + } net_info_ping_t; +typedef net_info_ping_t* ping_t; + +/* + * ping_received_sent(pingresp) +*/ +#define LuaCBfunc lua_upvalueindex(1) +#define nipUD lua_upvalueindex(2) + +static int ping_received_sent(lua_State *L) { + struct ping_resp *resp = (struct ping_resp *) lua_touserdata (L, 1); + ping_t nip = (ping_t) lua_touserdata (L, nipUD); + lua_pushvalue(L, LuaCBfunc); + + NODE_DBG("[net_info ping_received_sent] nip = %p\n", nip); + + if (resp == NULL) { /* resolution failed so call the CB with 0 byte count to flag this */ + luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); + lua_pushinteger(L, 0); + luaL_pcallx(L, 1, 0); + return 0; + } + char ipaddrstr[16]; + ipaddr_ntoa_r((ip_addr_t *) &nip->ping_opt.ip, ipaddrstr, sizeof(ipaddrstr)); + + if (resp->total_count == 0) { /* processing receive response */ + NODE_DBG("[ping_received] %s: resp_time=%d seqno=%d bytes=%d ping_err=%d\n", + ipaddrstr, resp->resp_time, resp->seqno, resp->bytes, resp->ping_err); + lua_pushinteger(L, resp->bytes); + lua_pushstring(L, ipaddrstr); + lua_pushinteger(L, resp->seqno); + lua_pushinteger(L, resp->ping_err == 0 ? resp->resp_time: -1); + luaL_pcallx(L, 4, 0); + } else { /* sent completion is currently a No-op */ + NODE_DBG("[ping_sent] %s: total_count=%d timeout_count=%d " + "total_bytes=%d total_time=%d\n", + ipaddrstr, resp->total_count, resp->timeout_count, + resp->total_bytes, resp->total_time); + luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); + } + return 0; +} + + +/* + * Wrapper to call ping_received_sent(pingresp) + */ +static void ping_CB(net_info_ping_t *nip, struct ping_resp *pingresp) { + NODE_DBG("[net_info ping_CB] nip = %p, nip->ping_callback_ref = %p, pingresp= %p\n", nip, nip->ping_callback_ref, pingresp); + lua_State *L = lua_getstate(); + lua_rawgeti(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); + lua_pushlightuserdata(L, pingresp); + lua_call(L, 1, 0); // call the closure (ping_received_sent) +} + +/* + * Wrapper to call ping_start using fully resolve IP4 address + */ +static void net_info_ping_raw(const char *name, ip_addr_t *ipaddr, ping_t nip) { + NODE_DBG("[net_info_ping_raw] name = %s, ipaddr= %x\n", name, ipaddr); + if (ipaddr) { + char ipaddrstr[16]; + ipaddr_ntoa_r(ipaddr, ipaddrstr, sizeof(ipaddrstr)); + NODE_DBG("[net_info_ping_raw] ip: %s\n", ipaddrstr); + } + lua_State *L = lua_getstate(); + + if (!ipaddr || ipaddr->addr == 0xFFFFFFFF) { + ping_CB(nip, NULL); /* A NULL pinresp flags DNS resolution failure */ + return; + } + + nip->ping_opt.ip = ipaddr->addr; + NODE_DBG("[net_info_ping_raw] calling ping_start\n"); + if (!ping_start(&(nip->ping_opt))) { + luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); + luaL_error(L, "memory allocation error: cannot start ping"); + } +} + +// Lua: net_info.ping(target, [count], responseCB) +static int net_info_ping(lua_State *L) +{ + ip_addr_t addr; + + // retrieve function parameters + const char *ping_target = luaL_checkstring(L, 1); + bool isf2 = lua_isfunction(L, 2); + lua_Integer l_count = isf2 ? 0: luaL_optinteger(L, 2, 0); /* use ping_start() default */ + lua_settop(L, isf2 ? 2 : 3); + luaL_argcheck(L, lua_isfunction(L, -1), -1, "no callback specified"); + + ping_t nip = (ping_t) memset(lua_newuserdata(L, sizeof(*nip)), 0, sizeof(*nip)); + + /* Register C closure with 2 Upvals: (1) Lua CB function; (2) nip Userdata */ + lua_pushcclosure(L, ping_received_sent, 2); // stack has nip UD, responseCB; [-n, +1, m] + + nip->ping_callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); // registers the closure to registry [-1, +0, m] + nip->ping_opt.count = l_count; + nip->ping_opt.coarse_time = 0; + nip->ping_opt.recv_function = (ping_recv_function) &ping_CB; + nip->ping_opt.sent_function = (ping_sent_function) &ping_CB; + + NODE_DBG("[net_info_ping] nip = %p, nip->ping_callback_ref = %p\n", nip, nip->ping_callback_ref); + + err_t err = dns_gethostbyname(ping_target, &addr, (dns_found_callback) net_info_ping_raw, nip); + if (err != ERR_OK && err != ERR_INPROGRESS) { + luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); + return luaL_error(L, "lwip error %d", err); + } + if (err == ERR_OK) { + NODE_DBG("[net_info_ping] No DNS resolution needed\n"); + net_info_ping_raw(ping_target, &addr, nip); + } + return 0; +} + +LROT_BEGIN(net_info, NULL, 0) + LROT_FUNCENTRY( ping, net_info_ping ) +LROT_END( net_info, NULL, 0 ) + +NODEMCU_MODULE(NET_INFO, "net_info", net_info, NULL); diff --git a/docs/modules/net_info.md b/docs/modules/net_info.md new file mode 100644 index 0000000000..742d198d8b --- /dev/null +++ b/docs/modules/net_info.md @@ -0,0 +1,57 @@ +# net_info Module +| Since | Origin / Contributor | Maintainer | Source | +| :----- | :-------------------- | :---------- | :------ | +| 2020-05-03 | [vsky279](https://github.com/vsky279) | [vsky279](https://github.com/vsky279) | [net_info.c](../../../app/modules/net_info.c) + +This module is a wrapper for common network diagnostic and analysis tools. + +## net_info Module Methods + +### ni:ping() + +This is a function to ping a server. A callback function is called when response is received. + +#### Syntax +`ni:ping(ip_address, [count], callback)` + +#### Parameters +- `domain` destination domain or IP address +- `count` number of ping packets to be sent (optional parameter, default value is 4) +- `callback(bytes, ipaddr, seqno, rtt)` callback function which is invoked when response is received where + - `bytes` number of bytes received from destination server (0 means no response) + - `ipaddr` destination serve IP address + - `seqno` ICMP sequence number (does not increment when no response is received) + - `rtt` round trip time in ms + +If domain name cannot be resolved callback is invoked with `bytes` parameter equal to 0 (i.e. no response) and `nil` values for all other parameters. + +#### Returns +`nil` + +#### Example +```lua +net_info.ping("www.nodemcu.com", function (b, ip, sq, tm) + if ip then print(("%d bytes from %s, icmp_seq=%d time=%dms"):format(b, ip, sq, tm)) else print("Invalid IP address") end + end) +``` + +Multiple pings can start in short sequence thought if the new ping overlaps with the previous one the first stops receiving answers, i.e. +```lua +function ping_resp(b, ip, sq, tm) + print(string.format("%d bytes from %s, icmp_seq=%d time=%dms", b, ip, sq, tm)) +end + +net_info.ping("8.8.8.8", 4, ping_resp) +tmr.create():alarm(1000, tmr.ALARM_SINGLE, function() net_info.ping("8.8.4.4", 4, ping_resp) end) +``` +gives +``` +32 bytes from 8.8.8.8, icmp_seq=9 time=14ms +32 bytes from 8.8.8.8, icmp_seq=10 time=9ms +32 bytes from 8.8.4.4, icmp_seq=11 time=6ms +32 bytes from 8.8.4.4, icmp_seq=13 time=12ms +0 bytes from 8.8.8.8, icmp_seq=0 time=0ms +32 bytes from 8.8.4.4, icmp_seq=15 time=16ms +0 bytes from 8.8.8.8, icmp_seq=0 time=0ms +32 bytes from 8.8.4.4, icmp_seq=16 time=7ms +``` diff --git a/mkdocs.yml b/mkdocs.yml index a63b90a0aa..f450b92e08 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -92,6 +92,7 @@ pages: - 'mdns': 'modules/mdns.md' - 'mqtt': 'modules/mqtt.md' - 'net': 'modules/net.md' + - 'net_info': 'modules/net_info.md' - 'node': 'modules/node.md' - 'ow (1-Wire)': 'modules/ow.md' - 'pcm' : 'modules/pcm.md' From 9ea9272286c09f6cae859a4b115ca3cb9939d720 Mon Sep 17 00:00:00 2001 From: vsky Date: Sun, 10 May 2020 11:36:54 +0200 Subject: [PATCH 2/4] Ping as a part of net module --- app/include/user_config.h | 3 ++ app/include/user_modules.h | 1 - app/modules/net.c | 5 ++++ app/modules/net_info.c | 17 ++++-------- app/modules/net_info.h | 3 ++ docs/modules/net.md | 55 ++++++++++++++++++++++++++++++++++++ docs/modules/net_info.md | 57 -------------------------------------- 7 files changed, 72 insertions(+), 69 deletions(-) create mode 100644 app/modules/net_info.h delete mode 100644 docs/modules/net_info.md diff --git a/app/include/user_config.h b/app/include/user_config.h index 82b0c1cd52..bb97a207d8 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -136,6 +136,9 @@ //#define TIMER_SUSPEND_ENABLE //#define PMSLEEP_ENABLE +// The net module optionally offers net info functionnality. Uncomment the following +// to enable the functionnality. +//#define NET_INFO_ENABLE // The WiFi module optionally offers an enhanced level of WiFi connection // management, using internal timer callbacks. Whilst many Lua developers diff --git a/app/include/user_modules.h b/app/include/user_modules.h index 9cc5c60a98..c04a6bdbbf 100644 --- a/app/include/user_modules.h +++ b/app/include/user_modules.h @@ -39,7 +39,6 @@ //#define LUA_USE_MODULES_MDNS #define LUA_USE_MODULES_MQTT #define LUA_USE_MODULES_NET -//#define LUA_USE_MODULES_NET_INFO #define LUA_USE_MODULES_NODE #define LUA_USE_MODULES_OW //#define LUA_USE_MODULES_PCM diff --git a/app/modules/net.c b/app/modules/net.c index 73496989a6..f7b3a58473 100644 --- a/app/modules/net.c +++ b/app/modules/net.c @@ -20,6 +20,8 @@ #include "lwip/udp.h" #include "lwip/dhcp.h" +#include "net_info.h" + typedef enum net_type { TYPE_TCP_SERVER = 0, TYPE_TCP_CLIENT, @@ -1070,6 +1072,9 @@ LROT_BEGIN(net, NULL, 0) LROT_FUNCENTRY( ifinfo, net_ifinfo ) LROT_FUNCENTRY( multicastJoin, net_multicastJoin ) LROT_FUNCENTRY( multicastLeave, net_multicastLeave ) +#ifdef NET_INFO_ENABLE + LROT_FUNCENTRY( ping, net_info_ping ) +#endif LROT_TABENTRY( dns, net_dns_map ) #ifdef TLS_MODULE_PRESENT LROT_TABENTRY( cert, tls_cert ) diff --git a/app/modules/net_info.c b/app/modules/net_info.c index c0eda0f0fb..2aec02442a 100644 --- a/app/modules/net_info.c +++ b/app/modules/net_info.c @@ -5,8 +5,9 @@ // *************************************************************************** // #define NODE_DEBUG -#define LUA_USE_MODULES_NET_INFO +#include "net_info.h" + #include "module.h" #include "lauxlib.h" @@ -103,8 +104,8 @@ static void net_info_ping_raw(const char *name, ip_addr_t *ipaddr, ping_t nip) { } } -// Lua: net_info.ping(target, [count], responseCB) -static int net_info_ping(lua_State *L) +// Lua: net.ping(domain, [count], callback) +int net_info_ping(lua_State *L) { ip_addr_t addr; @@ -118,7 +119,7 @@ static int net_info_ping(lua_State *L) ping_t nip = (ping_t) memset(lua_newuserdata(L, sizeof(*nip)), 0, sizeof(*nip)); /* Register C closure with 2 Upvals: (1) Lua CB function; (2) nip Userdata */ - lua_pushcclosure(L, ping_received_sent, 2); // stack has nip UD, responseCB; [-n, +1, m] + lua_pushcclosure(L, ping_received_sent, 2); // stack has nip UD, callback; [-n, +1, m] nip->ping_callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); // registers the closure to registry [-1, +0, m] nip->ping_opt.count = l_count; @@ -127,7 +128,7 @@ static int net_info_ping(lua_State *L) nip->ping_opt.sent_function = (ping_sent_function) &ping_CB; NODE_DBG("[net_info_ping] nip = %p, nip->ping_callback_ref = %p\n", nip, nip->ping_callback_ref); - + err_t err = dns_gethostbyname(ping_target, &addr, (dns_found_callback) net_info_ping_raw, nip); if (err != ERR_OK && err != ERR_INPROGRESS) { luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); @@ -139,9 +140,3 @@ static int net_info_ping(lua_State *L) } return 0; } - -LROT_BEGIN(net_info, NULL, 0) - LROT_FUNCENTRY( ping, net_info_ping ) -LROT_END( net_info, NULL, 0 ) - -NODEMCU_MODULE(NET_INFO, "net_info", net_info, NULL); diff --git a/app/modules/net_info.h b/app/modules/net_info.h new file mode 100644 index 0000000000..094447500a --- /dev/null +++ b/app/modules/net_info.h @@ -0,0 +1,3 @@ +#ifdef NET_INFO_ENABLE +int net_info_ping(lua_State *L); +#endif diff --git a/docs/modules/net.md b/docs/modules/net.md index f6d6901f05..4bd7b5d5a6 100644 --- a/docs/modules/net.md +++ b/docs/modules/net.md @@ -626,6 +626,61 @@ Sets the IP of the DNS server used to resolve hostnames. Default: resolver1.open #### See also [`net.dns:getdnsserver()`](#netdnsgetdnsserver) + +### net.ping() + +This is a function to ping a server. A callback function is called when response is or is not received. + +The function is disabled by default to enable this functionnality define `NET_INFO_ENABLE` macro needs to be defined in `user_config.h`. + +#### Syntax +`net.ping(domain, [count], callback)` + +#### Parameters +- `domain` destination domain or IP address +- `count` number of ping packets to be sent (optional parameter, default value is 4) +- `callback(bytes, ipaddr, seqno, rtt)` callback function which is invoked when response is received where + - `bytes` number of bytes received from destination server (0 means no response) + - `ipaddr` destination serve IP address + - `seqno` ICMP sequence number + - `rtt` round trip time in ms + +If domain name cannot be resolved callback is invoked with `bytes` parameter equal to 0 (i.e. no response) and `nil` values for all other parameters. + +#### Returns +`nil` + +#### Example +```lua +net.ping("www.nodemcu.com", function (b, ip, sq, tm) + if ip then print(("%d bytes from %s, icmp_seq=%d time=%dms"):format(b, ip, sq, tm)) else print("Invalid IP address") end + end) +``` + +Multiple pings can start in short sequence thought if the new ping overlaps with the previous one the first stops receiving answers, i.e. +```lua +function ping_resp(b, ip, sq, tm) + print(string.format("%d bytes from %s, icmp_seq=%d time=%dms", b, ip, sq, tm)) +end + +net.ping("8.8.8.8", 4, ping_resp) +tmr.create():alarm(1000, tmr.ALARM_SINGLE, function() net.ping("8.8.4.4", 4, ping_resp) end) +``` +gives +``` +32 bytes from 8.8.8.8, icmp_seq=9 time=14ms +32 bytes from 8.8.8.8, icmp_seq=10 time=9ms +32 bytes from 8.8.4.4, icmp_seq=11 time=6ms +32 bytes from 8.8.4.4, icmp_seq=13 time=12ms +0 bytes from 8.8.8.8, icmp_seq=0 time=0ms +32 bytes from 8.8.4.4, icmp_seq=15 time=16ms +0 bytes from 8.8.8.8, icmp_seq=0 time=0ms +32 bytes from 8.8.4.4, icmp_seq=16 time=7ms +``` + + + + # net.cert Module This part gone to the [TLS](tls.md) module, link kept for backward compatibility. diff --git a/docs/modules/net_info.md b/docs/modules/net_info.md deleted file mode 100644 index 742d198d8b..0000000000 --- a/docs/modules/net_info.md +++ /dev/null @@ -1,57 +0,0 @@ -# net_info Module -| Since | Origin / Contributor | Maintainer | Source | -| :----- | :-------------------- | :---------- | :------ | -| 2020-05-03 | [vsky279](https://github.com/vsky279) | [vsky279](https://github.com/vsky279) | [net_info.c](../../../app/modules/net_info.c) - -This module is a wrapper for common network diagnostic and analysis tools. - -## net_info Module Methods - -### ni:ping() - -This is a function to ping a server. A callback function is called when response is received. - -#### Syntax -`ni:ping(ip_address, [count], callback)` - -#### Parameters -- `domain` destination domain or IP address -- `count` number of ping packets to be sent (optional parameter, default value is 4) -- `callback(bytes, ipaddr, seqno, rtt)` callback function which is invoked when response is received where - - `bytes` number of bytes received from destination server (0 means no response) - - `ipaddr` destination serve IP address - - `seqno` ICMP sequence number (does not increment when no response is received) - - `rtt` round trip time in ms - -If domain name cannot be resolved callback is invoked with `bytes` parameter equal to 0 (i.e. no response) and `nil` values for all other parameters. - -#### Returns -`nil` - -#### Example -```lua -net_info.ping("www.nodemcu.com", function (b, ip, sq, tm) - if ip then print(("%d bytes from %s, icmp_seq=%d time=%dms"):format(b, ip, sq, tm)) else print("Invalid IP address") end - end) -``` - -Multiple pings can start in short sequence thought if the new ping overlaps with the previous one the first stops receiving answers, i.e. -```lua -function ping_resp(b, ip, sq, tm) - print(string.format("%d bytes from %s, icmp_seq=%d time=%dms", b, ip, sq, tm)) -end - -net_info.ping("8.8.8.8", 4, ping_resp) -tmr.create():alarm(1000, tmr.ALARM_SINGLE, function() net_info.ping("8.8.4.4", 4, ping_resp) end) -``` -gives -``` -32 bytes from 8.8.8.8, icmp_seq=9 time=14ms -32 bytes from 8.8.8.8, icmp_seq=10 time=9ms -32 bytes from 8.8.4.4, icmp_seq=11 time=6ms -32 bytes from 8.8.4.4, icmp_seq=13 time=12ms -0 bytes from 8.8.8.8, icmp_seq=0 time=0ms -32 bytes from 8.8.4.4, icmp_seq=15 time=16ms -0 bytes from 8.8.8.8, icmp_seq=0 time=0ms -32 bytes from 8.8.4.4, icmp_seq=16 time=7ms -``` From bc8d73fc63aa5ba04c8f0beaea42d49f9ca5bf1b Mon Sep 17 00:00:00 2001 From: vsky Date: Sun, 10 May 2020 17:18:21 +0200 Subject: [PATCH 3/4] Sent callback implemented Changed to NET_PING_ENABLE macro --- app/include/user_config.h | 2 +- app/modules/net.c | 6 +-- app/modules/net_info.h | 3 -- app/modules/{net_info.c => net_ping.c} | 61 ++++++++++++++++---------- app/modules/net_ping.h | 3 ++ docs/modules/net.md | 33 +++++++++----- 6 files changed, 67 insertions(+), 41 deletions(-) delete mode 100644 app/modules/net_info.h rename app/modules/{net_info.c => net_ping.c} (68%) create mode 100644 app/modules/net_ping.h diff --git a/app/include/user_config.h b/app/include/user_config.h index bb97a207d8..928d58847f 100644 --- a/app/include/user_config.h +++ b/app/include/user_config.h @@ -138,7 +138,7 @@ // The net module optionally offers net info functionnality. Uncomment the following // to enable the functionnality. -//#define NET_INFO_ENABLE +#define NET_PING_ENABLE // The WiFi module optionally offers an enhanced level of WiFi connection // management, using internal timer callbacks. Whilst many Lua developers diff --git a/app/modules/net.c b/app/modules/net.c index f7b3a58473..74356d2658 100644 --- a/app/modules/net.c +++ b/app/modules/net.c @@ -20,7 +20,7 @@ #include "lwip/udp.h" #include "lwip/dhcp.h" -#include "net_info.h" +#include "net_ping.h" typedef enum net_type { TYPE_TCP_SERVER = 0, @@ -1072,8 +1072,8 @@ LROT_BEGIN(net, NULL, 0) LROT_FUNCENTRY( ifinfo, net_ifinfo ) LROT_FUNCENTRY( multicastJoin, net_multicastJoin ) LROT_FUNCENTRY( multicastLeave, net_multicastLeave ) -#ifdef NET_INFO_ENABLE - LROT_FUNCENTRY( ping, net_info_ping ) +#ifdef NET_PING_ENABLE + LROT_FUNCENTRY( ping, net_ping ) #endif LROT_TABENTRY( dns, net_dns_map ) #ifdef TLS_MODULE_PRESENT diff --git a/app/modules/net_info.h b/app/modules/net_info.h deleted file mode 100644 index 094447500a..0000000000 --- a/app/modules/net_info.h +++ /dev/null @@ -1,3 +0,0 @@ -#ifdef NET_INFO_ENABLE -int net_info_ping(lua_State *L); -#endif diff --git a/app/modules/net_info.c b/app/modules/net_ping.c similarity index 68% rename from app/modules/net_info.c rename to app/modules/net_ping.c index 2aec02442a..4cfbe7f4d2 100644 --- a/app/modules/net_info.c +++ b/app/modules/net_ping.c @@ -1,12 +1,12 @@ // *************************************************************************** -// net_info module for ESP8266 with nodeMCU +// net_ping functionnality for ESP8266 with nodeMCU // // Written by Lukas Voborsky (@voborsky) with great help by TerryE // *************************************************************************** // #define NODE_DEBUG -#include "net_info.h" +#include "net_ping.h" #include "module.h" #include "lauxlib.h" @@ -19,29 +19,30 @@ /* ping_opt needs to be the first element of the structure. It is a workaround to pass the callback reference and self_ref to the ping_received function. Pointer the ping_option -structure is equal to the pointer to net_info_ping_t structure. +structure is equal to the pointer to net_ping_t structure. */ typedef struct { struct ping_option ping_opt; uint32_t ping_callback_ref; - } net_info_ping_t; -typedef net_info_ping_t* ping_t; + } net_ping_t; +typedef net_ping_t* ping_t; /* * ping_received_sent(pingresp) */ -#define LuaCBfunc lua_upvalueindex(1) -#define nipUD lua_upvalueindex(2) +#define LuaCBreceivedfunc lua_upvalueindex(1) +#define LuaCBsentfunc lua_upvalueindex(2) +#define nipUD lua_upvalueindex(3) static int ping_received_sent(lua_State *L) { struct ping_resp *resp = (struct ping_resp *) lua_touserdata (L, 1); ping_t nip = (ping_t) lua_touserdata (L, nipUD); - lua_pushvalue(L, LuaCBfunc); NODE_DBG("[net_info ping_received_sent] nip = %p\n", nip); if (resp == NULL) { /* resolution failed so call the CB with 0 byte count to flag this */ luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); + lua_pushvalue(L, LuaCBreceivedfunc); lua_pushinteger(L, 0); luaL_pcallx(L, 1, 0); return 0; @@ -52,17 +53,28 @@ static int ping_received_sent(lua_State *L) { if (resp->total_count == 0) { /* processing receive response */ NODE_DBG("[ping_received] %s: resp_time=%d seqno=%d bytes=%d ping_err=%d\n", ipaddrstr, resp->resp_time, resp->seqno, resp->bytes, resp->ping_err); + lua_pushvalue(L, LuaCBreceivedfunc); lua_pushinteger(L, resp->bytes); lua_pushstring(L, ipaddrstr); lua_pushinteger(L, resp->seqno); lua_pushinteger(L, resp->ping_err == 0 ? resp->resp_time: -1); luaL_pcallx(L, 4, 0); - } else { /* sent completion is currently a No-op */ + } else { /* processing sent response */ NODE_DBG("[ping_sent] %s: total_count=%d timeout_count=%d " "total_bytes=%d total_time=%d\n", ipaddrstr, resp->total_count, resp->timeout_count, resp->total_bytes, resp->total_time); - luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); + + lua_pushvalue(L, LuaCBsentfunc); + if lua_isfunction(L, -1) { + lua_pushstring(L, ipaddrstr); + lua_pushinteger(L, resp->total_count); + lua_pushinteger(L, resp->timeout_count); + lua_pushinteger(L, resp->total_bytes); + lua_pushinteger(L, resp->total_time); + luaL_pcallx(L, 5, 0); + } + luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); /* unregister the closure */ } return 0; } @@ -71,7 +83,7 @@ static int ping_received_sent(lua_State *L) { /* * Wrapper to call ping_received_sent(pingresp) */ -static void ping_CB(net_info_ping_t *nip, struct ping_resp *pingresp) { +static void ping_CB(net_ping_t *nip, struct ping_resp *pingresp) { NODE_DBG("[net_info ping_CB] nip = %p, nip->ping_callback_ref = %p, pingresp= %p\n", nip, nip->ping_callback_ref, pingresp); lua_State *L = lua_getstate(); lua_rawgeti(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); @@ -82,12 +94,12 @@ static void ping_CB(net_info_ping_t *nip, struct ping_resp *pingresp) { /* * Wrapper to call ping_start using fully resolve IP4 address */ -static void net_info_ping_raw(const char *name, ip_addr_t *ipaddr, ping_t nip) { - NODE_DBG("[net_info_ping_raw] name = %s, ipaddr= %x\n", name, ipaddr); +static void net_ping_raw(const char *name, ip_addr_t *ipaddr, ping_t nip) { + NODE_DBG("[net_ping_raw] name = %s, ipaddr= %x\n", name, ipaddr); if (ipaddr) { char ipaddrstr[16]; ipaddr_ntoa_r(ipaddr, ipaddrstr, sizeof(ipaddrstr)); - NODE_DBG("[net_info_ping_raw] ip: %s\n", ipaddrstr); + NODE_DBG("[net_ping_raw] ip: %s\n", ipaddrstr); } lua_State *L = lua_getstate(); @@ -97,7 +109,7 @@ static void net_info_ping_raw(const char *name, ip_addr_t *ipaddr, ping_t nip) { } nip->ping_opt.ip = ipaddr->addr; - NODE_DBG("[net_info_ping_raw] calling ping_start\n"); + NODE_DBG("[net_ping_raw] calling ping_start\n"); if (!ping_start(&(nip->ping_opt))) { luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); luaL_error(L, "memory allocation error: cannot start ping"); @@ -105,7 +117,7 @@ static void net_info_ping_raw(const char *name, ip_addr_t *ipaddr, ping_t nip) { } // Lua: net.ping(domain, [count], callback) -int net_info_ping(lua_State *L) +int net_ping(lua_State *L) { ip_addr_t addr; @@ -113,13 +125,14 @@ int net_info_ping(lua_State *L) const char *ping_target = luaL_checkstring(L, 1); bool isf2 = lua_isfunction(L, 2); lua_Integer l_count = isf2 ? 0: luaL_optinteger(L, 2, 0); /* use ping_start() default */ - lua_settop(L, isf2 ? 2 : 3); - luaL_argcheck(L, lua_isfunction(L, -1), -1, "no callback specified"); + lua_settop(L, isf2 ? 3 : 4); + luaL_argcheck(L, lua_isfunction(L, -2), -2, "no received callback specified"); + luaL_argcheck(L, lua_isfunction(L, -1) || lua_isnil(L, -1), -1, "invalid sent callback, function expected"); ping_t nip = (ping_t) memset(lua_newuserdata(L, sizeof(*nip)), 0, sizeof(*nip)); - /* Register C closure with 2 Upvals: (1) Lua CB function; (2) nip Userdata */ - lua_pushcclosure(L, ping_received_sent, 2); // stack has nip UD, callback; [-n, +1, m] + /* Register C closure with 3 Upvals: (1) Lua CB receive function; (2) Lua CB sent function; (3) nip Userdata */ + lua_pushcclosure(L, ping_received_sent, 3); // stack has 2 callbacks and nip UD; [-3, +1, m] nip->ping_callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); // registers the closure to registry [-1, +0, m] nip->ping_opt.count = l_count; @@ -127,16 +140,16 @@ int net_info_ping(lua_State *L) nip->ping_opt.recv_function = (ping_recv_function) &ping_CB; nip->ping_opt.sent_function = (ping_sent_function) &ping_CB; - NODE_DBG("[net_info_ping] nip = %p, nip->ping_callback_ref = %p\n", nip, nip->ping_callback_ref); + NODE_DBG("[net_ping] nip = %p, nip->ping_callback_ref = %p\n", nip, nip->ping_callback_ref); - err_t err = dns_gethostbyname(ping_target, &addr, (dns_found_callback) net_info_ping_raw, nip); + err_t err = dns_gethostbyname(ping_target, &addr, (dns_found_callback) net_ping_raw, nip); if (err != ERR_OK && err != ERR_INPROGRESS) { luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); return luaL_error(L, "lwip error %d", err); } if (err == ERR_OK) { - NODE_DBG("[net_info_ping] No DNS resolution needed\n"); - net_info_ping_raw(ping_target, &addr, nip); + NODE_DBG("[net_ping] No DNS resolution needed\n"); + net_ping_raw(ping_target, &addr, nip); } return 0; } diff --git a/app/modules/net_ping.h b/app/modules/net_ping.h new file mode 100644 index 0000000000..ac2c2b0dc5 --- /dev/null +++ b/app/modules/net_ping.h @@ -0,0 +1,3 @@ +#ifdef NET_PING_ENABLE +int net_ping(lua_State *L); +#endif diff --git a/docs/modules/net.md b/docs/modules/net.md index 4bd7b5d5a6..3712fdb1f4 100644 --- a/docs/modules/net.md +++ b/docs/modules/net.md @@ -629,23 +629,29 @@ Sets the IP of the DNS server used to resolve hostnames. Default: resolver1.open ### net.ping() -This is a function to ping a server. A callback function is called when response is or is not received. +Pings a server. A callback function is called when response is or is not received. Summary statistics can be retrieved via the second callback. -The function is disabled by default to enable this functionnality define `NET_INFO_ENABLE` macro needs to be defined in `user_config.h`. +The function can be disabled by commenting `NET_PING_ENABLE` macro in `user_config.h` when more compact build is needed. #### Syntax -`net.ping(domain, [count], callback)` +`net.ping(domain, [count], callback_received, [callback_sent])` #### Parameters - `domain` destination domain or IP address - `count` number of ping packets to be sent (optional parameter, default value is 4) -- `callback(bytes, ipaddr, seqno, rtt)` callback function which is invoked when response is received where +- `callback_received(bytes, ipaddr, seqno, rtt)` callback function which is invoked when response is received where - `bytes` number of bytes received from destination server (0 means no response) - - `ipaddr` destination serve IP address + - `ipaddr` destination server IP address - `seqno` ICMP sequence number - `rtt` round trip time in ms - If domain name cannot be resolved callback is invoked with `bytes` parameter equal to 0 (i.e. no response) and `nil` values for all other parameters. + +- `callback_sent(ipaddr, total_count, timeout_count, total_bytes, total_time)` callback function which is invoked when response is received where + - `ipaddrstr` destination server IP address + - `total_count` total number of packets sent + - `timeout_count` total number of packets lost (not received) + - `total_bytes` total number of bytes received from destination server + - `total_time` total time to perform ping #### Returns `nil` @@ -655,6 +661,15 @@ If domain name cannot be resolved callback is invoked with `bytes` parameter equ net.ping("www.nodemcu.com", function (b, ip, sq, tm) if ip then print(("%d bytes from %s, icmp_seq=%d time=%dms"):format(b, ip, sq, tm)) else print("Invalid IP address") end end) +net.ping("www.nodemcu.com", 10, function (b, ip, sq, tm) + if ip then print(("%d bytes from %s, icmp_seq=%d time=%dms"):format(b, ip, sq, tm)) else print("Invalid IP address") end + end) +net.ping("www.nodemcu.com", function (b, ip, sq, tm) + if ip then print(("%d bytes from %s, icmp_seq=%d time=%dms"):format(b, ip, sq, tm)) else print("Invalid IP address") end + end, + function (ip, tc, toc, tb, tt) + print(("--- %s ping statistics ---\n%d packets transmitted, %d received, %d%% packet loss, time %dms"):format(ip, tc, tc-toc, toc/tc*100, tt)) + end) ``` Multiple pings can start in short sequence thought if the new ping overlaps with the previous one the first stops receiving answers, i.e. @@ -672,15 +687,13 @@ gives 32 bytes from 8.8.8.8, icmp_seq=10 time=9ms 32 bytes from 8.8.4.4, icmp_seq=11 time=6ms 32 bytes from 8.8.4.4, icmp_seq=13 time=12ms -0 bytes from 8.8.8.8, icmp_seq=0 time=0ms +0 bytes from 8.8.8.8, icmp_seq=0 time=0ms -- no more answers received 32 bytes from 8.8.4.4, icmp_seq=15 time=16ms -0 bytes from 8.8.8.8, icmp_seq=0 time=0ms +0 bytes from 8.8.8.8, icmp_seq=0 time=0ms -- no more answers received 32 bytes from 8.8.4.4, icmp_seq=16 time=7ms ``` - - # net.cert Module This part gone to the [TLS](tls.md) module, link kept for backward compatibility. From 4f04c5303434aeee737a651d97d964d88ce359aa Mon Sep 17 00:00:00 2001 From: Terry Ellison Date: Sun, 10 May 2020 18:24:01 +0100 Subject: [PATCH 4/4] Update mkdocs.yml `net_info.md` no longer exists --- mkdocs.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index f450b92e08..a63b90a0aa 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -92,7 +92,6 @@ pages: - 'mdns': 'modules/mdns.md' - 'mqtt': 'modules/mqtt.md' - 'net': 'modules/net.md' - - 'net_info': 'modules/net_info.md' - 'node': 'modules/node.md' - 'ow (1-Wire)': 'modules/ow.md' - 'pcm' : 'modules/pcm.md'