luat_lib_socket.c 15 KB

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