/* @module libcoap @summary coap数据处理 @version 1.0 @data 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; } // libcoap.new(libcoap.GET, "time", {}, nil) 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) { 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; } 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)) 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; } 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; } 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; } 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; } 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; } 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; } lua_pushinteger(L, _coap->header.type); return 1; } 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 ) { rotable_newlib(L, reg_libcoap); createmeta(L); return 1; }