luat_lib_libcoap.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. /*
  2. @module libcoap
  3. @summary coap数据处理
  4. @version 1.0
  5. @date 2020.06.30
  6. @demo libcoap
  7. @tag LUAT_USE_COAP
  8. */
  9. #include "luat_base.h"
  10. #include "luat_timer.h"
  11. #include "luat_malloc.h"
  12. #include "luat_msgbus.h"
  13. #define LUAT_LOG_TAG "libcoap"
  14. #include "luat_log.h"
  15. //---------------------------
  16. #ifndef COAP_OPTION_IF_MATCH
  17. #define COAP_OPTION_IF_MATCH 1 /* C, opaque, 0-8 B, (none) */
  18. #define COAP_OPTION_URI_HOST 3 /* C, String, 1-255 B, destination address */
  19. #define COAP_OPTION_ETAG 4 /* E, opaque, 1-8 B, (none) */
  20. #define COAP_OPTION_IF_NONE_MATCH 5 /* empty, 0 B, (none) */
  21. #define COAP_OPTION_URI_PORT 7 /* C, uint, 0-2 B, destination port */
  22. #define COAP_OPTION_LOCATION_PATH 8 /* E, String, 0-255 B, - */
  23. #define COAP_OPTION_URI_PATH 11 /* C, String, 0-255 B, (none) */
  24. #define COAP_OPTION_CONTENT_FORMAT 12 /* E, uint, 0-2 B, (none) */
  25. #define COAP_OPTION_CONTENT_TYPE COAP_OPTION_CONTENT_FORMAT
  26. #define COAP_OPTION_MAXAGE 14 /* E, uint, 0--4 B, 60 Seconds */
  27. #define COAP_OPTION_URI_QUERY 15 /* C, String, 1-255 B, (none) */
  28. #define COAP_OPTION_ACCEPT 17 /* C, uint, 0-2 B, (none) */
  29. #define COAP_OPTION_LOCATION_QUERY 20 /* E, String, 0-255 B, (none) */
  30. #define COAP_OPTION_SIZE2 28 /* E, uint, 0-4 B, (none) */
  31. #define COAP_OPTION_PROXY_URI 35 /* C, String, 1-1034 B, (none) */
  32. #define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */
  33. #define COAP_OPTION_SIZE1 60 /* E, uint, 0-4 B, (none) */
  34. #define COAP_MEDIATYPE_TEXT_PLAIN 0 /* text/plain (UTF-8) */
  35. #define COAP_MEDIATYPE_APPLICATION_LINK_FORMAT 40 /* application/link-format */
  36. #define COAP_MEDIATYPE_APPLICATION_XML 41 /* application/xml */
  37. #define COAP_MEDIATYPE_APPLICATION_OCTET_STREAM 42 /* application/octet-stream */
  38. #define COAP_MEDIATYPE_APPLICATION_RDF_XML 43 /* application/rdf+xml */
  39. #define COAP_MEDIATYPE_APPLICATION_EXI 47 /* application/exi */
  40. #define COAP_MEDIATYPE_APPLICATION_JSON 50 /* application/json */
  41. #define COAP_MEDIATYPE_APPLICATION_CBOR 60 /* application/cbor */
  42. #endif
  43. //---------------------------
  44. typedef struct libcoap_header
  45. {
  46. unsigned int tokenLen: 4 ;
  47. unsigned int type : 2 ; // 0 - CON, 1 - NON, 2 - ACK, 3 - RST
  48. unsigned int version : 2 ;
  49. uint8_t code;
  50. uint16_t msgid;
  51. }libcoap_header_t;
  52. typedef struct libcoap_opt_header
  53. {
  54. unsigned int opt_len : 4 ;
  55. unsigned int opt_delta : 4 ;
  56. }libcoap_opt_header_t;
  57. typedef struct luat_lib_libcoap
  58. {
  59. libcoap_header_t header;
  60. char token[9];
  61. size_t optSize;
  62. size_t dataSize;
  63. char opt[256];
  64. char data[512 - 128];
  65. }luat_lib_libcoap_t;
  66. static uint16_t c_msgid = 1;
  67. #define LUAT_COAP_HANDLE "COAP*"
  68. //-----------------------------------------------------------------
  69. static void addopt(luat_lib_libcoap_t* _coap, uint8_t opt_type, const char* value, size_t len) {
  70. if (_coap->optSize > 0) { // 检查需要之前的opt
  71. }
  72. int cur_opt = opt_type;
  73. // LLOGD("opt type=%d value len=%d", opt_type, len);
  74. // LLOGD("opt optSize cur=%d", _coap->optSize);
  75. size_t idx = _coap->optSize;
  76. if (len <= 12) {
  77. _coap->opt[idx++] = (cur_opt << 4) + (len & 0xF);
  78. }
  79. else if (len <= 268) {
  80. _coap->opt[idx++] = (cur_opt << 4) + (0x0D);
  81. _coap->opt[idx++] = len - 0x0D;
  82. } else {
  83. LLOGW("coap opt is too large!!! ignore!!!");
  84. return;
  85. }
  86. for (size_t i = 0; i < len; i++)
  87. {
  88. _coap->opt[idx++] = *(value + i);
  89. }
  90. _coap->optSize += idx;
  91. }
  92. /**
  93. 创建一个coap数据包
  94. @api libcoap.new(code, uri, headers, payload)
  95. @int coap的code, 例如libcoap.GET/libcoap.POST/libcoap.PUT/libcoap.DELETE
  96. @string 目标URI,必须填写, 不需要加上/开头
  97. @table 请求头,类似于http的headers,可选
  98. @string 请求体,类似于http的body,可选
  99. @return userdata coap数据包
  100. @usage
  101. -- 创建一个请求服务器time的数据包
  102. local coapdata = libcoap.new(libcoap.GET, "time")
  103. local data = coapdata:rawdata()
  104. */
  105. static int l_libcoap_new(lua_State* L) {
  106. luat_lib_libcoap_t* _coap;
  107. // 生成coap结构体
  108. _coap = (luat_lib_libcoap_t*)lua_newuserdata(L, sizeof(luat_lib_libcoap_t));
  109. if (_coap == NULL)
  110. {
  111. LLOGW("out of memory!!!");
  112. return 0;
  113. }
  114. memset(_coap, 0, sizeof(luat_lib_libcoap_t));
  115. _coap->header.version = 0x01;
  116. _coap->header.tokenLen = 0;
  117. _coap->header.msgid = c_msgid ++; // 设置msgid
  118. luaL_setmetatable(L, LUAT_COAP_HANDLE);
  119. // 然后根据用户参数设置
  120. // 首先,是code, 第1参数
  121. _coap->header.code = luaL_checkinteger(L, 1);
  122. // 肯定要设置URI的吧, 第2参数
  123. size_t len = 0;
  124. const char* uri = luaL_checklstring(L, 2, &len);
  125. addopt(_coap, 11, uri, len); // Uri-Path = 11
  126. // 设置其他OPT, 第3参数
  127. // TODO 是个table吧
  128. // 最后是data, 第4参数
  129. if (lua_isstring(L, 4)) {
  130. const char* payload = luaL_checklstring(L, 4, &len);
  131. if (len > 512) {
  132. LLOGE("data limit to 512 bytes");
  133. lua_pushstring(L, "data limit to 512 bytes");
  134. lua_error(L);
  135. }
  136. _coap->dataSize = len;
  137. memcpy(_coap->data, payload, len);
  138. }
  139. return 1;
  140. }
  141. /**
  142. 解析coap数据包
  143. @api libcoap.parse(str)
  144. @string coap数据包
  145. @return userdata coap数据包,如果解析失败会返回nil
  146. @usage
  147. -- 解析服务器传入的数据包
  148. local coapdata = libcoap.parse(indata)
  149. log.info("coapdata", coapdata:hcode(), coapdata:data())
  150. */
  151. static int l_libcoap_parse(lua_State* L) {
  152. size_t len;
  153. const char* buff = luaL_checklstring(L, 1, &len);
  154. if (len < 4) {
  155. return 0; // 最起码得有4个字节呀
  156. }
  157. libcoap_header_t *header = (libcoap_header_t *)buff; // 把头部搞一下
  158. if (header->version != 0x01) {
  159. LLOGW("bad coap version");
  160. return 0;
  161. }
  162. luat_lib_libcoap_t* _coap;
  163. // 生成coap结构体
  164. _coap = (luat_lib_libcoap_t*)lua_newuserdata(L, sizeof(luat_lib_libcoap_t));
  165. if (_coap == NULL)
  166. {
  167. LLOGE("out of memory at libcoap.parse");
  168. return 0;
  169. }
  170. memset(_coap, 0, sizeof(luat_lib_libcoap_t));
  171. memcpy(_coap, buff, 4);
  172. luaL_setmetatable(L, LUAT_COAP_HANDLE);
  173. int idx = 4;
  174. // 分析一下token
  175. if (_coap->header.tokenLen > 0) {
  176. memcpy(_coap->token, buff+len, _coap->header.tokenLen);
  177. idx += _coap->header.tokenLen;
  178. }
  179. // 准备一下指针
  180. char* ptr = (char*)buff;
  181. ptr += 4; // 跳过头部
  182. ptr += _coap->header.tokenLen;
  183. // 分析opt
  184. if (idx < len) {
  185. while (idx < len && *ptr != 0xFF) {
  186. libcoap_opt_header_t *opt_header = (libcoap_opt_header_t *)ptr;
  187. if (opt_header->opt_delta == 0xF)
  188. break;
  189. LLOGD("found opt %d %d", opt_header->opt_delta, opt_header->opt_len);
  190. if (opt_header->opt_len <= 12) {
  191. // nop
  192. }
  193. else if (opt_header->opt_len == 13) {
  194. opt_header->opt_len += (unsigned int)(*(ptr+1));
  195. }
  196. ptr += opt_header->opt_len + 1;
  197. idx += opt_header->opt_len + 1;
  198. _coap->optSize += opt_header->opt_len + 1;
  199. }
  200. LLOGD("opt size=%d", _coap->optSize);
  201. memcpy(_coap->opt, ptr - _coap->optSize, _coap->optSize);
  202. }
  203. // 分析一下data
  204. if (idx < len) {
  205. _coap->dataSize = len - idx - 1;
  206. LLOGD("data size=%d", _coap->dataSize);
  207. memcpy(_coap->data, ptr+1, _coap->dataSize);
  208. }
  209. return 1;
  210. }
  211. //---------------------------------------------
  212. #define tocoap(L) ((luat_lib_libcoap_t *)luaL_checkudata(L, 1, LUAT_COAP_HANDLE))
  213. /**
  214. 获取coap数据包的msgid
  215. @api coapdata:msgid()
  216. @return int coap数据包的msgid
  217. @usage
  218. -- 解析服务器传入的数据包
  219. local coapdata = libcoap.parse(indata)
  220. log.info("coapdata", coapdata:msgid())
  221. */
  222. static int libcoap_msgid(lua_State *L) {
  223. luat_lib_libcoap_t *_coap = tocoap(L);
  224. if (_coap == NULL) {
  225. LLOGE("coap sturt is NULL");
  226. lua_pushstring(L, "coap sturt is NULL");
  227. lua_error(L);
  228. return 0;
  229. }
  230. lua_pushinteger(L, _coap->header.msgid);
  231. return 1;
  232. }
  233. /**
  234. 获取coap数据包的token
  235. @api coapdata:token()
  236. @return string coap数据包的token
  237. @usage
  238. -- 解析服务器传入的数据包
  239. local coapdata = libcoap.parse(indata)
  240. log.info("coapdata", coapdata:token())
  241. */
  242. static int libcoap_token(lua_State *L) {
  243. luat_lib_libcoap_t *_coap = tocoap(L);
  244. if (_coap == NULL) {
  245. LLOGE("coap sturt is NULL");
  246. lua_pushstring(L, "coap sturt is NULL");
  247. lua_error(L);
  248. return 0;
  249. }
  250. _coap->token[8] = 0x00; // 确保有结束符
  251. lua_pushstring(L, _coap->token);
  252. return 1;
  253. }
  254. /**
  255. 获取coap数据包的二进制数据,用于发送到服务器
  256. @api coapdata:rawdata()
  257. @return string coap数据包的二进制数据
  258. @usage
  259. -- 解析服务器传入的数据包
  260. local coapdata = libcoap.new(libcoap.GET, "time")
  261. netc:send(coapdata:rawdata())
  262. */
  263. static int libcoap_rawdata(lua_State *L) {
  264. luat_lib_libcoap_t *_coap = tocoap(L);
  265. if (_coap == NULL) {
  266. LLOGE("coap sturt is NULL");
  267. lua_pushstring(L, "coap sturt is NULL");
  268. lua_error(L);
  269. return 0;
  270. }
  271. // 开始合成数据吧
  272. size_t len = 0;
  273. char buff[512] = {0}; // 最大长度暂定512
  274. // 首先, 拷贝头部
  275. _coap->header.version = 0x01;
  276. _coap->header.tokenLen = strlen(_coap->token);
  277. memcpy(buff, _coap, 4); // 头部固定4个字节
  278. len += 4;
  279. //LLOGD("libcoap header len=%d", len);
  280. // 有没有token呢?
  281. if (_coap->header.tokenLen > 0) {
  282. memcpy((char*)(buff) + len, _coap->token, _coap->header.tokenLen);
  283. len += _coap->header.tokenLen;
  284. //LLOGD("libcoap add token %ld", _coap->header.tokenLen);
  285. }
  286. // 然后处理opt
  287. if (_coap->optSize > 0) {
  288. memcpy((char*)(buff) + len, _coap->opt, _coap->optSize);
  289. len += _coap->optSize;
  290. //LLOGD("libcoap add opt %ld ,first=%d", _coap->optSize, _coap->opt[0]);
  291. }
  292. // 最后添加data
  293. if (_coap->dataSize > 0) {
  294. buff[len] = 0xFF;
  295. len ++;
  296. memcpy((char*)(buff) + len, _coap->data, _coap->dataSize);
  297. len += _coap->dataSize;
  298. //LLOGD("libcoap add data %ld", _coap->dataSize);
  299. }
  300. lua_pushlstring(L, buff, len);
  301. return 1;
  302. }
  303. /**
  304. 获取coap数据包的code
  305. @api coapdata:code()
  306. @return int coap数据包的code
  307. @usage
  308. -- 解析服务器传入的数据包
  309. local coapdata = libcoap.parse(indata)
  310. log.info("coapdata", coapdata:code())
  311. */
  312. static int libcoap_code(lua_State *L) {
  313. luat_lib_libcoap_t *_coap = tocoap(L);
  314. if (_coap == NULL) {
  315. LLOGE("coap sturt is NULL");
  316. lua_pushstring(L, "coap sturt is NULL");
  317. lua_error(L);
  318. return 0;
  319. }
  320. lua_pushinteger(L, _coap->header.code);
  321. return 1;
  322. }
  323. /**
  324. 获取coap数据包的http code, 比coap原始的code要友好
  325. @api coapdata:hcode()
  326. @return int coap数据包的http code,例如200,205,404
  327. @usage
  328. -- 解析服务器传入的数据包
  329. local coapdata = libcoap.parse(indata)
  330. log.info("coapdata", coapdata:hcode())
  331. */
  332. static int libcoap_httpcode(lua_State *L) {
  333. luat_lib_libcoap_t *_coap = tocoap(L);
  334. if (_coap == NULL) {
  335. LLOGE("coap sturt is NULL");
  336. lua_pushstring(L, "coap sturt is NULL");
  337. lua_error(L);
  338. return 0;
  339. }
  340. lua_pushinteger(L, (_coap->header.code >> 5) * 100 + (_coap->header.code & 0xF));
  341. return 1;
  342. }
  343. /**
  344. 获取coap数据包的type, 例如libcoap.CON/NON/ACK/RST
  345. @api coapdata:type(t)
  346. @int 新的type值,可选
  347. @return int coap数据包的type
  348. @usage
  349. -- 解析服务器传入的数据包
  350. local coapdata = libcoap.parse(indata)
  351. log.info("coapdata", coapdata:type())
  352. */
  353. static int libcoap_type(lua_State *L) {
  354. luat_lib_libcoap_t *_coap = tocoap(L);
  355. if (_coap == NULL) {
  356. LLOGE("coap sturt is NULL");
  357. lua_pushstring(L, "coap sturt is NULL");
  358. lua_error(L);
  359. return 0;
  360. }
  361. if (lua_isinteger(L, 1)) {
  362. _coap->header.type = luaL_checkinteger(L, 1);
  363. }
  364. lua_pushinteger(L, _coap->header.type);
  365. return 1;
  366. }
  367. /**
  368. 获取coap数据包的data
  369. @api coapdata:data()
  370. @return string coap数据包的data
  371. @usage
  372. -- 解析服务器传入的数据包
  373. local coapdata = libcoap.parse(indata)
  374. log.info("coapdata", coapdata:data())
  375. */
  376. static int libcoap_data(lua_State *L) {
  377. luat_lib_libcoap_t *_coap = tocoap(L);
  378. if (_coap == NULL) {
  379. LLOGE("coap sturt is NULL");
  380. lua_pushstring(L, "coap sturt is NULL");
  381. lua_error(L);
  382. return 0;
  383. }
  384. lua_pushlstring(L, _coap->data, _coap->dataSize);
  385. return 1;
  386. }
  387. static const luaL_Reg lib_libcoap[] = {
  388. {"tp", libcoap_type},
  389. {"msgid", libcoap_msgid},
  390. {"token", libcoap_token},
  391. {"code", libcoap_code},
  392. {"hcode", libcoap_httpcode},
  393. {"rawdata", libcoap_rawdata},
  394. {"data", libcoap_data},
  395. //{"__gc", libcoap_gc},
  396. //{"__tostring", libcoap_tostring},
  397. {NULL, NULL}
  398. };
  399. static void createmeta (lua_State *L) {
  400. luaL_newmetatable(L, LUAT_COAP_HANDLE); /* create metatable for file handles */
  401. lua_pushvalue(L, -1); /* push metatable */
  402. lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
  403. luaL_setfuncs(L, lib_libcoap, 0); /* add file methods to new metatable */
  404. lua_pop(L, 1); /* pop new metatable */
  405. }
  406. #include "rotable2.h"
  407. #define CODE(H,L) (H << 5 + L)
  408. static const rotable_Reg_t reg_libcoap[] =
  409. {
  410. { "new", ROREG_FUNC(l_libcoap_new)},
  411. { "parse", ROREG_FUNC(l_libcoap_parse)},
  412. // ----- 类型常量
  413. { "CON", ROREG_INT(0)},
  414. { "NON", ROREG_INT(1)},
  415. { "ACK", ROREG_INT(2)},
  416. { "RST", ROREG_INT(3)},
  417. // 请求类)
  418. { "NONE", ROREG_INT(0)},
  419. { "GET", ROREG_INT(1)},
  420. { "POST", ROREG_INT(2)},
  421. { "PUT", ROREG_INT(3)},
  422. { "DELETE", ROREG_INT(4)},
  423. // 响应类
  424. // { "Created", NULL, CODE(2,1)},
  425. // { "Deleted", NULL, CODE(2,2)},
  426. // { "Valid", NULL, CODE(2,3)},
  427. // { "Changed", NULL, CODE(2,4)},
  428. // { "Content", NULL, CODE(2,5)},
  429. // { "Bad Request",NULL, CODE(4,0)},
  430. // { "Unauthorized",NULL, CODE(4,1)},
  431. // { "Bad Option", NULL, CODE(4,2)},
  432. // { "Forbidden", NULL, CODE(4,3)},
  433. // { "Not Found", NULL, CODE(4,4)},
  434. // { "Method Not Allowed",NULL, CODE(4,5)},
  435. // { "Not Acceptable", NULL, CODE(4,6)},
  436. // { "Precondition Failed", NULL, CODE(4,12)},
  437. // { "Request Entity Too Large", NULL, CODE(4,13)},
  438. // { "Unsupported Content-Format", NULL, CODE(4,15)},
  439. // { "Internal Server Error", NULL, CODE(5,0)},
  440. // { "Not Implemented", NULL, CODE(5,1)},
  441. // { "Bad Gateway", NULL, CODE(5,2)},
  442. // { "Service Unavailable", NULL, CODE(5,3)},
  443. // { "Gateway Timeout", NULL, CODE(5,4)},
  444. // { "Proxying Not Supported", NULL, CODE(5,5)},
  445. { NULL, ROREG_INT(0) }
  446. };
  447. LUAMOD_API int luaopen_libcoap( lua_State *L ) {
  448. luat_newlib2(L, reg_libcoap);
  449. createmeta(L);
  450. return 1;
  451. }