| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- /*
- @module libcoap
- @summary coap数据处理
- @version 1.0
- @date 2020.06.30
- */
- #include "luat_base.h"
- #include "luat_timer.h"
- #include "luat_malloc.h"
- #include "luat_msgbus.h"
- #define LUAT_LOG_TAG "luat.libcoap"
- #include "luat_log.h"
- //---------------------------
- #ifndef COAP_OPTION_IF_MATCH
- #define COAP_OPTION_IF_MATCH 1 /* C, opaque, 0-8 B, (none) */
- #define COAP_OPTION_URI_HOST 3 /* C, String, 1-255 B, destination address */
- #define COAP_OPTION_ETAG 4 /* E, opaque, 1-8 B, (none) */
- #define COAP_OPTION_IF_NONE_MATCH 5 /* empty, 0 B, (none) */
- #define COAP_OPTION_URI_PORT 7 /* C, uint, 0-2 B, destination port */
- #define COAP_OPTION_LOCATION_PATH 8 /* E, String, 0-255 B, - */
- #define COAP_OPTION_URI_PATH 11 /* C, String, 0-255 B, (none) */
- #define COAP_OPTION_CONTENT_FORMAT 12 /* E, uint, 0-2 B, (none) */
- #define COAP_OPTION_CONTENT_TYPE COAP_OPTION_CONTENT_FORMAT
- #define COAP_OPTION_MAXAGE 14 /* E, uint, 0--4 B, 60 Seconds */
- #define COAP_OPTION_URI_QUERY 15 /* C, String, 1-255 B, (none) */
- #define COAP_OPTION_ACCEPT 17 /* C, uint, 0-2 B, (none) */
- #define COAP_OPTION_LOCATION_QUERY 20 /* E, String, 0-255 B, (none) */
- #define COAP_OPTION_SIZE2 28 /* E, uint, 0-4 B, (none) */
- #define COAP_OPTION_PROXY_URI 35 /* C, String, 1-1034 B, (none) */
- #define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */
- #define COAP_OPTION_SIZE1 60 /* E, uint, 0-4 B, (none) */
- #define COAP_MEDIATYPE_TEXT_PLAIN 0 /* text/plain (UTF-8) */
- #define COAP_MEDIATYPE_APPLICATION_LINK_FORMAT 40 /* application/link-format */
- #define COAP_MEDIATYPE_APPLICATION_XML 41 /* application/xml */
- #define COAP_MEDIATYPE_APPLICATION_OCTET_STREAM 42 /* application/octet-stream */
- #define COAP_MEDIATYPE_APPLICATION_RDF_XML 43 /* application/rdf+xml */
- #define COAP_MEDIATYPE_APPLICATION_EXI 47 /* application/exi */
- #define COAP_MEDIATYPE_APPLICATION_JSON 50 /* application/json */
- #define COAP_MEDIATYPE_APPLICATION_CBOR 60 /* application/cbor */
- #endif
- //---------------------------
- typedef struct libcoap_header
- {
- unsigned int tokenLen: 4 ;
- unsigned int type : 2 ; // 0 - CON, 1 - NON, 2 - ACK, 3 - RST
- unsigned int version : 2 ;
- uint8_t code;
- uint16_t msgid;
- }libcoap_header_t;
- typedef struct libcoap_opt_header
- {
- unsigned int opt_len : 4 ;
- unsigned int opt_delta : 4 ;
- }libcoap_opt_header_t;
- typedef struct luat_lib_libcoap
- {
- libcoap_header_t header;
- char token[9];
- size_t optSize;
- size_t dataSize;
- char opt[256];
- char data[512 - 128];
- }luat_lib_libcoap_t;
- static uint16_t c_msgid = 1;
- #define LUAT_COAP_HANDLE "COAP*"
- //-----------------------------------------------------------------
- static void addopt(luat_lib_libcoap_t* _coap, uint8_t opt_type, const char* value, size_t len) {
- if (_coap->optSize > 0) { // 检查需要之前的opt
- }
- int cur_opt = opt_type;
- // LLOGD("opt type=%d value len=%d", opt_type, len);
- // LLOGD("opt optSize cur=%d", _coap->optSize);
- size_t idx = _coap->optSize;
- if (len <= 12) {
- _coap->opt[idx++] = (cur_opt << 4) + (len & 0xF);
- }
- else if (len <= 268) {
- _coap->opt[idx++] = (cur_opt << 4) + (0x0D);
- _coap->opt[idx++] = len - 0x0D;
- } else {
- LLOGW("coap opt is too large!!! ignore!!!");
- return;
- }
- for (size_t i = 0; i < len; i++)
- {
- _coap->opt[idx++] = *(value + i);
- }
- _coap->optSize += idx;
- }
- /**
- 创建一个coap数据包
- @api libcoap.new(code, uri, headers, payload)
- @int coap的code, 例如libcoap.GET/libcoap.POST/libcoap.PUT/libcoap.DELETE
- @string 目标URI,必须填写, 不需要加上/开头
- @table 请求头,类似于http的headers,可选
- @string 请求体,类似于http的body,可选
- @return userdata coap数据包
- @usage
- -- 创建一个请求服务器time的数据包
- local coapdata = libcoap.new(libcoap.GET, "time")
- local data = coapdata:rawdata()
- */
- static int l_libcoap_new(lua_State* L) {
- luat_lib_libcoap_t* _coap;
- // 生成coap结构体
- _coap = (luat_lib_libcoap_t*)lua_newuserdata(L, sizeof(luat_lib_libcoap_t));
- if (_coap == NULL)
- {
- LLOGW("out of memory!!!");
- return 0;
- }
- memset(_coap, 0, sizeof(luat_lib_libcoap_t));
- _coap->header.version = 0x01;
- _coap->header.tokenLen = 0;
- _coap->header.msgid = c_msgid ++; // 设置msgid
- luaL_setmetatable(L, LUAT_COAP_HANDLE);
- // 然后根据用户参数设置
- // 首先,是code, 第1参数
- _coap->header.code = luaL_checkinteger(L, 1);
- // 肯定要设置URI的吧, 第2参数
- size_t len = 0;
- const char* uri = luaL_checklstring(L, 2, &len);
- addopt(_coap, 11, uri, len); // Uri-Path = 11
- // 设置其他OPT, 第3参数
- // TODO 是个table吧
- // 最后是data, 第4参数
- if (lua_isstring(L, 4)) {
- const char* payload = luaL_checklstring(L, 4, &len);
- if (len > 512) {
- LLOGE("data limit to 512 bytes");
- lua_pushstring(L, "data limit to 512 bytes");
- lua_error(L);
- }
- _coap->dataSize = len;
- memcpy(_coap->data, payload, len);
- }
- return 1;
- }
- /**
- 解析coap数据包
- @api libcoap.parse(str)
- @string coap数据包
- @return userdata coap数据包,如果解析失败会返回nil
- @usage
- -- 解析服务器传入的数据包
- local coapdata = libcoap.parse(indata)
- log.info("coapdata", coapdata:hcode(), coapdata:data())
- */
- static int l_libcoap_parse(lua_State* L) {
- size_t len;
- const char* buff = luaL_checklstring(L, 1, &len);
- if (len < 4) {
- return 0; // 最起码得有4个字节呀
- }
- libcoap_header_t *header = (libcoap_header_t *)buff; // 把头部搞一下
- if (header->version != 0x01) {
- LLOGW("bad coap version");
- return 0;
- }
- luat_lib_libcoap_t* _coap;
- // 生成coap结构体
- _coap = (luat_lib_libcoap_t*)lua_newuserdata(L, sizeof(luat_lib_libcoap_t));
- if (_coap == NULL)
- {
- LLOGE("out of memory at libcoap.parse");
- return 0;
- }
- memset(_coap, 0, sizeof(luat_lib_libcoap_t));
- memcpy(_coap, buff, 4);
- luaL_setmetatable(L, LUAT_COAP_HANDLE);
- int idx = 4;
- // 分析一下token
- if (_coap->header.tokenLen > 0) {
- memcpy(_coap->token, buff+len, _coap->header.tokenLen);
- idx += _coap->header.tokenLen;
- }
- // 准备一下指针
- char* ptr = (char*)buff;
- ptr += 4; // 跳过头部
- ptr += _coap->header.tokenLen;
- // 分析opt
- if (idx < len) {
- while (idx < len && *ptr != 0xFF) {
- libcoap_opt_header_t *opt_header = (libcoap_opt_header_t *)ptr;
- if (opt_header->opt_delta == 0xF)
- break;
- LLOGD("found opt %d %d", opt_header->opt_delta, opt_header->opt_len);
- if (opt_header->opt_len <= 12) {
- // nop
- }
- else if (opt_header->opt_len == 13) {
- opt_header->opt_len += (unsigned int)(*(ptr+1));
- }
-
- ptr += opt_header->opt_len + 1;
- idx += opt_header->opt_len + 1;
- _coap->optSize += opt_header->opt_len + 1;
- }
- LLOGD("opt size=%d", _coap->optSize);
- memcpy(_coap->opt, ptr - _coap->optSize, _coap->optSize);
- }
-
- // 分析一下data
- if (idx < len) {
- _coap->dataSize = len - idx - 1;
- LLOGD("data size=%d", _coap->dataSize);
- memcpy(_coap->data, ptr+1, _coap->dataSize);
- }
- return 1;
- }
- //---------------------------------------------
- #define tocoap(L) ((luat_lib_libcoap_t *)luaL_checkudata(L, 1, LUAT_COAP_HANDLE))
- /**
- 获取coap数据包的msgid
- @api coapdata:msgid()
- @return int coap数据包的msgid
- @usage
- -- 解析服务器传入的数据包
- local coapdata = libcoap.parse(indata)
- log.info("coapdata", coapdata:msgid())
- */
- static int libcoap_msgid(lua_State *L) {
- luat_lib_libcoap_t *_coap = tocoap(L);
- if (_coap == NULL) {
- LLOGE("coap sturt is NULL");
- lua_pushstring(L, "coap sturt is NULL");
- lua_error(L);
- return 0;
- }
- lua_pushinteger(L, _coap->header.msgid);
- return 1;
- }
- /**
- 获取coap数据包的token
- @api coapdata:token()
- @return string coap数据包的token
- @usage
- -- 解析服务器传入的数据包
- local coapdata = libcoap.parse(indata)
- log.info("coapdata", coapdata:token())
- */
- static int libcoap_token(lua_State *L) {
- luat_lib_libcoap_t *_coap = tocoap(L);
- if (_coap == NULL) {
- LLOGE("coap sturt is NULL");
- lua_pushstring(L, "coap sturt is NULL");
- lua_error(L);
- return 0;
- }
- _coap->token[8] = 0x00; // 确保有结束符
- lua_pushstring(L, _coap->token);
- return 1;
- }
- /**
- 获取coap数据包的二进制数据,用于发送到服务器
- @api coapdata:rawdata()
- @return string coap数据包的二进制数据
- @usage
- -- 解析服务器传入的数据包
- local coapdata = libcoap.new(libcoap.GET, "time")
- netc:send(coapdata:rawdata())
- */
- static int libcoap_rawdata(lua_State *L) {
- luat_lib_libcoap_t *_coap = tocoap(L);
- if (_coap == NULL) {
- LLOGE("coap sturt is NULL");
- lua_pushstring(L, "coap sturt is NULL");
- lua_error(L);
- return 0;
- }
- // 开始合成数据吧
- size_t len = 0;
- char buff[512] = {0}; // 最大长度暂定512
- // 首先, 拷贝头部
- _coap->header.version = 0x01;
- _coap->header.tokenLen = strlen(_coap->token);
- memcpy(buff, _coap, 4); // 头部固定4个字节
- len += 4;
- //LLOGD("libcoap header len=%d", len);
- // 有没有token呢?
- if (_coap->header.tokenLen > 0) {
- memcpy((char*)(buff) + len, _coap->token, _coap->header.tokenLen);
- len += _coap->header.tokenLen;
- //LLOGD("libcoap add token %ld", _coap->header.tokenLen);
- }
- // 然后处理opt
- if (_coap->optSize > 0) {
- memcpy((char*)(buff) + len, _coap->opt, _coap->optSize);
- len += _coap->optSize;
- //LLOGD("libcoap add opt %ld ,first=%d", _coap->optSize, _coap->opt[0]);
- }
- // 最后添加data
- if (_coap->dataSize > 0) {
- buff[len] = 0xFF;
- len ++;
- memcpy((char*)(buff) + len, _coap->data, _coap->dataSize);
- len += _coap->dataSize;
- //LLOGD("libcoap add data %ld", _coap->dataSize);
- }
- lua_pushlstring(L, buff, len);
- return 1;
- }
- /**
- 获取coap数据包的code
- @api coapdata:code()
- @return int coap数据包的code
- @usage
- -- 解析服务器传入的数据包
- local coapdata = libcoap.parse(indata)
- log.info("coapdata", coapdata:code())
- */
- static int libcoap_code(lua_State *L) {
- luat_lib_libcoap_t *_coap = tocoap(L);
- if (_coap == NULL) {
- LLOGE("coap sturt is NULL");
- lua_pushstring(L, "coap sturt is NULL");
- lua_error(L);
- return 0;
- }
- lua_pushinteger(L, _coap->header.code);
- return 1;
- }
- /**
- 获取coap数据包的http code, 比coap原始的code要友好
- @api coapdata:hcode()
- @return int coap数据包的http code,例如200,205,404
- @usage
- -- 解析服务器传入的数据包
- local coapdata = libcoap.parse(indata)
- log.info("coapdata", coapdata:hcode())
- */
- static int libcoap_httpcode(lua_State *L) {
- luat_lib_libcoap_t *_coap = tocoap(L);
- if (_coap == NULL) {
- LLOGE("coap sturt is NULL");
- lua_pushstring(L, "coap sturt is NULL");
- lua_error(L);
- return 0;
- }
- lua_pushinteger(L, (_coap->header.code >> 5) * 100 + (_coap->header.code & 0xF));
- return 1;
- }
- /**
- 获取coap数据包的type, 例如libcoap.CON/NON/ACK/RST
- @api coapdata:type(t)
- @int 新的type值,可选
- @return int coap数据包的type
- @usage
- -- 解析服务器传入的数据包
- local coapdata = libcoap.parse(indata)
- log.info("coapdata", coapdata:type())
- */
- static int libcoap_type(lua_State *L) {
- luat_lib_libcoap_t *_coap = tocoap(L);
- if (_coap == NULL) {
- LLOGE("coap sturt is NULL");
- lua_pushstring(L, "coap sturt is NULL");
- lua_error(L);
- return 0;
- }
- if (lua_isinteger(L, 1)) {
- _coap->header.type = luaL_checkinteger(L, 1);
- }
- lua_pushinteger(L, _coap->header.type);
- return 1;
- }
- /**
- 获取coap数据包的data
- @api coapdata:data()
- @return string coap数据包的data
- @usage
- -- 解析服务器传入的数据包
- local coapdata = libcoap.parse(indata)
- log.info("coapdata", coapdata:data())
- */
- static int libcoap_data(lua_State *L) {
- luat_lib_libcoap_t *_coap = tocoap(L);
- if (_coap == NULL) {
- LLOGE("coap sturt is NULL");
- lua_pushstring(L, "coap sturt is NULL");
- lua_error(L);
- return 0;
- }
- lua_pushlstring(L, _coap->data, _coap->dataSize);
- return 1;
- }
- static const luaL_Reg lib_libcoap[] = {
- {"tp", libcoap_type},
- {"msgid", libcoap_msgid},
- {"token", libcoap_token},
- {"code", libcoap_code},
- {"hcode", libcoap_httpcode},
- {"rawdata", libcoap_rawdata},
- {"data", libcoap_data},
- //{"__gc", libcoap_gc},
- //{"__tostring", libcoap_tostring},
- {NULL, NULL}
- };
- static void createmeta (lua_State *L) {
- luaL_newmetatable(L, LUAT_COAP_HANDLE); /* create metatable for file handles */
- lua_pushvalue(L, -1); /* push metatable */
- lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
- luaL_setfuncs(L, lib_libcoap, 0); /* add file methods to new metatable */
- lua_pop(L, 1); /* pop new metatable */
- }
- #include "rotable.h"
- #define CODE(H,L) (H << 5 + L)
- static const rotable_Reg reg_libcoap[] =
- {
- { "new", l_libcoap_new, 0},
- { "parse", l_libcoap_parse, 0},
- // ----- 类型常量
- { "CON", NULL, 0},
- { "NON", NULL, 1},
- { "ACK", NULL, 2},
- { "RST", NULL, 3},
- // 请求类
- { "NONE", NULL, 0},
- { "GET", NULL, 1},
- { "POST", NULL, 2},
- { "PUT", NULL, 3},
- { "DELETE", NULL, 4},
- // 响应类
- // { "Created", NULL, CODE(2,1)},
- // { "Deleted", NULL, CODE(2,2)},
- // { "Valid", NULL, CODE(2,3)},
- // { "Changed", NULL, CODE(2,4)},
- // { "Content", NULL, CODE(2,5)},
- // { "Bad Request",NULL, CODE(4,0)},
- // { "Unauthorized",NULL, CODE(4,1)},
- // { "Bad Option", NULL, CODE(4,2)},
- // { "Forbidden", NULL, CODE(4,3)},
- // { "Not Found", NULL, CODE(4,4)},
- // { "Method Not Allowed",NULL, CODE(4,5)},
- // { "Not Acceptable", NULL, CODE(4,6)},
- // { "Precondition Failed", NULL, CODE(4,12)},
- // { "Request Entity Too Large", NULL, CODE(4,13)},
- // { "Unsupported Content-Format", NULL, CODE(4,15)},
- // { "Internal Server Error", NULL, CODE(5,0)},
- // { "Not Implemented", NULL, CODE(5,1)},
- // { "Bad Gateway", NULL, CODE(5,2)},
- // { "Service Unavailable", NULL, CODE(5,3)},
- // { "Gateway Timeout", NULL, CODE(5,4)},
- // { "Proxying Not Supported", NULL, CODE(5,5)},
- { NULL, NULL , 0}
- };
- LUAMOD_API int luaopen_libcoap( lua_State *L ) {
- luat_newlib(L, reg_libcoap);
- createmeta(L);
- return 1;
- }
|