Skip to content

Commit cd8135f

Browse files
author
vsky
committed
Net_info module exposing ping function initial commit
1 parent 32ad759 commit cd8135f

File tree

6 files changed

+288
-1
lines changed

6 files changed

+288
-1
lines changed

app/include/lwip/app/ping.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ struct ping_option{
5454
ping_recv_function recv_function;
5555
ping_sent_function sent_function;
5656
void* reverse;
57+
struct ping_msg *parent_msg;
5758
};
5859

5960
struct ping_msg{
@@ -75,6 +76,7 @@ struct ping_resp{
7576
uint32 bytes;
7677
uint32 total_bytes;
7778
uint32 total_time;
79+
uint8 ttl;
7880
sint8 ping_err;
7981
};
8082

app/include/user_modules.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
//#define LUA_USE_MODULES_MDNS
3939
#define LUA_USE_MODULES_MQTT
4040
#define LUA_USE_MODULES_NET
41+
#define LUA_USE_MODULES_NET_INFO
4142
#define LUA_USE_MODULES_NODE
4243
#define LUA_USE_MODULES_OW
4344
//#define LUA_USE_MODULES_PCM

app/lwip/app/ping.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,14 @@ ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr)
164164
pingresp.resp_time = delay;
165165
pingresp.seqno = ntohs(iecho->seqno);
166166
pingresp.ping_err = 0;
167-
pingmsg->ping_opt->recv_function(pingmsg->ping_opt,(void*) &pingresp);
167+
pingresp.ttl = iphdr->_ttl;
168+
169+
// hand back pointer to message without breaking compatibility
170+
pingmsg->ping_opt->parent_msg = pingmsg;
171+
172+
// pingmsg->ping_opt->recv_function(pingmsg,(void*) &pingresp);
173+
pingmsg->ping_opt->recv_function(pingmsg->ping_opt, (void*) &pingresp);
174+
168175
}
169176
}
170177
seqno = iecho->seqno;

