Skip to content

Commit 315f2e3

Browse files
author
vsky
committed
Net_info module exposing ping function initial commit
1 parent 314ca4f commit 315f2e3

File tree

4 files changed

+226
-0
lines changed

4 files changed

+226
-0
lines changed

app/include/user_modules.h

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
//#define LUA_USE_MODULES_MDNS
4040
#define LUA_USE_MODULES_MQTT
4141
#define LUA_USE_MODULES_NET
42+
#define LUA_USE_MODULES_NET_INFO
4243
#define LUA_USE_MODULES_NODE
4344
#define LUA_USE_MODULES_OW
4445
//#define LUA_USE_MODULES_PCM

app/modules/net_info.c

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// ***************************************************************************
2+
// net_info module for ESP8266 with nodeMCU
3+
//
4+
// adopted jan 2017 for commit to nodeMCU by Wolfgang Rosner
5+
// re-worked by Lukas Voborsky, @voborsky
6+
// ***************************************************************************
7+
8+
// #define NODE_DEBUG
9+
10+
#include "module.h"
11+
#include "lauxlib.h"
12+
13+
#include "lwip/ip_addr.h"
14+
#include "espconn.h"
15+
#include "lwip/dns.h"
16+
#include "lwip/app/ping.h"
17+
18+
/*
19+
ping_opt needs to be the first element of the structure. It is a workaround to pass the
20+
callback reference and self_ref to the ping_received function. Pointer the ping_option
21+
structure is equal to the pointer to net_info_ping_t structure.
22+
*/
23+
typedef struct {
24+
struct ping_option ping_opt;
25+
sint32_t ping_callback_ref;
26+
sint32_t self_ref;
27+
} net_info_ping_t;
28+
typedef net_info_ping_t* ping_t;
29+
30+
static void ping_received(void *arg, void *data) {
31+
NODE_DBG("[ping_received] arg = %p, data = %p\n", arg, data);
32+
ping_t nip = (ping_t)arg; // override ping_option with net_info_ping_t to access the callback reference
33+
struct ping_resp *pingresp = (struct ping_resp*)data;
34+
35+
NODE_DBG("[ping_received] arg: total_count=%d resp_time=%d seqno=%d timeout_count=%d bytes=%d total_bytes=%d total_time=%d ping_err=%d\n", pingresp->total_count, pingresp->resp_time, pingresp->seqno, pingresp->timeout_count, pingresp->bytes, pingresp->total_bytes, pingresp->total_time, pingresp->ping_err);
36+
37+
char ipaddrstr[16];
38+
ip_addr_t source_ip;
39+
source_ip.addr = nip->ping_opt.ip;
40+
ipaddr_ntoa_r(&source_ip, ipaddrstr, sizeof(ipaddrstr));
41+
42+
lua_State *L = lua_getstate();
43+
lua_rawgeti(L, LUA_REGISTRYINDEX, nip->ping_callback_ref);
44+
lua_pushinteger(L, pingresp->bytes);
45+
lua_pushstring(L, ipaddrstr);
46+
lua_pushinteger(L, pingresp->seqno);
47+
lua_pushinteger(L, pingresp->resp_time);
48+
49+
lua_call(L, 4, 0);
50+
}
51+
52+
static int unregister_refs(lua_State* L, ping_t nip){
53+
if(nip->ping_callback_ref != LUA_NOREF) {
54+
NODE_DBG("[unregister_refs] luaL_unref nip->ping_callback_ref (%p)\n", nip->ping_callback_ref);
55+
luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref);
56+
nip->ping_callback_ref = LUA_NOREF;
57+
}
58+
if (nip->self_ref != LUA_REFNIL ) {
59+
NODE_DBG("[unregister_refs] luaL_unref nip->self_ref (%p, %p)\n", nip, nip->self_ref);
60+
luaL_unref(L, LUA_REGISTRYINDEX, nip->self_ref);
61+
nip->self_ref = LUA_NOREF;
62+
}
63+
}
64+
65+
static void ping_sent(void *arg, void *data) {
66+
NODE_DBG("[ping_sent] arg = %p, data = %p\n", arg, data);
67+
ping_t nip = (ping_t)arg;
68+
lua_State *L = lua_getstate();
69+
unregister_refs(L, nip);
70+
}
71+
72+
static void net_info_ping_raw(const char *name, ip_addr_t *ipaddr, void *arg) {
73+
ip_addr_t addr;
74+
NODE_DBG("[net_info_ping_raw] name = %s, ipaddr= %x\n", name, ipaddr);
75+
if (ipaddr != NULL) addr = *ipaddr;
76+
else addr.addr = 0xFFFFFFFF;
77+
NODE_DBG("[net_info_ping_raw] addr.addr = %x\n", addr.addr);
78+
79+
ping_t nip = (ping_t)arg;
80+
lua_State *L = lua_getstate();
81+
82+
if (addr.addr != 0xFFFFFFFF) {
83+
nip->ping_opt.ip = addr.addr;
84+
nip->ping_opt.coarse_time = 0;
85+
nip->ping_opt.recv_function = &ping_received;
86+
nip->ping_opt.sent_function = &ping_sent;
87+
88+
NODE_DBG("[net_info_ping_raw] calling ping_start\n");
89+
if (!ping_start(&(nip->ping_opt))) {
90+
unregister_refs(L, nip);
91+
luaL_error(L, "memory allocation error: cannot start ping");
92+
return;
93+
}
94+
} else {
95+
lua_rawgeti(L, LUA_REGISTRYINDEX, nip->ping_callback_ref);
96+
lua_pushinteger(L, 0);
97+
lua_call(L, 1, 0);
98+
unregister_refs(L, nip);
99+
return;
100+
}
101+
}
102+
103+
static int net_info_ping(lua_State *L)
104+
{
105+
// if (!luaL_getmetatable(L, "net_info.ping")) {
106+
// luaL_rometatable(L, "net_info.ping", LROT_TABLEREF(net_info_dyn));
107+
// }
108+
109+
ping_t nip = (ping_t)lua_newuserdata(L, sizeof(net_info_ping_t));
110+
luaL_getmetatable(L, "net_info.ping");
111+
lua_setmetatable(L, -2);
112+
nip->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
113+
nip->ping_callback_ref = LUA_NOREF;
114+
115+
NODE_DBG("[net_info_ping] nip = %p, nip->self_ref = %p\n", nip, nip->self_ref);
116+
117+
// retrieve function parameters
118+
const char *ping_target = luaL_checkstring(L, 1);
119+
bool isf2 = lua_isfunction(L, 2);
120+
nip->ping_opt.count = isf2 ? 0: luaL_optinteger(L, 2, 0); /* use ping_start() default */
121+
lua_settop(L, isf2 ? 2 : 3);
122+
luaL_argcheck(L, lua_isfunction(L, -1), -1, "no callback specified");
123+
nip->ping_callback_ref = luaL_ref(L, LUA_REGISTRYINDEX);
124+
125+
NODE_DBG("[net_info_ping] nip->ping_callback_ref = %p\n", nip->ping_callback_ref);
126+
127+
ip_addr_t addr;
128+
err_t err = dns_gethostbyname(ping_target, &addr, net_info_ping_raw, nip);
129+
if (err == ERR_OK) {
130+
NODE_DBG("[net_info_ping] dns_gethostbyname: ERR_OK\n", nip, nip->self_ref);
131+
net_info_ping_raw(ping_target, &addr, nip);
132+
} else if (err != ERR_INPROGRESS) {
133+
unregister_refs(L, nip);
134+
return luaL_error(L, "lwip error %d", err);
135+
}
136+
return 0;
137+
}
138+
139+
static int net_info_unregister(lua_State* L){
140+
ping_t nip = (ping_t)luaL_checkudata(L, 1, "net_info.ping");
141+
NODE_DBG("[net_info_unregister] nip = %p\n", nip);
142+
if (nip == NULL) {
143+
luaL_error(L, "ping object expected");
144+
return 0;
145+
}
146+
unregister_refs(L, nip);
147+
return 0;
148+
}
149+
150+
// Module function map
151+
LROT_BEGIN(net_info_dyn, NULL, LROT_MASK_GC_INDEX )
152+
LROT_FUNCENTRY( __gc, net_info_unregister )
153+
LROT_TABENTRY( __index, net_info_dyn )
154+
LROT_END( net_info_dyn, NULL, LROT_MASK_GC_INDEX )
155+
156+
157+
LROT_BEGIN(net_info, NULL, 0)
158+
LROT_FUNCENTRY( ping, net_info_ping )
159+
LROT_END( net_info, NULL, 0 )
160+
161+
int luaopen_net_info( lua_State *L ){
162+
NODE_DBG("[luaopen_net_info]\n");
163+
luaL_rometatable(L, "net_info.ping", LROT_TABLEREF(net_info_dyn));
164+
return 0;
165+
}
166+
167+
NODEMCU_MODULE(NET_INFO, "net_info", net_info, luaopen_net_info);

