luat_lib_socket.c 16 KB

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