app/modules/net_info.c

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/*
2+
* http://blog.mclemon.io/esp8266-contributing-to-the-nodemcu-ecosystem
3+
* https://github.com/smcl/nodemcu-firmware/blob/cc04aaf92c1c076c30ef0b0eee43b3f924137440/app/modules/test.c
4+
*
5+
* extracted ping function
6+
* adopted jan 2017 for commit to nodeMCU by Wolfgang Rosner
7+
*/
8+
9+
10+
#include "module.h"
11+
#include "lauxlib.h"
12+
#include "platform.h"
13+
14+
// #include <string.h>
15+
// #include <strings.h>
16+
// #include <stddef.h>
17+
// #include <stdint.h>
18+
#include "mem.h"
19+
20+
#include "lwip/ip_addr.h"
21+
#include "espconn.h"
22+
#include "lwip/dns.h"
23+
#include "lwip/app/ping.h"
24+
#include "lwip/raw.h"
25+
26+
27+
#include "task/task.h"
28+
29+
30+
31+
// https://github.com/nodemcu/nodemcu-firmware/wiki/[DRAFT]-How-to-write-a-C-module#debug-and-error-messages
32+
33+
#define NET_INFO_DEBUG_ON
34+
35+
#define log_prefix " ### DEBUG: net_info ### : "
36+
37+
#if defined(DEVELOP_VERSION)
38+
#define NET_INFO_DEBUG_ON
39+
#endif
40+
#if defined(NET_INFO_DEBUG_ON)
41+
#define NET_INFO_DEBUG(format, ...) dbg_printf("%s"format"", log_prefix, ##__VA_ARGS__)
42+
#else
43+
#define NET_INFO_DEBUG(...)
44+
#endif
45+
#if defined(NODE_ERROR)
46+
#define NET_INFO_ERR(format, ...) NODE_ERR("%s"format"\n", log_prefix, ##__VA_ARGS__)
47+
#else
48+
#define NET_INFO_ERR(...)
49+
#endif
50+
51+
52+
#define NET_INFO_PRIORITY_OUTPUT TASK_PRIORITY_MEDIUM
53+
#define NET_INFO_PRIORITY_ERROR TASK_PRIORITY_MEDIUM
54+
55+
// these statics should go away for reentrancy and maybe other reasons!
56+
static int ping_callback_ref;
57+
static int ping_host_count;
58+
static ip_addr_t ping_host_ip;
59+
struct ping_option *ping_opt = NULL;
60+
61+
void ping_received(void *arg, void *data) {
62+
// this would require change of the interface
63+
// struct ping_msg *pingmsg = (struct ping_msg*)arg;
64+
// struct ping_option *pingopt = pingmsg->ping_opt;
65+
struct ping_option *pingopt = (struct ping_option*)arg;
66+
struct ping_msg *pingmsg = pingopt->parent_msg ;
67+
68+
struct ping_resp *pingresp = (struct ping_resp*)data;
69+
70+
char ipaddrstr[16];
71+
ip_addr_t source_ip;
72+
73+
source_ip.addr = pingopt->ip;
74+
ipaddr_ntoa_r(&source_ip, ipaddrstr, sizeof(ipaddrstr));
75+
76+
if (ping_callback_ref != LUA_NOREF) {
77+
lua_State *L = lua_getstate();
78+
lua_rawgeti(L, LUA_REGISTRYINDEX, ping_callback_ref);
79+
lua_pushinteger(L, pingresp->bytes);
80+
lua_pushstring(L, ipaddrstr);
81+
lua_pushinteger(L, pingresp->seqno);
82+
lua_pushinteger(L, pingresp->ttl);
83+
lua_pushinteger(L, pingresp->resp_time);
84+
lua_call(L, 5, 0);
85+
}
86+
}
87+
88+
static void ping_by_hostname(const char *name, ip_addr_t *ipaddr, void *arg) {
89+
if (!ping_opt) {
90+
ping_opt = (struct ping_option *)os_zalloc(sizeof(struct ping_option));
91+
} else {
92+
os_memset (ping_opt, 0, sizeof(struct ping_option));
93+
}
94+
95+
if (ipaddr == NULL) {
96+
lua_State *L = lua_getstate();
97+
luaL_error(L, "SEVERE problem resolving hostname - network and DNS accessible?\n");
98+
return;
99+
}
100+
if (ipaddr->addr == IPADDR_NONE) {
101+
lua_State *L = lua_getstate();
102+
luaL_error(L, "problem resolving hostname - maybe nonexistent host?\n");
103+
return;
104+
}
105+
106+
ping_opt->count = ping_host_count;
107+
ping_opt->ip = ipaddr->addr;
108+
ping_opt->coarse_time = 0;
109+
ping_opt->recv_function = &ping_received;
110+
111+
ping_start(ping_opt);
112+
}
113+
114+
115+
/**
116+
* test.ping()
117+
* Description:
118+
* Send ICMP ping request to address, optionally call callback when response received
119+
*
120+
* Syntax:
121+
* wifi.sta.getconfig(ssid, password) --Set STATION configuration, Auto-connect by default, Connects to any BSSID
122+
* test.ping(address) -- send 4 ping requests to target address
123+
* test.ping(address, n) -- send n ping requests to target address
124+
* test.ping(address, n, callback) -- send n ping requests to target address
125+
* Parameters:
126+
* address: string
127+
* n: number of requests to send
128+
* callback:
129+
* Returns:
130+
* Nothing.
131+
*
132+
* Example:
133+
* test.ping("192.168.0.1") -- send 4 pings to 192.168.0.1
134+
* test.ping("192.168.0.1", 10) -- send 10 pings to 192.168.0.1
135+
* test.ping("192.168.0.1", 10, got_ping) -- send 10 pings to 192.168.0.1, call got_ping() with the
136+
* -- ping results
137+
*/
138+
139+
static int net_info_ping(lua_State *L)
140+
{
141+
const char *ping_target;
142+
unsigned count = 4;
143+
144+
// retrieve address arg (mandatory)
145+
if (lua_isstring(L, 1)) {
146+
ping_target = luaL_checkstring(L, 1);
147+
} else {
148+
return luaL_error(L, "no address specified");
149+
}
150+
151+
// retrieve count arg (optional)
152+
if (lua_isnumber(L, 2)) {
153+
count = luaL_checkinteger(L, 2);
154+
}
155+
156+
// retrieve callback arg (optional)
157+
if (ping_callback_ref != LUA_NOREF)
158+
luaL_unref(L, LUA_REGISTRYINDEX, ping_callback_ref);
159+
ping_callback_ref = LUA_NOREF;
160+
161+
if (lua_type(L, 3) == LUA_TFUNCTION || lua_type(L, 3) == LUA_TLIGHTFUNCTION)
162+
ping_callback_ref = luaL_ref(L, LUA_REGISTRYINDEX);
163+
164+
// attempt to parse ping target as IP
165+
uint32 ip = ipaddr_addr(ping_target);
166+
167+
if (ip != IPADDR_NONE) {
168+
if (!ping_opt) {
169+
ping_opt = (struct ping_option *)os_zalloc(sizeof(struct ping_option));
170+
} else {
171+
os_memset (ping_opt, 0, sizeof(struct ping_option));
172+
}
173+
174+
175+
ping_opt->count = count;
176+
ping_opt->ip = ip;
177+
ping_opt->coarse_time = 0;
178+
ping_opt->recv_function = &ping_received;
179+
180+
ping_start(ping_opt);
181+
} else {
182+
ping_host_count = count;
183+
184+
struct espconn *ping_dns_lookup;
185+
espconn_create(ping_dns_lookup);
186+
espconn_gethostbyname(ping_dns_lookup, ping_target, &ping_host_ip, ping_by_hostname);
187+
}
188+
189+
return 0;
190+
}
191+
192+
// Module function map
193+
LROT_BEGIN(net_info)
194+
LROT_FUNCENTRY( ping, net_info_ping )
195+
LROT_END( net_ifo, NULL, 0 )
196+
197+
NODEMCU_MODULE(NET_INFO, "net_info", net_info, NULL);

