luat_lib_socket.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. /*
  2. @module socket
  3. @summary socket操作库
  4. @version 1.0
  5. @date 2020.03.30
  6. */
  7. #include "luat_base.h"
  8. #include "luat_timer.h"
  9. #include "luat_malloc.h"
  10. #include "luat_msgbus.h"
  11. #include "luat_socket.h"
  12. #define LUAT_LOG_TAG "socket"
  13. #include "luat_log.h"
  14. #define LUAT_NETC_HANDLE "NETC*"
  15. /*
  16. ntp时间同步
  17. @api socket.ntpSync(server)
  18. @string ntp服务器域名,默认值ntp1.aliyun.com
  19. @return int 启动成功返回0, 失败返回1或者2
  20. @usage
  21. socket.ntpSync()
  22. sys.subscribe("NTP_UPDATE", function(re)
  23. log.info("ntp", "result", re)
  24. end)
  25. */
  26. static int socket_ntp_sync(lua_State *L) {
  27. const char* hostname = luaL_optstring(L, 1, "ntp1.aliyun.com");
  28. int re = luat_socket_ntp_sync(hostname);
  29. lua_pushinteger(L, re);
  30. return 1;
  31. }
  32. /*
  33. 直接向地址发送一段数据
  34. @api socket.tsend(host, port, data)
  35. @string 服务器域名或者ip
  36. @int 服务器端口号
  37. @string 待发送的数据
  38. @return nil 无返回值
  39. @usage
  40. socket.tsend("www.baidu.com", 80, "GET / HTTP/1.0\r\n\r\n")
  41. */
  42. static int sal_tls_test(lua_State *L)
  43. {
  44. size_t len;
  45. const char* buff = luaL_checklstring(L, 3, &len);
  46. luat_socket_tsend(luaL_checkstring(L, 1), luaL_checkinteger(L, 2), (void*)buff, len);
  47. return 0;
  48. }
  49. /*
  50. 网络是否就绪
  51. @api socket.isReady()
  52. @return boolean 已联网返回true,否则返回false
  53. */
  54. static int l_socket_is_ready(lua_State *L) {
  55. lua_pushboolean(L, luat_socket_is_ready());
  56. return 1;
  57. }
  58. /*
  59. 获取自身ip,通常是内网ip
  60. @api socket.ip()
  61. @return string 已联网返回ip地址,否则返回nil
  62. */
  63. static int l_socket_selfip(lua_State *L) {
  64. uint32_t ip = luat_socket_selfip();
  65. if (ip == 0) {
  66. return 0;
  67. }
  68. lua_pushfstring(L, "%d.%d.%d.%d", (ip >> 0) & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
  69. return 1;
  70. }
  71. #include "netclient.h"
  72. static int luat_lib_netc_msg_handler(lua_State* L, void* ptr) {
  73. netc_ent_t* ent = (netc_ent_t*)ptr;
  74. if (ent->event == NETC_EVENT_END) {
  75. lua_getglobal(L, "sys_pub");
  76. if (lua_isfunction(L, -1)) {
  77. char buff[32] = {0};
  78. sprintf(buff, "NETC_END_%x", ent->netc_id);
  79. //LLOGD("FUCK [%s]", buff);
  80. lua_pushstring(L, buff);
  81. lua_call(L, 1, 0);
  82. }
  83. if (ent->lua_ref) {
  84. luaL_unref(L, ent->lua_ref, LUA_REGISTRYINDEX);
  85. }
  86. goto exit;
  87. }
  88. LLOGD("netc[%ld] event=%ld lua_ref=%ld", ent->netc_id, ent->event, ent->lua_ref);
  89. if (ent->lua_ref == 0) {
  90. goto exit;
  91. }
  92. if (lua_rawgeti(L, LUA_REGISTRYINDEX, ent->lua_ref) != LUA_TFUNCTION) {
  93. LLOGW("netc[%ld] callback isn't a function", ent->netc_id);
  94. goto exit;
  95. };
  96. lua_pushinteger(L, ent->netc_id);
  97. switch (ent->event)
  98. {
  99. case NETC_EVENT_CONNECT_OK:
  100. lua_pushinteger(L, 1);
  101. lua_call(L, 2, 0);
  102. break;
  103. case NETC_EVENT_CONNECT_FAIL:
  104. lua_pushinteger(L, 0);
  105. lua_call(L, 2, 0);
  106. break;
  107. //case NETC_EVENT_CLOSE:
  108. // lua_call(L, 1, 0);
  109. // break;
  110. case NETC_EVENT_RECV:
  111. lua_pushlstring(L, ent->buff, ent->len);
  112. //lua_pushliteral(L, "");
  113. lua_call(L, 2, 0);
  114. break;
  115. case NETC_EVENT_ERROR:
  116. lua_call(L, 1, 0);
  117. break;
  118. default:
  119. break;
  120. }
  121. exit:
  122. if (ent->buff) {
  123. luat_heap_free((void*)ent->buff);
  124. }
  125. luat_heap_free((void*)ent);
  126. return 0;
  127. }
  128. static int luat_lib_socket_new(lua_State* L, int netc_type);
  129. static int luat_lib_socket_ent_handler(netc_ent_t* ent) {
  130. if (ent->event != NETC_EVENT_END && ent->lua_ref == 0) {
  131. if (ent->buff) {
  132. luat_heap_free((void*)ent->buff);
  133. }
  134. luat_heap_free((void*)ent);
  135. return 0;
  136. }
  137. rtos_msg_t msg;
  138. msg.handler = luat_lib_netc_msg_handler;
  139. msg.ptr = ent;
  140. luat_msgbus_put(&msg, 1);
  141. return 0;
  142. }
  143. //----------------------------------------------------------------
  144. /*
  145. 新建一个tcp socket
  146. @api socket.tcp()
  147. @return object socket对象,如果创建失败会返回nil
  148. @usage
  149. -- 如果读取失败,会返回nil
  150. local so = socket.tcp()
  151. if so then
  152. so:host("www.baidu.com")
  153. so:port(80)
  154. so:on("connect", function(id, re)
  155. if re == 1 then
  156. so:send("GET / HTTP/1.0\r\n\r\n")
  157. end
  158. end)
  159. so:on("recv", function(id, data)
  160. log.info("netc", id, data)
  161. end)
  162. if so:start() == 1 then
  163. sys.waitUntil("NETC_END_" .. so:id())
  164. end
  165. so:close()
  166. so:clean()
  167. end
  168. */
  169. static int luat_lib_socket_tcp(lua_State* L) {
  170. return luat_lib_socket_new(L, NETC_TYPE_TCP);
  171. }
  172. /*
  173. 新建一个udp socket
  174. @api socket.udp()
  175. @return nil 暂不支持
  176. */
  177. static int luat_lib_socket_udp(lua_State* L) {
  178. return luat_lib_socket_new(L, NETC_TYPE_UDP);
  179. }
  180. //-----------------------------------------------------------------
  181. static int luat_lib_socket_new(lua_State* L, int netc_type) {
  182. netclient_t* thiz;
  183. //size_t len;
  184. // 强制GC一次
  185. //LOG_D("force execute FULL GC");
  186. //lua_gc(L, LUA_GCCOLLECT, 0);
  187. // 生成netc结构体
  188. //LOG_D("init netclient ...");
  189. thiz = (netclient_t*)lua_newuserdata(L, sizeof(netclient_t));
  190. if (thiz == NULL)
  191. {
  192. //LOG_W("netclient, fail to create!!!!memory full?!");
  193. return 0;
  194. }
  195. memset(thiz, 0, sizeof(netclient_t));
  196. thiz->sock_fd = -1;
  197. thiz->pipe_read_fd = -1;
  198. thiz->pipe_write_fd = -1;
  199. thiz->rx = luat_lib_socket_ent_handler;
  200. thiz->type = netc_type;
  201. //rt_memset(thiz->hostname, 0, sizeof(thiz->hostname));
  202. thiz->hostname[0] = '_';
  203. thiz->id = netc_next_no();
  204. sprintf(thiz->idStr, "%x", thiz->id);
  205. luaL_setmetatable(L, LUAT_NETC_HANDLE);
  206. //LLOGI("netc[%ld] create successd", thiz->id);
  207. return 1;
  208. }
  209. //---------------------------------------------
  210. #define tonetc(L) ((netclient_t *)luaL_checkudata(L, 1, LUAT_NETC_HANDLE))
  211. /*
  212. 启动socket线程
  213. @api so:start(host, port)
  214. @string 服务器域名或ip,如果已经使用so:host和so:port配置,就不需要传参数了
  215. @port 服务器端口,如果已经使用so:host和so:port配置,就不需要传参数了
  216. @return int 成功返回0,失败返回1
  217. @usage
  218. -- 参考socket.tcp的说明, 并查阅demo
  219. */
  220. static int netc_connect(lua_State *L) {
  221. netclient_t* thiz;
  222. size_t len;
  223. //uint32_t port;
  224. int re;
  225. thiz = tonetc(L);
  226. if (lua_gettop(L) < 2) {
  227. if (thiz->hostname[1] != 0x00 && thiz->port > 0) {
  228. // ok
  229. }
  230. else {
  231. //LLOGW("sock:connect require 2 args! top=%d", lua_gettop(L));
  232. lua_pushinteger(L, 2);
  233. return 1;
  234. }
  235. }
  236. else {
  237. const char* hostname = luaL_checklstring(L, 2, &len);
  238. if (len >= 32) {
  239. //LLOGE("netc[%ld] hostname is too long >= 32", thiz->id);
  240. lua_pushinteger(L, 1);
  241. return 1;
  242. }
  243. memcpy(thiz->hostname, hostname, len);
  244. thiz->hostname[len] = 0x00;
  245. thiz->port = luaL_optinteger(L, 3, 80);
  246. }
  247. thiz->rx = luat_lib_socket_ent_handler;
  248. //LLOGI("netc[%ld] host=%s port=%d type=%s", thiz->id, thiz->hostname, thiz->port, thiz->type == NETC_TYPE_TCP ? "TCP" : "UDP");
  249. re = netclient_start(thiz);
  250. if (re == 0) {
  251. lua_settop(L, 1);
  252. thiz->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  253. }
  254. lua_pushinteger(L, re);
  255. return 1;
  256. }
  257. /*
  258. 关闭socket对象
  259. @api so:close()
  260. @return nil 总会成功
  261. @usage
  262. -- 参考socket.tcp的说明, 并查阅demo
  263. */
  264. static int netc_close(lua_State *L) {
  265. netclient_t *netc = tonetc(L);
  266. if (netc->closed == 0) {
  267. netclient_close(netc);
  268. }
  269. return 0;
  270. }
  271. /*
  272. 通过socket对象发送数据
  273. @api so:send(data,flags)
  274. @string 待发送数据
  275. @int 可选的额外参数,底层相关.例如NBIOT下的rai值, 传入2,代表数据已经全部发送完成,可更快进入休眠.
  276. @return boolean 发送成功返回true,否则返回false
  277. @usage
  278. -- 参考socket.tcp的说明, 并查阅demo
  279. */
  280. static int netc_send(lua_State *L) {
  281. size_t len = 0;
  282. netclient_t *netc;
  283. netc = tonetc(L);
  284. const char* data = luaL_checklstring(L, 2, &len);
  285. int flags = luaL_optinteger(L, 3, 0);
  286. if (len > 0) {
  287. int32_t re = netclient_send(netc, (void*)data, len, flags);
  288. lua_pushboolean(L, re == len ? 1 : 0);
  289. }
  290. else {
  291. lua_pushboolean(L, 0);
  292. }
  293. return 1;
  294. }
  295. static int netc_gc(lua_State *L) {
  296. netclient_t *netc = tonetc(L);
  297. LLOGI("netc[%ld] __gc trigger", netc->id);
  298. netclient_close(netc);
  299. if (netc->cb_error) {
  300. luaL_unref(L, LUA_REGISTRYINDEX, netc->cb_error);
  301. }
  302. if (netc->cb_recv) {
  303. luaL_unref(L, LUA_REGISTRYINDEX, netc->cb_recv);
  304. }
  305. // if (netc->cb_close) {
  306. // luaL_unref(L, LUA_REGISTRYINDEX, netc->cb_close);
  307. // }
  308. if (netc->cb_connect) {
  309. luaL_unref(L, LUA_REGISTRYINDEX, netc->cb_connect);
  310. }
  311. return 0;
  312. }
  313. static int netc_tostring(lua_State *L) {
  314. netclient_t *netc = tonetc(L);
  315. lua_pushfstring(L, "netc[%d] %s,%d,%s %s", netc->id,
  316. netc->hostname, netc->port,
  317. netc->type == NETC_TYPE_TCP ? "TCP" : "UDP",
  318. netc->closed ? "Closed" : "Not-Closed");
  319. return 1;
  320. }
  321. /*
  322. 获取socket对象的id
  323. @api so:id()
  324. @return string 对象id,全局唯一
  325. -- 参考socket.tcp的说明, 并查阅demo
  326. */
  327. static int netc_id(lua_State *L) {
  328. netclient_t *netc = tonetc(L);
  329. lua_pushstring(L, netc->idStr);
  330. return 1;
  331. }
  332. /*
  333. 设置服务器域名或ip
  334. @api so:host(host)
  335. @string 服务器域名或ip
  336. @return nil 无返回值
  337. @usage
  338. -- 参考socket.tcp的说明, 并查阅demo
  339. */
  340. static int netc_host(lua_State *L) {
  341. netclient_t *netc = tonetc(L);
  342. if (lua_gettop(L) > 1 && lua_isstring(L, 2)) {
  343. size_t len = 0;
  344. const char* hostname = luaL_checklstring(L, 2, &len);
  345. if (len >= 64) {
  346. LLOGE("hostname is too long!!!!!");
  347. lua_pushinteger(L, 1);
  348. return 1;
  349. }
  350. else if (len == 0) {
  351. LLOGE("hostname is emtry!!!!!");
  352. lua_pushinteger(L, 1);
  353. return 1;
  354. }
  355. memcpy(netc->hostname, hostname, len);
  356. netc->hostname[len] = 0x00;
  357. }
  358. lua_pushstring(L, netc->hostname);
  359. return 1;
  360. }
  361. /*
  362. 设置服务器端口
  363. @api so:port(port)
  364. @int 服务器端口
  365. @return nil 无返回值
  366. @usage
  367. -- 参考socket.tcp的说明, 并查阅demo
  368. */
  369. static int netc_port(lua_State *L) {
  370. netclient_t *netc = tonetc(L);
  371. if (lua_gettop(L) > 1 && lua_isinteger(L, 2)) {
  372. netc->port = lua_tointeger(L, 2);
  373. //LLOGI("netc[%ld] port=%d", netc->id, netc->port);
  374. }
  375. lua_pushinteger(L, netc->port);
  376. return 1;
  377. }
  378. /*
  379. 清理socket关联的资源,socket对象在废弃前必须调用
  380. @api so:clean(0)
  381. @return nil 无返回值
  382. @usage
  383. -- 参考socket.tcp的说明, 并查阅demo
  384. */
  385. static int netc_clean(lua_State *L) {
  386. netclient_t *netc = tonetc(L);
  387. if (!netc->closed) {
  388. netc_close(L);
  389. }
  390. if (netc->cb_error) {
  391. //LOG_D("netc[%ld] unref 0x%08X", netc->id, netc->cb_error);
  392. luaL_unref(L, LUA_REGISTRYINDEX, netc->cb_error);
  393. netc->cb_error = 0;
  394. }
  395. if (netc->cb_recv) {
  396. //LOG_D("netc[%ld] unref 0x%08X", netc->id, netc->cb_recv);
  397. luaL_unref(L, LUA_REGISTRYINDEX, netc->cb_recv);
  398. netc->cb_recv = 0;
  399. }
  400. // if (netc->cb_close) {
  401. // //LOG_D("netc[%ld] unref 0x%08X", netc->id, netc->cb_close);
  402. // luaL_unref(L, LUA_REGISTRYINDEX, netc->cb_close);
  403. // netc->cb_close = 0;
  404. // }
  405. if (netc->cb_connect) {
  406. //LOG_D("netc[%ld] unref 0x%08X", netc->id, netc->cb_connect);
  407. luaL_unref(L, LUA_REGISTRYINDEX, netc->cb_connect);
  408. netc->cb_connect = 0;
  409. }
  410. return 0;
  411. }
  412. /*
  413. 设置socket的事件回调
  414. @api so:on(event, func)
  415. @string 事件名称
  416. @function 回调方法
  417. @return nil 无返回值
  418. @usage
  419. -- 参考socket.tcp的说明, 并查阅demo
  420. */
  421. static int netc_on(lua_State *L) {
  422. netclient_t *netc = tonetc(L);
  423. if (lua_gettop(L) < 3) {
  424. return 0;
  425. }
  426. if (lua_isstring(L, 2)) {
  427. if (lua_isfunction(L, 3)) {
  428. const char* ent = lua_tostring(L, 2);
  429. lua_pushvalue(L, 3);
  430. if (strcmp("recv", ent) == 0) {
  431. netc->cb_recv = luaL_ref(L, LUA_REGISTRYINDEX);
  432. }
  433. // else if (strcmp("close", ent) == 0) {
  434. // netc->cb_close = luaL_ref(L, LUA_REGISTRYINDEX);
  435. // }
  436. else if (strcmp("connect", ent) == 0) {
  437. netc->cb_connect = luaL_ref(L, LUA_REGISTRYINDEX);
  438. }
  439. //else if (strcmp("any", ent) == 0) {
  440. // netc->cb_any = luaL_ref(L, LUA_REGISTRYINDEX);
  441. //}
  442. else if (strcmp("error", ent) == 0) {
  443. netc->cb_error = luaL_ref(L, LUA_REGISTRYINDEX);
  444. }
  445. else {
  446. //LLOGI("netc[%ld] unkown event type=%s", netc->id, ent);
  447. }
  448. }
  449. }
  450. return 0;
  451. }
  452. /*
  453. socket是否已经断开?
  454. @api so:closed()
  455. @return int 未断开0,已断开1
  456. @return bool 未断开返回false,已断开返回true, V0003新增
  457. @usage
  458. -- 参考socket.tcp的说明, 并查阅demo
  459. */
  460. static int netc_closed(lua_State *L) {
  461. netclient_t *netc = tonetc(L);
  462. lua_pushinteger(L, netc->closed);
  463. lua_pushboolean(L, netc->closed == 0 ? 1 : 0);
  464. return 2;
  465. }
  466. /*
  467. 为netclient绑定socket id, 该操作仅在NBIOT模块下有意义.
  468. @api so:rebind(socket_id)
  469. @int socket的id.
  470. @return bool 成功返回true, 否则返回false. V0003新增
  471. @usage
  472. -- 参考socket.tcp的说明, 并查阅demo
  473. */
  474. static int netc_rebind(lua_State *L) {
  475. netclient_t *netc = tonetc(L);
  476. netc->closed = 0;
  477. netc->sock_fd = luaL_checkinteger(L, 2);
  478. int ret = netclient_rebind(netc);
  479. lua_pushboolean(L, ret == 0 ? 1 : 0);
  480. return 1;
  481. }
  482. /*
  483. 获取底层socket id
  484. @api so:sockid()
  485. @return int 底层socket id
  486. @usage
  487. -- 参考socket.tcp的说明, 并查阅demo
  488. */
  489. static int netc_sockid(lua_State *L) {
  490. netclient_t *netc = tonetc(L);
  491. lua_pushinteger(L, netc->sock_fd);
  492. return 1;
  493. }
  494. static const luaL_Reg lib_netc[] = {
  495. {"id", netc_id},
  496. {"host", netc_host},
  497. {"port", netc_port},
  498. {"connect", netc_connect},
  499. {"start", netc_connect},
  500. {"close", netc_close},
  501. {"closed", netc_closed},
  502. {"send", netc_send},
  503. {"clean", netc_clean},
  504. {"on", netc_on},
  505. {"rebind", netc_rebind},
  506. {"sockid", netc_sockid},
  507. {"__gc", netc_gc},
  508. {"__tostring", netc_tostring},
  509. {NULL, NULL}
  510. };
  511. static int luat_socket_meta_index(lua_State *L) {
  512. if (lua_isstring(L, 2)) {
  513. const char* keyname = luaL_checkstring(L, 2);
  514. //printf("zbuff keyname = %s\n", keyname);
  515. int i = 0;
  516. while (1) {
  517. if (lib_netc[i].name == NULL) break;
  518. if (!strcmp(keyname, lib_netc[i].name)) {
  519. lua_pushcfunction(L, lib_netc[i].func);
  520. return 1;
  521. }
  522. i++;
  523. }
  524. }
  525. return 0;
  526. }
  527. static void createmeta (lua_State *L) {
  528. luaL_newmetatable(L, LUAT_NETC_HANDLE); /* create metatable for file handles */
  529. //lua_pushvalue(L, -1); /* push metatable */
  530. lua_pushcfunction(L, luat_socket_meta_index);
  531. lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
  532. //luaL_setfuncs(L, lib_netc, 0); /* add file methods to new metatable */
  533. lua_pop(L, 1); /* pop new metatable */
  534. }
  535. #include "rotable.h"
  536. static const rotable_Reg reg_socket[] =
  537. {
  538. { "tcp", luat_lib_socket_tcp, 0},
  539. { "udp", luat_lib_socket_udp, 0},
  540. { "tsend" , sal_tls_test , 0},
  541. { "ntpSync", socket_ntp_sync, 0}, // TODO 改成平台无关的UDP实现?
  542. { "isReady", l_socket_is_ready, 0},
  543. { "ip", l_socket_selfip, 0},
  544. { NULL, NULL , 0}
  545. };
  546. LUAMOD_API int luaopen_socket( lua_State *L ) {
  547. luat_newlib(L, reg_socket);
  548. createmeta(L);
  549. return 1;
  550. }