docs/modules/net_info.md

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# net_info Module
2+
| Since | Origin / Contributor | Maintainer | Source |
3+
| :----- | :-------------------- | :---------- | :------ |
4+
| 2020-05-03 | [vsky279](https://github.com/vsky279) | [vsky279](https://github.com/vsky279) | [net_info.c](../../../app/modules/net_info.c)
5+
6+
This module is a wrapper for common network diagnostic and analysis tools.
7+
8+
## net_info Module Methods
9+
10+
### ni:ping()
11+
12+
This is a function to ping a server. A callback function is called when response is received.
13+
14+
#### Syntax
15+
`ni:ping(ip_address, [count], callback)`
16+
17+
#### Parameters
18+
- `domain` destination domain or IP address
19+
- `count` number of ping packets to be sent (optional parameter, default value is 4)
20+
- `callback(bytes, ipaddr, seqno, rtt)` callback function which is invoked when response is received where
21+
- `bytes` number of bytes received from destination server (0 means no response)
22+
- `ipaddr` destination serve IP address
23+
- `seqno` ICMP sequence number (does not increment when no response is received)
24+
- `rtt` round trip time in ms
25+
26+
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.
27+
28+
#### Returns
29+
`nil`
30+
31+
#### Example
32+
```lua
33+
net_info.ping("www.nodemcu.com", function (b, ip, sq, tm)
34+
if ip then print(("%d bytes from %s, icmp_seq=%d time=%dms"):format(b, ip, sq, tm)) else print("Invalid IP address") end
35+
end)
36+
```
37+
38+
Multiple pings can start in short sequence thought if the new ping overlaps with the previous one the first stops receiving answers, i.e.
39+
```lua
40+
function ping_resp(b, ip, sq, tm)
41+
print(string.format("%d bytes from %s, icmp_seq=%d time=%dms", b, ip, sq, tm))
42+
end
43+
44+
net_info.ping("8.8.8.8", 4, ping_resp)
45+
tmr.create():alarm(1000, tmr.ALARM_SINGLE, function() net_info.ping("8.8.4.4", 4, ping_resp) end)
46+
```
47+
gives
48+
```
49+
32 bytes from 8.8.8.8, icmp_seq=9 time=14ms
50+
32 bytes from 8.8.8.8, icmp_seq=10 time=9ms
51+
32 bytes from 8.8.4.4, icmp_seq=11 time=6ms
52+
32 bytes from 8.8.4.4, icmp_seq=13 time=12ms
53+
0 bytes from 8.8.8.8, icmp_seq=0 time=0ms
54+
32 bytes from 8.8.4.4, icmp_seq=15 time=16ms
55+
0 bytes from 8.8.8.8, icmp_seq=0 time=0ms
56+
32 bytes from 8.8.4.4, icmp_seq=16 time=7ms
57+
```

mkdocs.yml

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ pages:
9292
- 'mdns': 'modules/mdns.md'
9393
- 'mqtt': 'modules/mqtt.md'
9494
- 'net': 'modules/net.md'
95+
- 'net_info': 'modules/net_info.md'
9596
- 'node': 'modules/node.md'
9697
- 'ow (1-Wire)': 'modules/ow.md'
9798
- 'pcm' : 'modules/pcm.md'

0 commit comments

Comments
 (0)