docs/modules/net_info.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# net_info Module
2+
| Since | Origin / Contributor | Maintainer | Source |
3+
| :----- | :-------------------- | :---------- | :------ |
4+
| 2017-01-21 | [smcl](http://blog.mclemon.io/esp8266-contributing-to-the-nodemcu-ecosystem) | [wolfgangr](https://github.com/wolfgangr/nodemcu-firmware) | [net_info.c](../../../app/modules/net_info.c)
5+
6+
7+
This module is a stub to collect common network diagnostic and analysis tools.
8+
9+
##net_info.ping()
10+
send ICMP ECHO_REQUEST to network hosts
11+
12+
**Synopsis:**:
13+
```
14+
net_info.ping(host [, count [, callback]])
15+
```
16+
17+
**Usage example:**
18+
```
19+
=net_info.ping("www.google.de",2)
20+
> 32 bytes from 172.217.20.195, icmp_seq=25 ttl=53 time=37ms
21+
32 bytes from 172.217.20.195, icmp_seq=26 ttl=53 time=38ms
22+
ping 2, timeout 0, total payload 64 bytes, 1946 ms
23+
```
24+
25+
26+
**Description:** (from *linux man 8 ping*)
27+
28+
> `ping` uses the ICMP protocol's mandatory ECHO_REQUEST datagram to elicit an ICMP ECHO_RESPONSE from a host or gateway. ECHO_REQUEST datagrams (''pings'') have an IP and ICMP header, followed by a struct timeval and then an arbitrary number of ''pad'' bytes used to fill out the packet.
29+
30+
31+
**Usage variants**
32+
33+
ping host **by IP-Adress:**
34+
```
35+
net_info.ping("1.2.3.4")
36+
```
37+
Enter IP-Adress in commonly known dotted quad-decimal notation, enclosed in string quotes.
38+
39+
!!! Note
40+
There is only limited error checking on the validity of IP adresses in lwIP. Check twice!
41+
42+
43+
Use **DNS resolver** to get IP adress for ping:
44+
```
45+
net_info.ping("hostname")
46+
```
47+
48+
!!! Note
49+
This only works with Network access and DNS resolution properly configured.
50+
51+
52+
Custom **ping count**:
53+
```
54+
net_info.ping(host, count)
55+
```
56+
* `host` can be given by IP or hostname as above.
57+
* `count` number of repetitive pings - default is 4 if omitted.
58+
59+
60+
Ping **callback function**:
61+
```
62+
net_info.ping(host, count, callback)
63+
```
64+
Instead of printing ping results on the console, the given callback function ist called each time a ECHO_RESPONSE is received.
65+
66+
The callback receives the following arguments:
67+
```
68+
function ping_recv(bytes, ipaddr, seqno, ttl, ping)
69+
```
70+
* length of message
71+
* ip-address of pinged host
72+
* icmp_seq number
73+
* time-to-live-value
74+
* ping time in ms
75+
76+
!!! Caution
77+
The callback functionality is still untested. Use at even more your own risk!
78+
79+
For further reference to callback functionality, see smcl origin link provided on top of this page.

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ pages:
8383
- 'mdns': 'modules/mdns.md'
8484
- 'mqtt': 'modules/mqtt.md'
8585
- 'net': 'modules/net.md'
86+
- 'net_info': 'en/modules/net_info.md'
8687
- 'node': 'modules/node.md'
8788
- 'ow (1-Wire)': 'modules/ow.md'
8889
- 'pcm' : 'modules/pcm.md'

0 commit comments

Comments
 (0)