net_ping.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // ***************************************************************************
  2. // net_ping functionnality for ESP8266 with nodeMCU
  3. //
  4. // Written by Lukas Voborsky (@voborsky) with great help by TerryE
  5. // ***************************************************************************
  6. // #define NODE_DEBUG
  7. #include "net_ping.h"
  8. #include "module.h"
  9. #include "lauxlib.h"
  10. #include "lwip/ip_addr.h"
  11. #include "espconn.h"
  12. #include "lwip/dns.h"
  13. #include "lwip/app/ping.h"
  14. /*
  15. ping_opt needs to be the first element of the structure. It is a workaround to pass the
  16. callback reference and self_ref to the ping_received function. Pointer the ping_option
  17. structure is equal to the pointer to net_ping_t structure.
  18. */
  19. typedef struct {
  20. struct ping_option ping_opt;
  21. uint32_t ping_callback_ref;
  22. } net_ping_t;
  23. typedef net_ping_t* ping_t;
  24. /*
  25. * ping_received_sent(pingresp)
  26. */
  27. #define LuaCBreceivedfunc lua_upvalueindex(1)
  28. #define LuaCBsentfunc lua_upvalueindex(2)
  29. #define nipUD lua_upvalueindex(3)
  30. static int ping_received_sent(lua_State *L) {
  31. struct ping_resp *resp = (struct ping_resp *) lua_touserdata (L, 1);
  32. ping_t nip = (ping_t) lua_touserdata (L, nipUD);
  33. NODE_DBG("[net_info ping_received_sent] nip = %p\n", nip);
  34. if (resp == NULL) { /* resolution failed so call the CB with 0 byte count to flag this */
  35. luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref);
  36. lua_pushvalue(L, LuaCBreceivedfunc);
  37. lua_pushinteger(L, 0);
  38. luaL_pcallx(L, 1, 0);
  39. return 0;
  40. }
  41. char ipaddrstr[16];
  42. ipaddr_ntoa_r((ip_addr_t *) &nip->ping_opt.ip, ipaddrstr, sizeof(ipaddrstr));
  43. if (resp->total_count == 0) { /* processing receive response */
  44. NODE_DBG("[ping_received] %s: resp_time=%d seqno=%d bytes=%d ping_err=%d\n",
  45. ipaddrstr, resp->resp_time, resp->seqno, resp->bytes, resp->ping_err);
  46. lua_pushvalue(L, LuaCBreceivedfunc);
  47. lua_pushinteger(L, resp->bytes);
  48. lua_pushstring(L, ipaddrstr);
  49. lua_pushinteger(L, resp->seqno);
  50. lua_pushinteger(L, resp->ping_err == 0 ? resp->resp_time: -1);
  51. luaL_pcallx(L, 4, 0);
  52. } else { /* processing sent response */
  53. NODE_DBG("[ping_sent] %s: total_count=%d timeout_count=%d "
  54. "total_bytes=%d total_time=%d\n",
  55. ipaddrstr, resp->total_count, resp->timeout_count,
  56. resp->total_bytes, resp->total_time);
  57. lua_pushvalue(L, LuaCBsentfunc);
  58. if lua_isfunction(L, -1) {
  59. lua_pushstring(L, ipaddrstr);
  60. lua_pushinteger(L, resp->total_count);
  61. lua_pushinteger(L, resp->timeout_count);
  62. lua_pushinteger(L, resp->total_bytes);
  63. lua_pushinteger(L, resp->total_time);
  64. luaL_pcallx(L, 5, 0);
  65. }
  66. luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref); /* unregister the closure */
  67. }
  68. return 0;
  69. }
  70. /*
  71. * Wrapper to call ping_received_sent(pingresp)
  72. */
  73. static void ping_CB(net_ping_t *nip, struct ping_resp *pingresp) {
  74. NODE_DBG("[net_info ping_CB] nip = %p, nip->ping_callback_ref = %p, pingresp= %p\n", nip, nip->ping_callback_ref, pingresp);
  75. lua_State *L = lua_getstate();
  76. lua_rawgeti(L, LUA_REGISTRYINDEX, nip->ping_callback_ref);
  77. lua_pushlightuserdata(L, pingresp);
  78. lua_call(L, 1, 0); // call the closure (ping_received_sent)
  79. }
  80. /*
  81. * Wrapper to call ping_start using fully resolve IP4 address
  82. */
  83. static void net_ping_raw(const char *name, ip_addr_t *ipaddr, ping_t nip) {
  84. NODE_DBG("[net_ping_raw] name = %s, ipaddr= %x\n", name, ipaddr);
  85. if (ipaddr) {
  86. char ipaddrstr[16];
  87. ipaddr_ntoa_r(ipaddr, ipaddrstr, sizeof(ipaddrstr));
  88. NODE_DBG("[net_ping_raw] ip: %s\n", ipaddrstr);
  89. }
  90. lua_State *L = lua_getstate();
  91. if (!ipaddr || ipaddr->addr == 0xFFFFFFFF) {
  92. ping_CB(nip, NULL); /* A NULL pinresp flags DNS resolution failure */
  93. return;
  94. }
  95. nip->ping_opt.ip = ipaddr->addr;
  96. NODE_DBG("[net_ping_raw] calling ping_start\n");
  97. if (!ping_start(&(nip->ping_opt))) {
  98. luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref);
  99. luaL_error(L, "memory allocation error: cannot start ping");
  100. }
  101. }
  102. // Lua: net.ping(domain, [count], callback)
  103. int net_ping(lua_State *L)
  104. {
  105. ip_addr_t addr;
  106. // retrieve function parameters
  107. const char *ping_target = luaL_checkstring(L, 1);
  108. bool isf2 = lua_isfunction(L, 2);
  109. lua_Integer l_count = isf2 ? 0: luaL_optinteger(L, 2, 0); /* use ping_start() default */
  110. lua_settop(L, isf2 ? 3 : 4);
  111. luaL_argcheck(L, lua_isfunction(L, -2), -2, "no received callback specified");
  112. luaL_argcheck(L, lua_isfunction(L, -1) || lua_isnil(L, -1), -1, "invalid sent callback, function expected");
  113. ping_t nip = (ping_t) memset(lua_newuserdata(L, sizeof(*nip)), 0, sizeof(*nip));
  114. /* Register C closure with 3 Upvals: (1) Lua CB receive function; (2) Lua CB sent function; (3) nip Userdata */
  115. lua_pushcclosure(L, ping_received_sent, 3); // stack has 2 callbacks and nip UD; [-3, +1, m]
  116. nip->ping_callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); // registers the closure to registry [-1, +0, m]
  117. nip->ping_opt.count = l_count;
  118. nip->ping_opt.coarse_time = 0;
  119. nip->ping_opt.recv_function = (ping_recv_function) &ping_CB;
  120. nip->ping_opt.sent_function = (ping_sent_function) &ping_CB;
  121. NODE_DBG("[net_ping] nip = %p, nip->ping_callback_ref = %p\n", nip, nip->ping_callback_ref);
  122. err_t err = dns_gethostbyname(ping_target, &addr, (dns_found_callback) net_ping_raw, nip);
  123. if (err != ERR_OK && err != ERR_INPROGRESS) {
  124. luaL_unref(L, LUA_REGISTRYINDEX, nip->ping_callback_ref);
  125. return luaL_error(L, "lwip error %d", err);
  126. }
  127. if (err == ERR_OK) {
  128. NODE_DBG("[net_ping] No DNS resolution needed\n");
  129. net_ping_raw(ping_target, &addr, nip);
  130. }
  131. return 0;
  132. }