diff --git a/README.md b/README.md index d6d69bc5..d343075c 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,10 @@ Tencent QQ group: 309957875
- cross compiler (done) # Change log +2015-03-15
+bugs fixed: #239, #273.
+reduce coap module memory usage, add coap module to default built. + 2015-03-11
fix bugs of spiffs.
build both float and integer version [latest releases](https://github.com/nodemcu/nodemcu-firmware/releases/latest).
@@ -414,3 +418,25 @@ They'll be available as `u8g.` in Lua. -- first LED green, second LED white ws2812.writergb(4, string.char(0, 255, 0, 255, 255, 255)) ``` + +####coap client and server +```lua +-- use copper addon for firefox +cs=coap.Server() +cs:listen(5683) + +myvar=1 +cs:var("myvar") -- get coap://192.168.18.103:5683/v1/v/myvar will return the value of myvar: 1 + +-- function should tack one string, return one string. +function myfun(payload) + print("myfun called") + respond = "hello" + return respond +end +cs:func("myfun") -- post coap://192.168.18.103:5683/v1/f/myfun will call myfun + +cc = coap.Client() +cc:get(coap.CON, "coap://192.168.18.100:5683/.well-known/core") +cc:post(coap.NON, "coap://192.168.18.100:5683/", "Hello") +``` \ No newline at end of file diff --git a/app/coap/coap.c b/app/coap/coap.c index 6dded680..af431d76 100644 --- a/app/coap/coap.c +++ b/app/coap/coap.c @@ -76,7 +76,7 @@ int coap_parseToken(coap_buffer_t *tokbuf, const coap_header_t *hdr, const uint8 else if (hdr->tkl <= 8) { - if (4 + hdr->tkl > buflen) + if (4U + hdr->tkl > buflen) return COAP_ERR_TOKEN_TOO_SHORT; // tok bigger than packet tokbuf->p = buf+4; // past header tokbuf->len = hdr->tkl; @@ -93,7 +93,7 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8 { // inject token uint8_t *p; - if (buflen < 4 + hdr->tkl) + if (buflen < (4U + hdr->tkl)) return COAP_ERR_BUFFER_TOO_SMALL; p = buf + 4; if ((hdr->tkl > 0) && (hdr->tkl != tokbuf->len)) @@ -102,7 +102,7 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8 if (hdr->tkl > 0) c_memcpy(p, tokbuf->p, hdr->tkl); - // http://tools.ietf.org/html/draft-ietf-core-coap-18#section-3.1 + // http://tools.ietf.org/html/rfc7252#section-3.1 // inject options return hdr->tkl; } @@ -111,8 +111,8 @@ int coap_buildToken(const coap_buffer_t *tokbuf, const coap_header_t *hdr, uint8 int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8_t **buf, size_t buflen) { const uint8_t *p = *buf; - uint16_t len, delta; uint8_t headlen = 1; + uint16_t len, delta; if (buflen < headlen) // too small return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER; @@ -179,14 +179,14 @@ int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8 return 0; } -// http://tools.ietf.org/html/draft-ietf-core-coap-18#section-3.1 +// http://tools.ietf.org/html/rfc7252#section-3.1 int coap_parseOptionsAndPayload(coap_option_t *options, uint8_t *numOptions, coap_buffer_t *payload, const coap_header_t *hdr, const uint8_t *buf, size_t buflen) { size_t optionIndex = 0; + uint16_t delta = 0; const uint8_t *p = buf + 4 + hdr->tkl; const uint8_t *end = buf + buflen; int rc; - uint16_t delta = 0; if (p > end) return COAP_ERR_OPTION_OVERRUNS_PACKET; // out of bounds @@ -215,7 +215,7 @@ int coap_parseOptionsAndPayload(coap_option_t *options, uint8_t *numOptions, coa return 0; } -int coap_buildOptionHeader(unsigned short optDelta, size_t length, uint8_t *buf, size_t buflen) +int coap_buildOptionHeader(uint32_t optDelta, size_t length, uint8_t *buf, size_t buflen) { int n = 0; uint8_t *p = buf; @@ -298,7 +298,7 @@ int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen) } // options are always stored consecutively, so can return a block with same option num -const coap_option_t * coap_findOptions(const coap_packet_t *pkt, uint8_t num, uint8_t *count) +const coap_option_t *coap_findOptions(const coap_packet_t *pkt, uint8_t num, uint8_t *count) { // FIXME, options is always sorted, can find faster than this size_t i; @@ -352,7 +352,7 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt) uint16_t optDelta = 0; int rc = 0; - if (p-buf > *buflen) + if (((size_t)(p-buf)) > *buflen) return COAP_ERR_BUFFER_TOO_SMALL; optDelta = pkt->opts[i].num - running_delta; @@ -381,17 +381,17 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt) return 0; } -void coap_option_nibble(uint16_t value, uint8_t *nibble) +void coap_option_nibble(uint32_t value, uint8_t *nibble) { if (value<13) { *nibble = (0xFF & value); } else - if (((uint32_t)value)<=0xFF+13) + if (value<=0xFF+13) { *nibble = 13; - } else if (((uint32_t)value) -269 <=0xFFFF) + } else if (value<=0xFFFF+269) { *nibble = 14; } @@ -405,7 +405,7 @@ int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint pkt->hdr.code = rspcode; pkt->hdr.id[0] = msgid_hi; pkt->hdr.id[1] = msgid_lo; - pkt->numopts = 0; + pkt->numopts = 1; // need token in response if (tok) { @@ -442,7 +442,7 @@ unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val) { return n; } -static uint8_t _token_data[4]={'n','o','d','e'}; +static uint8_t _token_data[4] = {'n','o','d','e'}; coap_buffer_t the_token = { _token_data, 4 }; static unsigned short message_id; diff --git a/app/coap/coap.h b/app/coap/coap.h index 1c8827a6..3862f57b 100644 --- a/app/coap/coap.h +++ b/app/coap/coap.h @@ -18,13 +18,15 @@ extern "C" { #define COAP_RESPONSE_CLASS(C) (((C) >> 5) & 0xFF) -// http://tools.ietf.org/html/draft-ietf-core-coap-18#section-3 +//http://tools.ietf.org/html/rfc7252#section-3 typedef struct { - uint8_t ver; - uint8_t t; - uint8_t tkl; - uint8_t code; + uint8_t ver; /* CoAP version number */ + uint8_t t; /* CoAP Message Type */ + uint8_t tkl; /* Token length: indicates length of the Token field */ + uint8_t code; /* CoAP status code. Can be request (0.xx), success reponse (2.xx), + * client error response (4.xx), or rever error response (5.xx) + * For possible values, see http://tools.ietf.org/html/rfc7252#section-12.1 */ uint8_t id[2]; } coap_header_t; @@ -42,23 +44,24 @@ typedef struct typedef struct { - uint8_t num; - coap_buffer_t buf; + uint8_t num; /* Option number. See http://tools.ietf.org/html/rfc7252#section-5.10 */ + coap_buffer_t buf; /* Option value */ } coap_option_t; typedef struct { - coap_header_t hdr; - coap_buffer_t tok; - uint8_t numopts; - coap_option_t opts[MAXOPT]; - coap_buffer_t payload; - coap_rw_buffer_t scratch; // scratch->p = malloc(...) , and free it when done. + coap_header_t hdr; /* Header of the packet */ + coap_buffer_t tok; /* Token value, size as specified by hdr.tkl */ + uint8_t numopts; /* Number of options */ + coap_option_t opts[MAXOPT]; /* Options of the packet. For possible entries see + * http://tools.ietf.org/html/rfc7252#section-5.10 */ + coap_buffer_t payload; /* Payload carried by the packet */ + coap_rw_buffer_t content; // content->p = malloc(...) , and free it when done. } coap_packet_t; ///////////////////////////////////////// -//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.2 +//http://tools.ietf.org/html/rfc7252#section-12.2 typedef enum { COAP_OPTION_IF_MATCH = 1, @@ -78,7 +81,7 @@ typedef enum COAP_OPTION_PROXY_SCHEME = 39 } coap_option_num_t; -//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.1.1 +//http://tools.ietf.org/html/rfc7252#section-12.1.1 typedef enum { COAP_METHOD_GET = 1, @@ -87,7 +90,7 @@ typedef enum COAP_METHOD_DELETE = 4 } coap_method_t; -//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.1.1 +//http://tools.ietf.org/html/rfc7252#section-12.1.1 typedef enum { COAP_TYPE_CON = 0, @@ -96,8 +99,8 @@ typedef enum COAP_TYPE_RESET = 3 } coap_msgtype_t; -//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-5.2 -//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.1.2 +//http://tools.ietf.org/html/rfc7252#section-5.2 +//http://tools.ietf.org/html/rfc7252#section-12.1.2 #define MAKE_RSPCODE(clas, det) ((clas << 5) | (det)) typedef enum { @@ -107,7 +110,7 @@ typedef enum COAP_RSPCODE_CHANGED = MAKE_RSPCODE(2, 4) } coap_responsecode_t; -//http://tools.ietf.org/html/draft-ietf-core-coap-18#section-12.3 +//http://tools.ietf.org/html/rfc7252#section-12.3 typedef enum { COAP_CONTENTTYPE_NONE = -1, // bodge to allow us not to send option block @@ -155,15 +158,21 @@ struct coap_luser_entry{ coap_luser_entry *next; }; -struct coap_endpoint_t -{ - coap_method_t method; - coap_endpoint_func handler; - const coap_endpoint_path_t *path; - const char *core_attr; - coap_luser_entry *user_entry; +struct coap_endpoint_t{ + coap_method_t method; /* (i.e. POST, PUT or GET) */ + coap_endpoint_func handler; /* callback function which handles this + * type of endpoint (and calls + * coap_make_response() at some point) */ + const coap_endpoint_path_t *path; /* path towards a resource (i.e. foo/bar/) */ + const char *core_attr; /* the 'ct' attribute, as defined in RFC7252, section 7.2.1.: + * "The Content-Format code "ct" attribute + * provides a hint about the + * Content-Formats this resource returns." + * (Section 12.3. lists possible ct values.) */ + coap_luser_entry *user_entry; }; + /////////////////////// void coap_dumpPacket(coap_packet_t *pkt); int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen); @@ -173,11 +182,11 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt); void coap_dump(const uint8_t *buf, size_t buflen, bool bare); int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint8_t *content, size_t content_len, uint8_t msgid_hi, uint8_t msgid_lo, const coap_buffer_t* tok, coap_responsecode_t rspcode, coap_content_type_t content_type); int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt); -void coap_option_nibble(uint16_t value, uint8_t *nibble); +void coap_option_nibble(uint32_t value, uint8_t *nibble); void coap_setup(void); void endpoint_setup(void); -int coap_buildOptionHeader(unsigned short optDelta, size_t length, uint8_t *buf, size_t buflen); +int coap_buildOptionHeader(uint32_t optDelta, size_t length, uint8_t *buf, size_t buflen); #ifdef __cplusplus } diff --git a/app/coap/coap_client.c b/app/coap/coap_client.c index 37a1a5f0..63caf074 100644 --- a/app/coap/coap_client.c +++ b/app/coap/coap_client.c @@ -11,6 +11,8 @@ void coap_client_response_handler(char *data, unsigned short len, unsigned short { NODE_DBG("coap_client_response_handler is called.\n"); coap_packet_t pkt; + pkt.content.p = NULL; + pkt.content.len = 0; int rc; if (0 != (rc = coap_parse(&pkt, data, len))){ diff --git a/app/coap/coap_server.c b/app/coap/coap_server.c index c83df093..cbec01f9 100644 --- a/app/coap/coap_server.c +++ b/app/coap/coap_server.c @@ -1,5 +1,6 @@ #include "user_config.h" #include "c_types.h" +#include "c_stdlib.h" #include "coap.h" @@ -8,6 +9,8 @@ size_t coap_server_respond(char *req, unsigned short reqlen, char *rsp, unsigned NODE_DBG("coap_server_respond is called.\n"); size_t rlen = rsplen; coap_packet_t pkt; + pkt.content.p = NULL; + pkt.content.len = 0; uint8_t scratch_raw[4]; coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)}; int rc; @@ -25,13 +28,16 @@ size_t coap_server_respond(char *req, unsigned short reqlen, char *rsp, unsigned else { coap_packet_t rsppkt; + rsppkt.content.p = NULL; + rsppkt.content.len = 0; #ifdef COAP_DEBUG coap_dumpPacket(&pkt); #endif coap_handle_req(&scratch_buf, &pkt, &rsppkt); if (0 != (rc = coap_build(rsp, &rlen, &rsppkt))){ NODE_DBG("coap_build failed rc=%d\n", rc); - return 0; + // return 0; + rlen = 0; } else { @@ -44,6 +50,11 @@ size_t coap_server_respond(char *req, unsigned short reqlen, char *rsp, unsigned coap_dumpPacket(&rsppkt); #endif } + if(rsppkt.content.p){ + c_free(rsppkt.content.p); + rsppkt.content.p = NULL; + rsppkt.content.len = 0; + } return rlen; } } diff --git a/app/coap/endpoints.c b/app/coap/endpoints.c index 43a44eb1..1d7d48bb 100644 --- a/app/coap/endpoints.c +++ b/app/coap/endpoints.c @@ -1,5 +1,6 @@ #include "c_stdio.h" #include "c_string.h" +#include "c_stdlib.h" #include "coap.h" #include "lua.h" @@ -8,20 +9,24 @@ #include "os_type.h" -static char rsp[512] = ""; -const uint16_t rsplen = 512; -void build_well_known_rsp(void); +void build_well_known_rsp(char *rsp, uint16_t rsplen); void endpoint_setup(void) { coap_setup(); - build_well_known_rsp(); } static const coap_endpoint_path_t path_well_known_core = {2, {".well-known", "core"}}; static int handle_get_well_known_core(const coap_endpoint_t *ep, coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo) { - return coap_make_response(scratch, outpkt, (const uint8_t *)rsp, c_strlen(rsp), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT); + outpkt->content.p = (uint8_t *)c_zalloc(MAX_PAYLOAD_SIZE); // this should be free-ed when outpkt is built in coap_server_respond() + if(outpkt->content.p == NULL){ + NODE_DBG("not enough memory\n"); + return COAP_ERR_BUFFER_TOO_SMALL; + } + outpkt->content.len = MAX_PAYLOAD_SIZE; + build_well_known_rsp(outpkt->content.p, outpkt->content.len); + return coap_make_response(scratch, outpkt, (const uint8_t *)outpkt->content.p, c_strlen(outpkt->content.p), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT); } static const coap_endpoint_path_t path_variable = {2, {"v1", "v"}}; @@ -211,13 +216,13 @@ const coap_endpoint_t endpoints[] = {(coap_method_t)0, NULL, NULL, NULL, NULL} }; -void build_well_known_rsp(void) +void build_well_known_rsp(char *rsp, uint16_t rsplen) { const coap_endpoint_t *ep = endpoints; int i; uint16_t len = rsplen; - c_memset(rsp, 0, sizeof(rsp)); + c_memset(rsp, 0, len); len--; // Null-terminated string diff --git a/app/coap/pdu.c b/app/coap/pdu.c index 8313146c..e32f028d 100644 --- a/app/coap/pdu.c +++ b/app/coap/pdu.c @@ -24,6 +24,8 @@ coap_pdu_t * coap_new_pdu(void) { c_free(pdu); return NULL; } + pdu->pkt->content.p = NULL; + pdu->pkt->content.len = 0; pdu->msg.p = (uint8_t *)c_zalloc(MAX_REQUEST_SIZE+1); // +1 for string '\0' if(!pdu->msg.p){ diff --git a/app/include/user_modules.h b/app/include/user_modules.h index f90109f3..103b004f 100644 --- a/app/include/user_modules.h +++ b/app/include/user_modules.h @@ -27,7 +27,7 @@ #define LUA_USE_MODULES_OW #define LUA_USE_MODULES_BIT #define LUA_USE_MODULES_MQTT -// #define LUA_USE_MODULES_COAP // need about 1k more ram for now +#define LUA_USE_MODULES_COAP #define LUA_USE_MODULES_U8G #define LUA_USE_MODULES_WS2812 #endif /* LUA_USE_MODULES */ diff --git a/app/include/user_version.h b/app/include/user_version.h index ed2b0d6d..1576fbe3 100644 --- a/app/include/user_version.h +++ b/app/include/user_version.h @@ -7,6 +7,6 @@ #define NODE_VERSION_INTERNAL 0U #define NODE_VERSION "NodeMCU 0.9.5" -#define BUILD_DATE "build 20150311" +#define BUILD_DATE "build 20150315" #endif /* __USER_VERSION_H__ */ diff --git a/app/modules/coap.c b/app/modules/coap.c index 5a4a433d..8e1ba6c0 100644 --- a/app/modules/coap.c +++ b/app/modules/coap.c @@ -227,6 +227,8 @@ static void coap_response_handler(void *arg, char *pdata, unsigned short len) struct espconn *pesp_conn = arg; coap_packet_t pkt; + pkt.content.p = NULL; + pkt.content.len = 0; // static uint8_t buf[MAX_MESSAGE_SIZE+1] = {0}; // +1 for string '\0' uint8_t buf[MAX_MESSAGE_SIZE+1] = {0}; // +1 for string '\0' c_memset(buf, 0, sizeof(buf)); // wipe prev data @@ -421,7 +423,6 @@ static int coap_request( lua_State* L, coap_method_t m ) extern coap_luser_entry *variable_entry; extern coap_luser_entry *function_entry; -extern void build_well_known_rsp(void); // Lua: coap:var/func( string ) static int coap_regist( lua_State* L, const char* mt, int isvar ) { @@ -456,8 +457,6 @@ static int coap_regist( lua_State* L, const char* mt, int isvar ) h->L = L; h->name = name; - build_well_known_rsp(); // rebuild .well-known - NODE_DBG("coap_regist is called.\n"); return 0; }