luat_lib_websocket.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. /*
  2. @module websocket
  3. @summary websocket客户端
  4. @version 1.0
  5. @date 2022.11.28
  6. @demo websocket
  7. @tag LUAT_USE_WEBSOCKET
  8. @usage
  9. local wsc = nil
  10. if websocket then
  11. wsc = websocket.create(nil, "ws://echo.airtun.air32.cn/ws/echo")
  12. wsc:autoreconn(true, 3000) -- 自动重连机制
  13. wsc:on(function(wsc, event, data)
  14. log.info("wsc", event, data)
  15. if event == "conack" then
  16. wsc:send((json.encode({action="echo", device_id=device_id})))
  17. sys.publish("wsc_conack")
  18. end
  19. end)
  20. wsc:connect()
  21. --sys.waitUntil("websocket_conack", 15000)
  22. while true do
  23. sys.wait(45000)
  24. if wsc:ready() then
  25. wsc:send((json.encode({action="echo", msg=os.date()})))
  26. end
  27. end
  28. wsc:close()
  29. wsc = nil
  30. end
  31. */
  32. #include "luat_base.h"
  33. #include "luat_network_adapter.h"
  34. #include "luat_rtos.h"
  35. #include "luat_zbuff.h"
  36. #include "luat_mem.h"
  37. #include "luat_websocket.h"
  38. #define LUAT_LOG_TAG "websocket"
  39. #include "luat_log.h"
  40. #define LUAT_WEBSOCKET_CTRL_TYPE "WS*"
  41. static luat_websocket_ctrl_t *get_websocket_ctrl(lua_State *L)
  42. {
  43. if (luaL_testudata(L, 1, LUAT_WEBSOCKET_CTRL_TYPE))
  44. {
  45. return ((luat_websocket_ctrl_t *)luaL_checkudata(L, 1, LUAT_WEBSOCKET_CTRL_TYPE));
  46. }
  47. else
  48. {
  49. return ((luat_websocket_ctrl_t *)lua_touserdata(L, 1));
  50. }
  51. }
  52. int l_websocket_callback(lua_State *L, void *ptr)
  53. {
  54. (void)ptr;
  55. rtos_msg_t *msg = (rtos_msg_t *)lua_topointer(L, -1);
  56. luat_websocket_ctrl_t *websocket_ctrl = (luat_websocket_ctrl_t *)msg->ptr;
  57. luat_websocket_pkg_t pkg = {0};
  58. // size_t payload_size = 0;
  59. switch (msg->arg1)
  60. {
  61. case WEBSOCKET_MSG_TIMER_PING:
  62. {
  63. luat_websocket_ping(websocket_ctrl);
  64. break;
  65. }
  66. case WEBSOCKET_MSG_RECONNECT:
  67. {
  68. luat_websocket_reconnect(websocket_ctrl);
  69. break;
  70. }
  71. case WEBSOCKET_MSG_PUBLISH:
  72. {
  73. char *raw = (char *)msg->arg2;
  74. luat_websocket_pkg_t pkg = {0};
  75. luat_websocket_payload(raw, &pkg, 64 * 1024);
  76. // 如果是起始帧(Text/Binary,FIN=0)
  77. if ((pkg.OPT_CODE == 0x01 || pkg.OPT_CODE == 0x02) && pkg.FIN == 0)
  78. {
  79. websocket_ctrl->is_fragmenting = 1; // 标记正在分片
  80. websocket_ctrl->frame_opt_code = pkg.OPT_CODE; // 记录起始帧类型
  81. if (websocket_ctrl->frame_buffer) {
  82. luat_heap_free(websocket_ctrl->frame_buffer);
  83. websocket_ctrl->frame_buffer = NULL;
  84. websocket_ctrl->frame_buffer_len = 0;
  85. }
  86. websocket_ctrl->frame_buffer = luat_heap_malloc(pkg.plen);
  87. if (!websocket_ctrl->frame_buffer) {
  88. LLOGE("out of memory for frame buffer");
  89. luat_heap_free(raw);
  90. break;
  91. }
  92. websocket_ctrl->frame_buffer_len = pkg.plen;
  93. memcpy(websocket_ctrl->frame_buffer, pkg.payload, pkg.plen);
  94. }
  95. // 如果是 continuation 帧
  96. else if (pkg.OPT_CODE == 0x00)
  97. {
  98. // 如果不在分片过程中,则忽略
  99. if (!websocket_ctrl->is_fragmenting)
  100. {
  101. LLOGW("unexpected continuation frame");
  102. luat_heap_free(raw);
  103. break;
  104. }
  105. size_t new_len = websocket_ctrl->frame_buffer_len + pkg.plen;
  106. char *new_buf = luat_heap_realloc(websocket_ctrl->frame_buffer, new_len);
  107. if (!new_buf) {
  108. LLOGE("realloc failed for continuation frame");
  109. luat_heap_free(raw);
  110. luat_heap_free(websocket_ctrl->frame_buffer); // 释放旧内存
  111. websocket_ctrl->frame_buffer = NULL;
  112. websocket_ctrl->frame_buffer_len = 0;
  113. websocket_ctrl->is_fragmenting = 0; // 重置状态
  114. break;
  115. }
  116. websocket_ctrl->frame_buffer = new_buf; // 更新指针
  117. memcpy(websocket_ctrl->frame_buffer + websocket_ctrl->frame_buffer_len,
  118. pkg.payload, pkg.plen);
  119. websocket_ctrl->frame_buffer_len = new_len;
  120. // 检查FIN标志,如果是最后一帧则上报
  121. if (pkg.FIN == 1) {
  122. // 上报完整数据
  123. if (websocket_ctrl->websocket_cb_id)
  124. {
  125. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_cb_id);
  126. if (lua_isfunction(L, -1))
  127. {
  128. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_ref);
  129. lua_pushstring(L, "recv");
  130. lua_pushlstring(L, websocket_ctrl->frame_buffer, websocket_ctrl->frame_buffer_len);
  131. lua_pushinteger(L, 1); // FIN=1
  132. lua_pushinteger(L, websocket_ctrl->frame_opt_code); // 使用记录的起始帧类型
  133. lua_call(L, 5, 0);
  134. }
  135. }
  136. // 清理分片缓存
  137. luat_heap_free(websocket_ctrl->frame_buffer);
  138. websocket_ctrl->frame_buffer = NULL;
  139. websocket_ctrl->frame_buffer_len = 0;
  140. websocket_ctrl->is_fragmenting = 0;
  141. }
  142. }
  143. // 如果是单帧完整或最后一帧
  144. else
  145. {
  146. // 如果是分片结束帧(FIN=1且正在分片)
  147. if (websocket_ctrl->is_fragmenting && pkg.FIN == 1)
  148. {
  149. // 拷贝合并分片数据
  150. size_t new_len = websocket_ctrl->frame_buffer_len + pkg.plen;
  151. char *final = luat_heap_malloc(new_len);
  152. if (final)
  153. {
  154. memcpy(final, websocket_ctrl->frame_buffer, websocket_ctrl->frame_buffer_len);
  155. memcpy(final + websocket_ctrl->frame_buffer_len, pkg.payload, pkg.plen);
  156. // 上报完整数据
  157. if (websocket_ctrl->websocket_cb_id)
  158. {
  159. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_cb_id);
  160. if (lua_isfunction(L, -1))
  161. {
  162. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_ref);
  163. lua_pushstring(L, "recv");
  164. lua_pushlstring(L, final, new_len);
  165. lua_pushinteger(L, pkg.FIN); // FIN=1
  166. lua_pushinteger(L, websocket_ctrl->frame_opt_code); // 起始帧类型
  167. lua_call(L, 5, 0);
  168. }
  169. }
  170. luat_heap_free(final);
  171. }
  172. // 清理分片缓存
  173. if (websocket_ctrl->frame_buffer) {
  174. luat_heap_free(websocket_ctrl->frame_buffer);
  175. websocket_ctrl->frame_buffer = NULL;
  176. }
  177. websocket_ctrl->frame_buffer_len = 0;
  178. websocket_ctrl->is_fragmenting = 0;
  179. }
  180. else
  181. {
  182. // 单帧完整,直接上报
  183. if (websocket_ctrl->websocket_cb_id)
  184. {
  185. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_cb_id);
  186. if (lua_isfunction(L, -1))
  187. {
  188. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_ref);
  189. lua_pushstring(L, "recv");
  190. lua_pushlstring(L, pkg.payload, pkg.plen);
  191. lua_pushinteger(L, pkg.FIN);
  192. lua_pushinteger(L, pkg.OPT_CODE);
  193. lua_call(L, 5, 0);
  194. }
  195. }
  196. }
  197. }
  198. luat_heap_free(raw);
  199. break;
  200. }
  201. case WEBSOCKET_MSG_CONNACK:
  202. {
  203. if (websocket_ctrl->websocket_cb_id)
  204. {
  205. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_cb_id);
  206. if (lua_isfunction(L, -1))
  207. {
  208. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_ref);
  209. lua_pushstring(L, "conack");
  210. lua_call(L, 2, 0);
  211. }
  212. lua_getglobal(L, "sys_pub");
  213. if (lua_isfunction(L, -1))
  214. {
  215. lua_pushstring(L, "WEBSOCKET_CONNACK");
  216. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_ref);
  217. lua_call(L, 2, 0);
  218. }
  219. }
  220. break;
  221. }
  222. case WEBSOCKET_MSG_RELEASE:
  223. {
  224. if (websocket_ctrl->websocket_ref)
  225. {
  226. luaL_unref(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_ref);
  227. websocket_ctrl->websocket_ref = 0;
  228. }
  229. break;
  230. }
  231. case WEBSOCKET_MSG_SENT :
  232. {
  233. if (websocket_ctrl->websocket_cb_id)
  234. {
  235. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_cb_id);
  236. if (lua_isfunction(L, -1))
  237. {
  238. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_ref);
  239. lua_pushstring(L, "sent");
  240. lua_call(L, 2, 0);
  241. }
  242. }
  243. break;
  244. }
  245. case WEBSOCKET_MSG_DISCONNECT :
  246. {
  247. if (websocket_ctrl->websocket_cb_id)
  248. {
  249. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_cb_id);
  250. if (lua_isfunction(L, -1))
  251. {
  252. lua_geti(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_ref);
  253. lua_pushstring(L, "disconnect");
  254. lua_call(L, 2, 0);
  255. }
  256. }
  257. break;
  258. }
  259. default:
  260. {
  261. LLOGD("l_websocket_callback error arg1:%d", msg->arg1);
  262. break;
  263. }
  264. }
  265. // lua_pushinteger(L, 0);
  266. return 0;
  267. }
  268. int l_luat_websocket_msg_cb(luat_websocket_ctrl_t *websocket_ctrl, int arg1, int arg2)
  269. {
  270. rtos_msg_t msg = {
  271. .handler = l_websocket_callback,
  272. .ptr = websocket_ctrl,
  273. .arg1 = arg1,
  274. .arg2 = arg2,
  275. };
  276. luat_msgbus_put(&msg, 0);
  277. return 0;
  278. }
  279. /*
  280. 配置是否打开debug信息
  281. @api wsc:debug(onoff)
  282. @boolean 是否打开debug开关
  283. @return nil 无返回值
  284. @usage wsc:debug(true)
  285. */
  286. static int l_websocket_set_debug(lua_State *L)
  287. {
  288. luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
  289. if (lua_isboolean(L, 2))
  290. {
  291. websocket_ctrl->netc->is_debug = lua_toboolean(L, 2);
  292. }
  293. return 0;
  294. }
  295. /*
  296. websocket客户端创建
  297. @api websocket.create(adapter, url, keepalive, use_ipv6)
  298. @int 适配器序号, 参考socket库的常量,默认为nil,会选择平台自带的方式
  299. @string 连接字符串,参考usage
  300. @int 心跳间隔,默认60秒. 2024.4.28新增
  301. @boolean 是否使用ipv6,默认false. 2024.6.17新增
  302. @return userdata 若成功会返回websocket客户端实例,否则返回nil
  303. @usage
  304. -- 普通TCP链接
  305. wsc = websocket.create(nil,"ws://air32.cn/abc")
  306. -- 加密TCP链接
  307. wsc = websocket.create(nil,"wss://air32.cn/abc")
  308. */
  309. static int l_websocket_create(lua_State *L)
  310. {
  311. int ret = 0;
  312. int adapter_index = luaL_optinteger(L, 1, network_get_last_register_adapter());
  313. if (adapter_index < 0 || adapter_index >= NW_ADAPTER_QTY)
  314. {
  315. return 0;
  316. }
  317. // 连接参数相关
  318. luat_websocket_connopts_t opts = {0};
  319. size_t ip_len = 0;
  320. opts.url = luaL_checklstring(L, 2, &ip_len);
  321. if (lua_isinteger(L, 3)) {
  322. opts.keepalive = luaL_checkinteger(L, 3);
  323. }
  324. if (lua_type(L, 4) == LUA_TBOOLEAN) {
  325. opts.use_ipv6 = lua_toboolean(L, 4);
  326. }
  327. luat_websocket_ctrl_t *websocket_ctrl = (luat_websocket_ctrl_t *)lua_newuserdata(L, sizeof(luat_websocket_ctrl_t));
  328. if (!websocket_ctrl)
  329. {
  330. LLOGE("out of memory when malloc websocket_ctrl");
  331. return 0;
  332. }
  333. ret = luat_websocket_init(websocket_ctrl, adapter_index);
  334. if (ret)
  335. {
  336. LLOGE("websocket init FAID ret %d", ret);
  337. return 0;
  338. }
  339. network_set_ip_invaild(&websocket_ctrl->ip_addr);
  340. ret = luat_websocket_set_connopts(websocket_ctrl, &opts);
  341. if (ret){
  342. luat_websocket_release_socket(websocket_ctrl);
  343. return 0;
  344. }
  345. // TODO 判断ret, 如果初始化失败, 应该终止
  346. luaL_setmetatable(L, LUAT_WEBSOCKET_CTRL_TYPE);
  347. lua_pushvalue(L, -1);
  348. websocket_ctrl->websocket_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  349. return 1;
  350. }
  351. /*
  352. 注册websocket回调
  353. @api wsc:on(cb)
  354. @function cb websocket回调,参数包括websocket_client, event, data, payload
  355. @return nil 无返回值
  356. @usage
  357. wsc:on(function(websocket_client, event, data, payload)
  358. -- 打印各种事件
  359. log.info("websocket", "event", event, data, payload)
  360. end)
  361. --[[
  362. event的值有:
  363. conack 连接服务器成功,已经收到websocket协议头部信息,通信已建立
  364. recv 收到服务器下发的信息, data, payload 不为nil
  365. sent send函数发送的消息,服务器在TCP协议层已确认收到
  366. disconnect 服务器连接已断开
  367. 其中 sent/disconnect 事件在 2023.04.01 新增
  368. ]]
  369. */
  370. static int l_websocket_on(lua_State *L)
  371. {
  372. luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
  373. if (websocket_ctrl->websocket_cb_id != 0)
  374. {
  375. luaL_unref(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_cb_id);
  376. websocket_ctrl->websocket_cb_id = 0;
  377. }
  378. if (lua_isfunction(L, 2))
  379. {
  380. lua_pushvalue(L, 2);
  381. websocket_ctrl->websocket_cb_id = luaL_ref(L, LUA_REGISTRYINDEX);
  382. }
  383. return 0;
  384. }
  385. /*
  386. 连接服务器
  387. @api wsc:connect()
  388. @return boolean 发起成功返回true, 否则返回false
  389. @usage
  390. -- 开始建立连接
  391. wsc:connect()
  392. -- 本函数仅代表发起成功, 后续仍需根据ready函数判断websocket是否连接正常
  393. */
  394. static int l_websocket_connect(lua_State *L)
  395. {
  396. luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
  397. int ret = luat_websocket_connect(websocket_ctrl);
  398. if (ret)
  399. {
  400. LLOGE("socket connect ret=%d\n", ret);
  401. luat_websocket_close_socket(websocket_ctrl);
  402. lua_pushboolean(L, 0);
  403. return 1;
  404. }
  405. lua_pushboolean(L, 1);
  406. return 1;
  407. }
  408. /*
  409. 自动重连
  410. @api wsc:autoreconn(reconnect, reconnect_time)
  411. @bool 是否自动重连
  412. @int 自动重连周期 单位ms 默认3000ms
  413. @usage
  414. wsc:autoreconn(true)
  415. */
  416. static int l_websocket_autoreconn(lua_State *L)
  417. {
  418. luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
  419. luat_websocket_autoreconn(websocket_ctrl, lua_toboolean(L, 2),luaL_optinteger(L, 3, 3000));
  420. return 0;
  421. }
  422. /*
  423. 发布消息
  424. @api wsc:send(data, fin, opt)
  425. @string 待发送的数据,必填
  426. @int 是否为最后一帧,默认1,即马上设置为最后一帧, 也就是单帧发送
  427. @int 操作码, 默认为字符串帧0, 可选1
  428. @return bool 成功返回true,否则为false或者nil
  429. @usage
  430. -- 简单发送数据
  431. wsc:send("123")
  432. -- 分段发送数据, 最后要用1(即FIN帧结束)
  433. wsc:send("123", 0)
  434. wsc:send("456", 0)
  435. wsc:send("789", 1)
  436. */
  437. static int l_websocket_send(lua_State *L)
  438. {
  439. size_t payload_len = 0;
  440. luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
  441. const char *payload = NULL;
  442. luat_zbuff_t *buff = NULL;
  443. int ret = 0;
  444. if (lua_isstring(L, 2))
  445. {
  446. payload = luaL_checklstring(L, 2, &payload_len);
  447. }
  448. else if (luaL_testudata(L, 2, LUAT_ZBUFF_TYPE))
  449. {
  450. buff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
  451. payload = (const char *)buff->addr;
  452. payload_len = buff->used;
  453. }
  454. else
  455. {
  456. LLOGD("only support string or zbuff");
  457. return 0;
  458. }
  459. luat_websocket_pkg_t pkg = {
  460. .FIN = 1,
  461. .OPT_CODE = 0x01,
  462. .plen = payload_len,
  463. .payload = payload};
  464. if (lua_isinteger(L, 3) && lua_tointeger(L, 3) == 1) {
  465. pkg.OPT_CODE = 0x02;
  466. }
  467. if (websocket_ctrl->websocket_state != 1) {
  468. LLOGI("not ready yet");
  469. lua_pushboolean(L, 0);
  470. return 1;
  471. }
  472. websocket_ctrl->frame_wait ++;
  473. ret = luat_websocket_send_frame(websocket_ctrl, &pkg);
  474. if (ret < 1) {
  475. websocket_ctrl->frame_wait --;// 发送失败
  476. }
  477. lua_pushboolean(L, ret == 0 ? 1 : 0);
  478. return 1;
  479. }
  480. /*
  481. websocket客户端关闭(关闭后资源释放无法再使用)
  482. @api wsc:close()
  483. @usage
  484. wsc:close()
  485. */
  486. static int l_websocket_close(lua_State *L)
  487. {
  488. luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
  489. // websocket_disconnect(&(websocket_ctrl->broker));
  490. luat_websocket_close_socket(websocket_ctrl);
  491. if (websocket_ctrl->websocket_cb_id != 0)
  492. {
  493. luaL_unref(L, LUA_REGISTRYINDEX, websocket_ctrl->websocket_cb_id);
  494. websocket_ctrl->websocket_cb_id = 0;
  495. }
  496. luat_websocket_release_socket(websocket_ctrl);
  497. return 0;
  498. }
  499. /*
  500. websocket客户端是否就绪
  501. @api wsc:ready()
  502. @return bool 客户端是否就绪
  503. @usage
  504. local stat = wsc:ready()
  505. */
  506. static int l_websocket_ready(lua_State *L)
  507. {
  508. luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
  509. lua_pushboolean(L, websocket_ctrl->websocket_state > 0 ? 1 : 0);
  510. return 1;
  511. }
  512. /*
  513. 设置额外的headers
  514. @api wsc:headers(headers)
  515. @table/string 可以是table,也可以是字符串
  516. @return bool 客户端是否就绪
  517. @usage
  518. -- table形式
  519. wsc:headers({
  520. Auth="Basic ABCDEFGG"
  521. })
  522. -- 字符串形式
  523. wsc:headers("Auth: Basic ABCDERG\r\n")
  524. */
  525. static int l_websocket_headers(lua_State *L)
  526. {
  527. luat_websocket_ctrl_t *websocket_ctrl = get_websocket_ctrl(L);
  528. if (!lua_istable(L, 2) && !lua_isstring(L, 2)) {
  529. return 0;
  530. }
  531. #define WS_HEADER_MAX (1024)
  532. char* buff = luat_heap_malloc(WS_HEADER_MAX);
  533. memset(buff, 0, WS_HEADER_MAX);
  534. if (lua_istable(L, 2)) {
  535. size_t name_sz = 0;
  536. size_t value_sz = 0;
  537. lua_pushnil(L);
  538. while (lua_next(L, 2) != 0) {
  539. const char *name = lua_tolstring(L, -2, &name_sz);
  540. const char *value = lua_tolstring(L, -1, &value_sz);
  541. if (name_sz == 0 || value_sz == 0 || name_sz + value_sz > 256) {
  542. LLOGW("bad header %s %s", name, value);
  543. luat_heap_free(buff);
  544. return 0;
  545. }
  546. memcpy(buff + strlen(buff), name, name_sz);
  547. memcpy(buff + strlen(buff), ":", 1);
  548. if (WS_HEADER_MAX - strlen(buff) < value_sz * 2) {
  549. LLOGW("bad header %s %s, too large", name, value);
  550. luat_heap_free(buff);
  551. return 0;
  552. }
  553. for (size_t i = 0; i < value_sz; i++)
  554. {
  555. switch (value[i])
  556. {
  557. case '*':
  558. case '-':
  559. case '.':
  560. case '_':
  561. case ' ':
  562. sprintf_(buff + strlen(buff), "%%%02X", value[i]);
  563. break;
  564. default:
  565. buff[strlen(buff)] = value[i];
  566. break;
  567. }
  568. }
  569. lua_pop(L, 1);
  570. memcpy(buff + strlen(buff), "\r\n", 2);
  571. }
  572. }
  573. else {
  574. size_t len = 0;
  575. const char* data = luaL_checklstring(L, 2, &len);
  576. if (len > 1023) {
  577. LLOGW("headers too large size %d", len);
  578. luat_heap_free(buff);
  579. return 0;
  580. }
  581. memcpy(buff, data, len);
  582. }
  583. luat_websocket_set_headers(websocket_ctrl, buff);
  584. lua_pushboolean(L, 1);
  585. return 1;
  586. }
  587. static int _websocket_struct_newindex(lua_State *L);
  588. void luat_websocket_struct_init(lua_State *L)
  589. {
  590. luaL_newmetatable(L, LUAT_WEBSOCKET_CTRL_TYPE);
  591. lua_pushcfunction(L, _websocket_struct_newindex);
  592. lua_setfield(L, -2, "__index");
  593. lua_pop(L, 1);
  594. }
  595. #include "rotable2.h"
  596. const rotable_Reg_t reg_websocket[] =
  597. {
  598. {"create", ROREG_FUNC(l_websocket_create)},
  599. {"on", ROREG_FUNC(l_websocket_on)},
  600. {"connect", ROREG_FUNC(l_websocket_connect)},
  601. {"autoreconn", ROREG_FUNC(l_websocket_autoreconn)},
  602. {"send", ROREG_FUNC(l_websocket_send)},
  603. {"close", ROREG_FUNC(l_websocket_close)},
  604. {"ready", ROREG_FUNC(l_websocket_ready)},
  605. {"headers", ROREG_FUNC(l_websocket_headers)},
  606. {"debug", ROREG_FUNC(l_websocket_set_debug)},
  607. {NULL, ROREG_INT(0)}
  608. };
  609. int _websocket_struct_newindex(lua_State *L)
  610. {
  611. const rotable_Reg_t *reg = reg_websocket;
  612. const char *key = luaL_checkstring(L, 2);
  613. while (1)
  614. {
  615. if (reg->name == NULL)
  616. return 0;
  617. if (!strcmp(reg->name, key))
  618. {
  619. lua_pushcfunction(L, reg->value.value.func);
  620. return 1;
  621. }
  622. reg++;
  623. }
  624. // return 0;
  625. }
  626. #ifndef LUAT_USE_NETWORK
  627. static const rotable_Reg_t reg_websocket_emtry[] = {
  628. {NULL, ROREG_INT(0)}
  629. };
  630. #endif
  631. LUAMOD_API int luaopen_websocket(lua_State *L)
  632. {
  633. #ifdef LUAT_USE_NETWORK
  634. luat_newlib2(L, reg_websocket);
  635. luat_websocket_struct_init(L);
  636. return 1;
  637. #else
  638. LLOGE("websocket require network enable!!");
  639. luat_newlib2(L, reg_websocket_emtry);
  640. return 1;
  641. #endif
  642. }