From f5bf7c7be6ada46028cfa556510fd6743c049a25 Mon Sep 17 00:00:00 2001 From: DipSwitch Date: Tue, 22 Sep 2015 16:15:59 +0200 Subject: [PATCH 1/9] First changes --- Makefile | 23 +----- coap.c | 190 ++++++++++++++++++++++++++------------------------ coap.h | 33 ++++++++- endpoints.c | 113 ------------------------------ main-posix.c | 85 ---------------------- microcoap.ino | 99 -------------------------- 6 files changed, 129 insertions(+), 414 deletions(-) delete mode 100644 endpoints.c delete mode 100644 main-posix.c delete mode 100644 microcoap.ino diff --git a/Makefile b/Makefile index 19175d2..48422e9 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1 @@ -CFLAGS += -Wall -DDEBUG -# -DIPV6 -SRC = $(wildcard *.c) -OBJ = $(SRC:%.c=%.o) -DEPS = $(SRC:%.c=%.d) -EXEC = coap - -all: $(EXEC) - --include $(DEPS) - -$(EXEC): $(OBJ) - @$(CC) $(CFLAGS) -o $@ $^ - -%.o: %.c %.d - @$(CC) -c $(CFLAGS) -o $@ $< - -%.d: %.c - @$(CC) -MM $(CFLAGS) $< > $@ - -clean: - @$(RM) $(EXEC) $(OBJ) $(DEPS) +include $(RIOTBASE)/Makefile.base diff --git a/coap.c b/coap.c index 4d036f5..ce9fb63 100644 --- a/coap.c +++ b/coap.c @@ -9,7 +9,7 @@ extern void endpoint_setup(void); extern const coap_endpoint_t endpoints[]; -#ifdef DEBUG +#ifdef MICROCOAP_DEBUG void coap_dumpHeader(coap_header_t *hdr) { printf("Header:\n"); @@ -21,7 +21,7 @@ void coap_dumpHeader(coap_header_t *hdr) } #endif -#ifdef DEBUG +#ifdef MICROCOAP_DEBUG void coap_dump(const uint8_t *buf, size_t buflen, bool bare) { if (bare) @@ -43,9 +43,11 @@ int coap_parseHeader(coap_header_t *hdr, const uint8_t *buf, size_t buflen) { if (buflen < 4) return COAP_ERR_HEADER_TOO_SHORT; + hdr->ver = (buf[0] & 0xC0) >> 6; if (hdr->ver != 1) return COAP_ERR_VERSION_NOT_1; + hdr->t = (buf[0] & 0x30) >> 4; hdr->tkl = buf[0] & 0x0F; hdr->code = buf[1]; @@ -54,28 +56,29 @@ int coap_parseHeader(coap_header_t *hdr, const uint8_t *buf, size_t buflen) return 0; } -int coap_parseToken(coap_buffer_t *tokbuf, const coap_header_t *hdr, const uint8_t *buf, size_t buflen) +int coap_parseToken(coap_packet_t *pkt, const uint8_t *buf, size_t buflen) { - if (hdr->tkl == 0) + coap_buffer_t *tok = &(pkt->tok); + int toklen = pkt->hdr.tkl; + + if (!toklen) { - tokbuf->p = NULL; - tokbuf->len = 0; + pkt->tok.p = NULL; + pkt->tok.len = 0; + return 0; } - else - if (hdr->tkl <= 8) + else if (toklen <= 8) { - 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; + if (4U + toklen > buflen) // token to long actually + return COAP_ERR_TOKEN_TOO_SHORT; + + pkt->tok.p = buf + 4; // past header + pkt->tok.len = toklen; return 0; } else - { - // invalid size return COAP_ERR_TOKEN_TOO_SHORT; - } } // advances p @@ -100,8 +103,7 @@ int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8 delta = p[1] + 13; p++; } - else - if (delta == 14) + else if (delta == 14) { headlen += 2; if (buflen < headlen) @@ -109,8 +111,7 @@ int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8 delta = ((p[1] << 8) | p[2]) + 269; p+=2; } - else - if (delta == 15) + else if (delta == 15) return COAP_ERR_OPTION_DELTA_INVALID; if (len == 13) @@ -121,27 +122,24 @@ int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8 len = p[1] + 13; p++; } - else - if (len == 14) + else if (len == 14) { headlen += 2; if (buflen < headlen) return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER; + len = ((p[1] << 8) | p[2]) + 269; p+=2; } - else - if (len == 15) + else if (len == 15) return COAP_ERR_OPTION_LEN_INVALID; if ((p + 1 + len) > (*buf + buflen)) return COAP_ERR_OPTION_TOO_BIG; - //printf("option num=%d\n", delta + *running_delta); option->num = delta + *running_delta; option->buf.p = p+1; option->buf.len = len; - //coap_dump(p+1, len, false); // advance buf *buf = p + 1 + len; @@ -161,18 +159,17 @@ int coap_parseOptionsAndPayload(coap_option_t *options, uint8_t *numOptions, coa if (p > end) return COAP_ERR_OPTION_OVERRUNS_PACKET; // out of bounds - //coap_dump(p, end - p); - // 0xFF is payload marker while((optionIndex < *numOptions) && (p < end) && (*p != 0xFF)) { if (0 != (rc = coap_parseOption(&options[optionIndex], &delta, &p, end-p))) return rc; + optionIndex++; } *numOptions = optionIndex; - if (p+1 < end && *p == 0xFF) // payload marker + if ((p + 1) < end && *p == 0xFF) // payload marker { payload->p = p+1; payload->len = end-(p+1); @@ -186,7 +183,7 @@ int coap_parseOptionsAndPayload(coap_option_t *options, uint8_t *numOptions, coa return 0; } -#ifdef DEBUG +#ifdef MICROCOAP_DEBUG void coap_dumpOptions(coap_option_t *opts, size_t numopt) { size_t i; @@ -200,7 +197,7 @@ void coap_dumpOptions(coap_option_t *opts, size_t numopt) } #endif -#ifdef DEBUG +#ifdef MICROCOAP_DEBUG void coap_dumpPacket(coap_packet_t *pkt) { coap_dumpHeader(&pkt->hdr); @@ -215,18 +212,20 @@ int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen) { int rc; - // coap_dump(buf, buflen, false); - - if (0 != (rc = coap_parseHeader(&pkt->hdr, buf, buflen))) + rc = coap_parseHeader(&(pkt->hdr), buf, buflen); + if (rc) return rc; -// coap_dumpHeader(&hdr); - if (0 != (rc = coap_parseToken(&pkt->tok, &pkt->hdr, buf, buflen))) + + rc = coap_parseToken(pkt, buf, buflen); + if (rc) return rc; + pkt->numopts = MAXOPT; - if (0 != (rc = coap_parseOptionsAndPayload(pkt->opts, &(pkt->numopts), &(pkt->payload), &pkt->hdr, buf, buflen))) + rc = coap_parseOptionsAndPayload(pkt->opts, &(pkt->numopts), &(pkt->payload), &pkt->hdr, buf, buflen); + if (rc) return rc; -// coap_dumpOptions(opts, numopt); - return 0; + + return rc; } // options are always stored consecutively, so can return a block with same option num @@ -288,7 +287,7 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt) if (pkt->hdr.tkl > 0) memcpy(p, pkt->tok.p, pkt->hdr.tkl); - // // http://tools.ietf.org/html/rfc7252#section-3.1 + // http://tools.ietf.org/html/rfc7252#section-3.1 // inject options p += pkt->hdr.tkl; @@ -308,18 +307,17 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt) { *p++ = (optDelta - 13); } - else - if (delta == 14) + else if (delta == 14) { *p++ = ((optDelta-269) >> 8); *p++ = (0xFF & (optDelta-269)); } + if (len == 13) { *p++ = (pkt->opts[i].buf.len - 13); } - else - if (len == 14) + else if (len == 14) { *p++ = (pkt->opts[i].buf.len >> 8); *p++ = (0xFF & (pkt->opts[i].buf.len-269)); @@ -336,55 +334,57 @@ int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt) { if (*buflen < 4 + 1 + pkt->payload.len + opts_len) return COAP_ERR_BUFFER_TOO_SMALL; + buf[4 + opts_len] = 0xFF; // payload marker memcpy(buf+5 + opts_len, pkt->payload.p, pkt->payload.len); *buflen = opts_len + 5 + pkt->payload.len; } else *buflen = opts_len + 4; + return 0; } void coap_option_nibble(uint32_t value, uint8_t *nibble) { if (value<13) - { *nibble = (0xFF & value); - } - else - if (value<=0xFF+13) - { + else if (value<=0xFF+13) *nibble = 13; - } else if (value<=0xFFFF+269) - { + else if (value<=0xFFFF+269) *nibble = 14; - } } -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_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint8_t *content, size_t content_len, + const coap_packet_t *inpkt, coap_responsecode_t rspcode, + coap_content_type_t content_type, coap_msgtype_t msg_type) { pkt->hdr.ver = 0x01; - pkt->hdr.t = COAP_TYPE_ACK; + pkt->hdr.t = msg_type; pkt->hdr.tkl = 0; pkt->hdr.code = rspcode; - pkt->hdr.id[0] = msgid_hi; - pkt->hdr.id[1] = msgid_lo; - pkt->numopts = 1; + pkt->hdr.id[0] = inpkt->hdr.id[0]; + pkt->hdr.id[1] = inpkt->hdr.id[1]; // need token in response - if (tok) { - pkt->hdr.tkl = tok->len; - pkt->tok = *tok; - } + pkt->hdr.tkl = inpkt->tok.len; + pkt->tok = inpkt->tok; // safe because 1 < MAXOPT - pkt->opts[0].num = COAP_OPTION_CONTENT_FORMAT; - pkt->opts[0].buf.p = scratch->p; - if (scratch->len < 2) - return COAP_ERR_BUFFER_TOO_SMALL; - scratch->p[0] = ((uint16_t)content_type & 0xFF00) >> 8; - scratch->p[1] = ((uint16_t)content_type & 0x00FF); - pkt->opts[0].buf.len = 2; + if (content_type >= 0) { + pkt->numopts = 1; + + pkt->opts[0].num = COAP_OPTION_CONTENT_FORMAT; + pkt->opts[0].buf.p = scratch->p; + if (scratch->len < 2) + return COAP_ERR_BUFFER_TOO_SMALL; + scratch->p[0] = ((uint16_t)content_type & 0xFF00) >> 8; + scratch->p[1] = ((uint16_t)content_type & 0x00FF); + pkt->opts[0].buf.len = 2; + } else + pkt->numopts = 0; + + // set the payload pkt->payload.p = content; pkt->payload.len = content_len; return 0; @@ -394,39 +394,45 @@ int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint // it could more easily return 405 errors int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt) { + const coap_endpoint_t *ep = endpoints; const coap_option_t *opt; uint8_t count; int i; - const coap_endpoint_t *ep = endpoints; - while(NULL != ep->handler) + // special case, this is a ping message + if (inpkt->hdr.code == 0) { + coap_make_response(scratch, outpkt, NULL, 0, inpkt, COAP_RSPCODE_EMPTY, COAP_CONTENTTYPE_EMPTY, COAP_TYPE_RESET); + return 0; + } + + // search trough all the handles to find a response + for (ep = endpoints; ep->handler; ++ep) { + // check if the endpoint handles the request code if (ep->method != inpkt->hdr.code) - goto next; - if (NULL != (opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count))) - { - if (count != ep->path->count) - goto next; - for (i=0;ipath->elems[i])) - goto next; - if (0 != memcmp(ep->path->elems[i], opt[i].buf.p, opt[i].buf.len)) - goto next; - } - // match! - return ep->handler(scratch, inpkt, outpkt, inpkt->hdr.id[0], inpkt->hdr.id[1]); - } -next: - ep++; + continue; + + // get the URI path options + opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count); + if (!opt) + continue; + + // validate the path length + if (count != ep->path->count) + continue; + + // check if the strings match + int match = 1; + for (i = 0; match && i < count; ++i) + match = (strncmp(ep->path->elems[i], (char*)opt[i].buf.p, opt[i].buf.len) == 0); + + // if we have our endpoint handle it + if (match) + return ep->handler(scratch, inpkt, outpkt); } - coap_make_response(scratch, outpkt, NULL, 0, inpkt->hdr.id[0], inpkt->hdr.id[1], &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE); + // couldn't find the response0 + coap_make_response(scratch, outpkt, NULL, 0, inpkt, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE, COAP_TYPE_ACK); return 0; } - -void coap_setup(void) -{ -} - diff --git a/coap.h b/coap.h index 9090285..f83efcf 100644 --- a/coap.h +++ b/coap.h @@ -96,6 +96,7 @@ typedef enum #define MAKE_RSPCODE(clas, det) ((clas << 5) | (det)) typedef enum { + COAP_RSPCODE_EMPTY = MAKE_RSPCODE(0, 0), COAP_RSPCODE_CONTENT = MAKE_RSPCODE(2, 5), COAP_RSPCODE_NOT_FOUND = MAKE_RSPCODE(4, 4), COAP_RSPCODE_BAD_REQUEST = MAKE_RSPCODE(4, 0), @@ -105,6 +106,7 @@ typedef enum //http://tools.ietf.org/html/rfc7252#section-12.3 typedef enum { + COAP_CONTENTTYPE_EMPTY = -2, // bodge to allow us not to send an empty block COAP_CONTENTTYPE_NONE = -1, // bodge to allow us not to send option block COAP_CONTENTTYPE_TEXT_PLAIN = 0, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT = 40, @@ -130,8 +132,13 @@ typedef enum /////////////////////// -typedef int (*coap_endpoint_func)(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo); +typedef int (*coap_endpoint_func)(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt); +/* To increase COAP_MAX_SEGMENTS, set CFLAGS to -DCOAP_MAX_SEGMENTS=. */ +#ifndef COAP_MAX_SEGMENTS #define MAX_SEGMENTS 2 // 2 = /foo/bar, 3 = /foo/bar/baz +#else +#define MAX_SEGMENTS (COAP_MAX_SEGMENTS) +#endif typedef struct { int count; @@ -154,16 +161,36 @@ typedef struct /////////////////////// +#ifdef MICROCOAP_DEBUG void coap_dumpPacket(coap_packet_t *pkt); +#else +#define coap_dumpPacket(pkt) +#endif + +#ifdef MICROCOAP_DEBUG +void coap_dump(const uint8_t *buf, size_t buflen, bool bare); +#else +#define coap_dump(buf, buflen, bare) +#endif + int coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen); + int coap_buffer_to_string(char *strbuf, size_t strbuflen, const coap_buffer_t *buf); + const coap_option_t *coap_findOptions(const coap_packet_t *pkt, uint8_t num, uint8_t *count); + 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_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint8_t *content, size_t content_len, + const coap_packet_t *inpkt, coap_responsecode_t rspcode, + coap_content_type_t content_type, coap_msgtype_t msg_type); + int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt); + void coap_option_nibble(uint32_t value, uint8_t *nibble); + void coap_setup(void); + void endpoint_setup(void); #ifdef __cplusplus diff --git a/endpoints.c b/endpoints.c deleted file mode 100644 index ccc961b..0000000 --- a/endpoints.c +++ /dev/null @@ -1,113 +0,0 @@ -#include -#include -#include "coap.h" - -static char light = '0'; - -const uint16_t rsplen = 1500; -static char rsp[1500] = ""; -void build_rsp(void); - -#ifdef ARDUINO -#include "Arduino.h" -static int led = 6; -void endpoint_setup(void) -{ - pinMode(led, OUTPUT); - build_rsp(); -} -#else -#include -void endpoint_setup(void) -{ - build_rsp(); -} -#endif - -static const coap_endpoint_path_t path_well_known_core = {2, {".well-known", "core"}}; -static int handle_get_well_known_core(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, strlen(rsp), id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT); -} - -static const coap_endpoint_path_t path_light = {1, {"light"}}; -static int handle_get_light(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 *)&light, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN); -} - -static int handle_put_light(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo) -{ - if (inpkt->payload.len == 0) - return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_BAD_REQUEST, COAP_CONTENTTYPE_TEXT_PLAIN); - if (inpkt->payload.p[0] == '1') - { - light = '1'; -#ifdef ARDUINO - digitalWrite(led, HIGH); -#else - printf("ON\n"); -#endif - return coap_make_response(scratch, outpkt, (const uint8_t *)&light, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN); - } - else - { - light = '0'; -#ifdef ARDUINO - digitalWrite(led, LOW); -#else - printf("OFF\n"); -#endif - return coap_make_response(scratch, outpkt, (const uint8_t *)&light, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN); - } -} - -const coap_endpoint_t endpoints[] = -{ - {COAP_METHOD_GET, handle_get_well_known_core, &path_well_known_core, "ct=40"}, - {COAP_METHOD_GET, handle_get_light, &path_light, "ct=0"}, - {COAP_METHOD_PUT, handle_put_light, &path_light, NULL}, - {(coap_method_t)0, NULL, NULL, NULL} -}; - -void build_rsp(void) -{ - uint16_t len = rsplen; - const coap_endpoint_t *ep = endpoints; - int i; - - len--; // Null-terminated string - - while(NULL != ep->handler) - { - if (NULL == ep->core_attr) { - ep++; - continue; - } - - if (0 < strlen(rsp)) { - strncat(rsp, ",", len); - len--; - } - - strncat(rsp, "<", len); - len--; - - for (i = 0; i < ep->path->count; i++) { - strncat(rsp, "/", len); - len--; - - strncat(rsp, ep->path->elems[i], len); - len -= strlen(ep->path->elems[i]); - } - - strncat(rsp, ">;", len); - len -= 2; - - strncat(rsp, ep->core_attr, len); - len -= strlen(ep->core_attr); - - ep++; - } -} - diff --git a/main-posix.c b/main-posix.c deleted file mode 100644 index 3711b02..0000000 --- a/main-posix.c +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include -#include -#include -#include - -#include "coap.h" - -#define PORT 5683 - -int main(int argc, char **argv) -{ - int fd; -#ifdef IPV6 - struct sockaddr_in6 servaddr, cliaddr; -#else /* IPV6 */ - struct sockaddr_in servaddr, cliaddr; -#endif /* IPV6 */ - uint8_t buf[4096]; - uint8_t scratch_raw[4096]; - coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)}; - -#ifdef IPV6 - fd = socket(AF_INET6,SOCK_DGRAM,0); -#else /* IPV6 */ - fd = socket(AF_INET,SOCK_DGRAM,0); -#endif /* IPV6 */ - - bzero(&servaddr,sizeof(servaddr)); -#ifdef IPV6 - servaddr.sin6_family = AF_INET6; - servaddr.sin6_addr = in6addr_any; - servaddr.sin6_port = htons(PORT); -#else /* IPV6 */ - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htonl(INADDR_ANY); - servaddr.sin_port = htons(PORT); -#endif /* IPV6 */ - bind(fd,(struct sockaddr *)&servaddr, sizeof(servaddr)); - - endpoint_setup(); - - while(1) - { - int n, rc; - socklen_t len = sizeof(cliaddr); - coap_packet_t pkt; - - n = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&cliaddr, &len); -#ifdef DEBUG - printf("Received: "); - coap_dump(buf, n, true); - printf("\n"); -#endif - - if (0 != (rc = coap_parse(&pkt, buf, n))) - printf("Bad packet rc=%d\n", rc); - else - { - size_t rsplen = sizeof(buf); - coap_packet_t rsppkt; -#ifdef DEBUG - coap_dumpPacket(&pkt); -#endif - coap_handle_req(&scratch_buf, &pkt, &rsppkt); - - if (0 != (rc = coap_build(buf, &rsplen, &rsppkt))) - printf("coap_build failed rc=%d\n", rc); - else - { -#ifdef DEBUG - printf("Sending: "); - coap_dump(buf, rsplen, true); - printf("\n"); -#endif -#ifdef DEBUG - coap_dumpPacket(&rsppkt); -#endif - - sendto(fd, buf, rsplen, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr)); - } - } - } -} - diff --git a/microcoap.ino b/microcoap.ino deleted file mode 100644 index 148b6ce..0000000 --- a/microcoap.ino +++ /dev/null @@ -1,99 +0,0 @@ -/* -* WARNING - UDP_TX_PACKET_MAX_SIZE is hardcoded by Arduino to 24 bytes -* This limits the size of possible outbound UDP packets -*/ - -#include -#include -#include -#include -#include "coap.h" - -#define PORT 5683 -static uint8_t mac[] = {0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02}; - -EthernetClient client; -EthernetUDP udp; -uint8_t packetbuf[256]; -static uint8_t scratch_raw[32]; -static coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)}; - -void setup() -{ - int i; - Serial.begin(9600); - while (!Serial) - { - ; // wait for serial port to connect. Needed for Leonardo only - } - - // start the Ethernet connection: - if (Ethernet.begin(mac) == 0) - { - Serial.println("Failed to configure Ethernet using DHCP"); - while(1); - } - Serial.print("My IP address: "); - for (i=0;i<4;i++) - { - Serial.print(Ethernet.localIP()[i], DEC); - Serial.print("."); - } - Serial.println(); - udp.begin(PORT); - - coap_setup(); - endpoint_setup(); -} - -void udp_send(const uint8_t *buf, int buflen) -{ - udp.beginPacket(udp.remoteIP(), udp.remotePort()); - while(buflen--) - udp.write(*buf++); - udp.endPacket(); -} - -void loop() -{ - int sz; - int rc; - coap_packet_t pkt; - int i; - - if ((sz = udp.parsePacket()) > 0) - { - udp.read(packetbuf, sizeof(packetbuf)); - - for (i=0;ibuf.p); + uint8_t size = 2 << (blk->szx + 3); + + (void) size; + + return 0; +} + // FIXME, if this looked in the table at the path before the method then // it could more easily return 405 errors int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt) @@ -413,10 +440,22 @@ int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_ // special case, this is a ping message if (inpkt->hdr.code == 0) { - coap_make_response(scratch, outpkt, NULL, 0, inpkt, COAP_RSPCODE_EMPTY, COAP_CONTENTTYPE_EMPTY, COAP_TYPE_RESET); + coap_make_response(scratch, outpkt, NULL, 0, inpkt, COAP_RSPCODE_EMPTY, COAP_CONTENTTYPE_NONE, COAP_TYPE_RESET); return 0; } + // special case, if this is a get of .well-known.core + if (inpkt->hdr.code == COAP_METHOD_GET) { + opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count); + if (opt && count == 2) { +#define STAT_STR(str) #str, (sizeof(#str) - 1) + if (!strncmp((char*)opt[0].buf.p, STAT_STR(.well-known)) + && !strncmp((char*)opt[1].buf.p, STAT_STR(core))) + return coap_send_endpoint_list(scratch, inpkt, outpkt); +#undef STAT_STR + } + } + // search trough all the handles to find a response for (ep = endpoints; ep->handler; ++ep) { diff --git a/coap.h b/coap.h index cb3a9d2..d757f49 100644 --- a/coap.h +++ b/coap.h @@ -21,7 +21,6 @@ typedef struct * client error response (4.xx), or rever error response (5.xx) * For possible values, see http://tools.ietf.org/html/rfc7252#section-12.1 */ uint16_t id; - //uint8_t id[2]; } coap_header_t; typedef struct @@ -70,6 +69,8 @@ typedef enum COAP_OPTION_URI_QUERY = 15, COAP_OPTION_ACCEPT = 17, COAP_OPTION_LOCATION_QUERY = 20, + COAP_OPTION_BLOCK2 = 23, + //COAP_OPTION_BLOCK1 = 23, COAP_OPTION_PROXY_URI = 35, COAP_OPTION_PROXY_SCHEME = 39 } coap_option_num_t; @@ -107,8 +108,7 @@ typedef enum //http://tools.ietf.org/html/rfc7252#section-12.3 typedef enum { - COAP_CONTENTTYPE_EMPTY = -2, // bodge to allow us not to send an empty block - COAP_CONTENTTYPE_NONE = -1, // bodge to allow us not to send option block + COAP_CONTENTTYPE_NONE = -1, // bogus to allow us not to send option block COAP_CONTENTTYPE_TEXT_PLAIN = 0, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT = 40, } coap_content_type_t; From 777f4ff07f9f689cc1c3aea2ab32d705fc1391b5 Mon Sep 17 00:00:00 2001 From: DipSwitch Date: Wed, 23 Sep 2015 11:28:26 +0200 Subject: [PATCH 4/9] block2 implementation finished, native .well-known.core support whitout fixed buffer --- coap.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- coap.h | 39 ++++++++++++++----- 2 files changed, 140 insertions(+), 15 deletions(-) diff --git a/coap.c b/coap.c index 28f2738..c454640 100644 --- a/coap.c +++ b/coap.c @@ -367,6 +367,19 @@ void coap_option_nibble(uint32_t value, uint8_t *nibble) *nibble = 14; } +int coap_add_option(coap_packet_t *pkt, uint8_t num, const void *p, size_t len) +{ + if (pkt->numopts == MAXOPT) { + return 1; + } + + coap_option_t *opt = &pkt->opts[pkt->numopts++]; + opt->num = num; + opt->buf.p = p; + opt->buf.len = len; + return 0; +} + int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint8_t *content, size_t content_len, const coap_packet_t *inpkt, coap_responsecode_t rspcode, coap_content_type_t content_type, coap_msgtype_t msg_type) @@ -411,20 +424,113 @@ int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpk { uint8_t count; const coap_option_t *opt; - uint8_t block[128]; (void) scratch; (void) outpkt; - (void) block; + // find the block option opt = coap_findOptions(inpkt, COAP_OPTION_BLOCK2, &count); if (!opt || count != 1) return COAP_ERR_OPTION_LEN_INVALID; + // decode the block request option coap_opt_block2_t *blk = (coap_opt_block2_t*)(opt->buf.p); - uint8_t size = 2 << (blk->szx + 3); + int size = 2 << (blk->szx + 3); + int offset = size * blk->num; + int copy = 0; + uint8_t buffer[size]; + + if (offset) { + puts("ohai"); + } + +#define BUF_TAKE(x) if (spc_left <= 0) break; \ + spc_left -= (x); \ + copy = spc_left >= 0 ? (x) : (x) + spc_left + +#define OFF_TAKE(x) (offset <= 0 \ + || ((offset -= (x)) < 0 \ + && (offset = (x) + offset) >= 0)) + +#define CLR_OFFSET() offset -= offset + + // get offset in application/link-format + int spc_left = size; + uint8_t *buf = buffer; + const coap_endpoint_t *ep = endpoints; + for (ep = endpoints; ep && ep->handler; ++ep) + { + if (ep->core_attr < 0) + continue; + + if (ep != endpoints) { + if (OFF_TAKE(1)) { + BUF_TAKE(1); + *buf++ = ','; + } + } + + if (OFF_TAKE(1)) { + BUF_TAKE(1); + *buf++ = '<'; + } + + for (int idx = 0; idx < ep->path->count; ++idx) { + if (OFF_TAKE(1)) { + BUF_TAKE(1); + *buf++ = '/'; + } + + if (OFF_TAKE(ep->path->elems[idx].len)) { + BUF_TAKE(ep->path->elems[idx].len - offset); + + memcpy(buf, ep->path->elems[idx].str + offset, copy); + buf += copy; + CLR_OFFSET(); + } + } + + if (OFF_TAKE(1)) { + BUF_TAKE(1); + *buf++ = '>'; + } + + if (OFF_TAKE(1)) { + BUF_TAKE(1); + *buf++ = ';'; + } + + if (OFF_TAKE(3)) { + BUF_TAKE(3); + memcpy(buf, "ct=" + offset, copy); + buf += copy; + CLR_OFFSET(); + } + + if (ep->core_attr) { + if (OFF_TAKE(1)) { + BUF_TAKE(1); + *buf++ = '0' + (ep->core_attr / 10); + } + + if (OFF_TAKE(1)) { + BUF_TAKE(1); + *buf++ = '0' + (ep->core_attr % 10); + } + } else { + if (OFF_TAKE(1)) { + BUF_TAKE(1); + *buf++ = '0'; + } + } + } + +#undef BUF_TAKE + + coap_make_response(scratch, outpkt, buffer, spc_left >= 0 ? size - spc_left : size, inpkt, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT, COAP_TYPE_ACK); - (void) size; + blk->more = (spc_left <= 0); + coap_add_option(outpkt, COAP_OPTION_BLOCK2, blk, sizeof(coap_opt_block2_t)); return 0; } @@ -475,7 +581,7 @@ int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_ // check if the strings match int match = 1; for (i = 0; match && i < count; ++i) - match = (strncmp(ep->path->elems[i], (char*)opt[i].buf.p, opt[i].buf.len) == 0); + match = (strncmp(ep->path->elems[i].str, (char*)opt[i].buf.p, opt[i].buf.len) == 0); // if we have our endpoint handle it if (match) diff --git a/coap.h b/coap.h index d757f49..627b29b 100644 --- a/coap.h +++ b/coap.h @@ -108,9 +108,13 @@ typedef enum //http://tools.ietf.org/html/rfc7252#section-12.3 typedef enum { - COAP_CONTENTTYPE_NONE = -1, // bogus to allow us not to send option block - COAP_CONTENTTYPE_TEXT_PLAIN = 0, - COAP_CONTENTTYPE_APPLICATION_LINKFORMAT = 40, + COAP_CONTENTTYPE_NONE = -1, // bogus to allow us not to send option block + COAP_CONTENTTYPE_TEXT_PLAIN = 0, + COAP_CONTENTTYPE_APPLICATION_LINKFORMAT = 40, + COAP_CONTENTTYPE_APPLICATION_XML = 41, + COAP_CONTENTTYPE_APPLICATION_OCT_STREAM = 42, + COAP_CONTENTTYPE_APPLICATION_EXI = 47, + COAP_CONTENTTYPE_APPLICATION_JSON = 50 } coap_content_type_t; /////////////////////// @@ -140,10 +144,28 @@ typedef int (*coap_endpoint_func)(coap_rw_buffer_t *scratch, const coap_packet_t #else #define MAX_SEGMENTS (COAP_MAX_SEGMENTS) #endif +typedef struct +{ + uint8_t len; + const char *str; +} coap_path_element_t; + +#if MAX_SEGMENTS >= 1 +# define PATH_ELEMENT1(str1) { 1, { { sizeof(#str1) - 1, #str1 } } } +#endif + +#if MAX_SEGMENTS >= 2 +# define PATH_ELEMENT2(str1, str2) { 2, { { sizeof(#str1) - 1, #str1 }, { sizeof(#str2) - 1, #str2 } } } +#endif + +#if MAX_SEGMENTS >= 3 +# define PATH_ELEMENT3(str1, str2, str3) { 3, { { sizeof(#str1) - 1, #str1 }, { sizeof(#str2) - 1, #str2 }, { sizeof(#str3) - 1, #str3 } } } +#endif + typedef struct { int count; - const char *elems[MAX_SEGMENTS]; + coap_path_element_t elems[MAX_SEGMENTS]; } coap_endpoint_path_t; typedef struct @@ -152,15 +174,14 @@ typedef struct 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.: + const coap_endpoint_path_t *path; /* path towards a resource (i.e. foo/bar/) */ + coap_content_type_t 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_endpoint_t; - /////////////////////// #ifdef MICROCOAP_DEBUG void coap_dumpPacket(coap_packet_t *pkt); @@ -190,9 +211,7 @@ int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_ void coap_option_nibble(uint32_t value, uint8_t *nibble); -void coap_setup(void); - -void endpoint_setup(void); +int coap_add_option(coap_packet_t *pkt, uint8_t num, const void *p, size_t len); #ifdef __cplusplus } From 35ffb6762e45e40453fbaaf05a3ced1977a18833 Mon Sep 17 00:00:00 2001 From: DipSwitch Date: Thu, 24 Sep 2015 09:10:40 +0200 Subject: [PATCH 5/9] extend block functionality --- coap.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++---------- coap.h | 17 ++++++++++---- 2 files changed, 72 insertions(+), 17 deletions(-) diff --git a/coap.c b/coap.c index c454640..faf0af9 100644 --- a/coap.c +++ b/coap.c @@ -420,6 +420,13 @@ typedef struct __attribute__((packed)) { uint8_t num : 4; } coap_opt_block2_t; +typedef struct __attribute__((packed)) { + uint8_t szx : 3; + uint8_t more : 1; + uint8_t num1 : 4; + uint8_t num2 : 8; +} coap_opt_block2_lng_t; + int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt) { uint8_t count; @@ -434,16 +441,21 @@ int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpk return COAP_ERR_OPTION_LEN_INVALID; // decode the block request option - coap_opt_block2_t *blk = (coap_opt_block2_t*)(opt->buf.p); - int size = 2 << (blk->szx + 3); - int offset = size * blk->num; - int copy = 0; - uint8_t buffer[size]; - - if (offset) { - puts("ohai"); + int size, offset, copy = 0; + if (opt->buf.len == 1) { + coap_opt_block2_t *blk = (coap_opt_block2_t*)(opt->buf.p); + size = 2 << (blk->szx + 3); + offset = size * blk->num; + } + else if (opt->buf.len == 2) { + coap_opt_block2_lng_t *blk = (coap_opt_block2_lng_t*)(opt->buf.p); + size = 2 << (blk->szx + 3); + uint16_t num = ((uint16_t)blk->num1) | (((uint16_t)blk->num2) << 8); + offset = size * num; } + uint8_t buffer[size]; + #define BUF_TAKE(x) if (spc_left <= 0) break; \ spc_left -= (x); \ copy = spc_left >= 0 ? (x) : (x) + spc_left @@ -500,6 +512,36 @@ int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpk *buf++ = ';'; } + if (OFF_TAKE(6)) { + BUF_TAKE(6); + memcpy(buf, "title=" + offset, copy); + buf += copy; + CLR_OFFSET(); + } + + if (OFF_TAKE(1)) { + BUF_TAKE(1); + *buf++ = '"'; + } + + if (OFF_TAKE(ep->path->title.len)) { + BUF_TAKE(ep->path->title.len - offset); + + memcpy(buf, ep->path->title.str + offset, copy); + buf += copy; + CLR_OFFSET(); + } + + if (OFF_TAKE(1)) { + BUF_TAKE(1); + *buf++ = '"'; + } + + if (OFF_TAKE(1)) { + BUF_TAKE(1); + *buf++ = ';'; + } + if (OFF_TAKE(3)) { BUF_TAKE(3); memcpy(buf, "ct=" + offset, copy); @@ -529,8 +571,16 @@ int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpk coap_make_response(scratch, outpkt, buffer, spc_left >= 0 ? size - spc_left : size, inpkt, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT, COAP_TYPE_ACK); - blk->more = (spc_left <= 0); - coap_add_option(outpkt, COAP_OPTION_BLOCK2, blk, sizeof(coap_opt_block2_t)); + if (opt->buf.len == 1) { + coap_opt_block2_t *blk = (coap_opt_block2_t*)(opt->buf.p); + blk->more = (spc_left <= 0); + coap_add_option(outpkt, COAP_OPTION_BLOCK2, blk, sizeof(coap_opt_block2_t)); + } + else if (opt->buf.len == 2) { + coap_opt_block2_lng_t *blk = (coap_opt_block2_lng_t*)(opt->buf.p); + blk->more = (spc_left <= 0); + coap_add_option(outpkt, COAP_OPTION_BLOCK2, blk, sizeof(coap_opt_block2_t)); + } return 0; } @@ -554,11 +604,9 @@ int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_ if (inpkt->hdr.code == COAP_METHOD_GET) { opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count); if (opt && count == 2) { -#define STAT_STR(str) #str, (sizeof(#str) - 1) if (!strncmp((char*)opt[0].buf.p, STAT_STR(.well-known)) && !strncmp((char*)opt[1].buf.p, STAT_STR(core))) return coap_send_endpoint_list(scratch, inpkt, outpkt); -#undef STAT_STR } } diff --git a/coap.h b/coap.h index 627b29b..f6a63d2 100644 --- a/coap.h +++ b/coap.h @@ -144,18 +144,24 @@ typedef int (*coap_endpoint_func)(coap_rw_buffer_t *scratch, const coap_packet_t #else #define MAX_SEGMENTS (COAP_MAX_SEGMENTS) #endif + +#define COAP_MAX_DYN_STR_LEN 15 + typedef struct { - uint8_t len; const char *str; -} coap_path_element_t; + uint8_t len; +} coap_str_element_t; + +#define STAT_STR(str) #str, sizeof(#str) - 1 +#define STAT_STR_EL(str) { STAT_STR(str) } #if MAX_SEGMENTS >= 1 -# define PATH_ELEMENT1(str1) { 1, { { sizeof(#str1) - 1, #str1 } } } +# define PATH_ELEMENT(title, str) { 1, STAT_STR_EL(title) { STAT_STR_EL(str) } } #endif #if MAX_SEGMENTS >= 2 -# define PATH_ELEMENT2(str1, str2) { 2, { { sizeof(#str1) - 1, #str1 }, { sizeof(#str2) - 1, #str2 } } } +# define PATH_ELEMENT2(title, str1, str2) { 2, STAT_STR_EL(title), { STAT_STR_EL(str1), STAT_STR_EL(str2) } } #endif #if MAX_SEGMENTS >= 3 @@ -165,7 +171,8 @@ typedef struct typedef struct { int count; - coap_path_element_t elems[MAX_SEGMENTS]; + coap_str_element_t title; + coap_str_element_t elems[MAX_SEGMENTS]; } coap_endpoint_path_t; typedef struct From d5b1117bd66ff84a709450d930e5a4cf2333b918 Mon Sep 17 00:00:00 2001 From: DipSwitch Date: Fri, 25 Sep 2015 17:54:22 +0200 Subject: [PATCH 6/9] improve server support --- coap.c | 46 ++++++++++++++++++++++++++++++---------------- coap.h | 10 ++++++---- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/coap.c b/coap.c index faf0af9..906aebb 100644 --- a/coap.c +++ b/coap.c @@ -8,6 +8,27 @@ extern const coap_endpoint_t endpoints[]; +typedef struct __attribute__((packed)) { + uint8_t szx : 3; + uint8_t more : 1; + uint8_t num : 4; +} coap_opt_block2_t; + +typedef struct __attribute__((packed)) { + uint8_t num2 : 8; + uint8_t szx : 3; + uint8_t more : 1; + uint8_t num1 : 4; +} coap_opt_block2_lng_t; + +typedef struct __attribute__((packed)) { + uint8_t num3 : 8; + uint8_t num2 : 8; + uint8_t szx : 3; + uint8_t more : 1; + uint8_t num1 : 4; +} coap_opt_block3_lng_t; + typedef union { uint8_t raw; struct { @@ -414,19 +435,6 @@ int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint return 0; } -typedef struct __attribute__((packed)) { - uint8_t szx : 3; - uint8_t more : 1; - uint8_t num : 4; -} coap_opt_block2_t; - -typedef struct __attribute__((packed)) { - uint8_t szx : 3; - uint8_t more : 1; - uint8_t num1 : 4; - uint8_t num2 : 8; -} coap_opt_block2_lng_t; - int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt) { uint8_t count; @@ -450,7 +458,13 @@ int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpk else if (opt->buf.len == 2) { coap_opt_block2_lng_t *blk = (coap_opt_block2_lng_t*)(opt->buf.p); size = 2 << (blk->szx + 3); - uint16_t num = ((uint16_t)blk->num1) | (((uint16_t)blk->num2) << 8); + uint16_t num = ((uint16_t)blk->num1) | (((uint16_t)blk->num2) << 4); + offset = size * num; + } + else if (opt->buf.len == 3) { + coap_opt_block3_lng_t *blk = (coap_opt_block3_lng_t*)(opt->buf.p); + size = 2 << (blk->szx + 3); + uint32_t num = ((uint32_t)blk->num1) | (((uint32_t)blk->num2) << 4) | (((uint32_t)blk->num3) << 12); offset = size * num; } @@ -579,7 +593,7 @@ int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpk else if (opt->buf.len == 2) { coap_opt_block2_lng_t *blk = (coap_opt_block2_lng_t*)(opt->buf.p); blk->more = (spc_left <= 0); - coap_add_option(outpkt, COAP_OPTION_BLOCK2, blk, sizeof(coap_opt_block2_t)); + coap_add_option(outpkt, COAP_OPTION_BLOCK2, blk, sizeof(coap_opt_block2_lng_t)); } return 0; @@ -614,7 +628,7 @@ int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_ for (ep = endpoints; ep->handler; ++ep) { // check if the endpoint handles the request code - if (ep->method != inpkt->hdr.code) + if (!(ep->method & (1 << (inpkt->hdr.code - 1)))) continue; // get the URI path options diff --git a/coap.h b/coap.h index f6a63d2..ce4719d 100644 --- a/coap.h +++ b/coap.h @@ -78,10 +78,12 @@ typedef enum //http://tools.ietf.org/html/rfc7252#section-12.1.1 typedef enum { - COAP_METHOD_GET = 1, - COAP_METHOD_POST = 2, - COAP_METHOD_PUT = 3, - COAP_METHOD_DELETE = 4 + COAP_METHOD_GET = (1 << 0), + COAP_METHOD_POST = (1 << 1), + COAP_METHOD_PUT = (1 << 2), + COAP_METHOD_DELETE = (1 << 3), + + COAP_METHOD_ALL = (COAP_METHOD_GET | COAP_METHOD_POST | COAP_METHOD_PUT | COAP_METHOD_DELETE) } coap_method_t; //http://tools.ietf.org/html/rfc7252#section-12.1.1 From 14d609617a96160844ce828679b385b51d5215f0 Mon Sep 17 00:00:00 2001 From: DipSwitch Date: Wed, 21 Oct 2015 12:04:33 +0200 Subject: [PATCH 7/9] changes for CoAP and block support etc. --- coap.c | 121 ++++++++++++++++++++++++++++++++++----------------------- coap.h | 37 +++++++++++++++--- 2 files changed, 105 insertions(+), 53 deletions(-) diff --git a/coap.c b/coap.c index 906aebb..3998e1f 100644 --- a/coap.c +++ b/coap.c @@ -435,6 +435,18 @@ int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint return 0; } +static uint8_t _default_blksize_buffer[2] = { + ((64 >> 2) - 6) +}; + +static const coap_option_t _default_blksize = { + COAP_OPTION_BLOCK2, + { + _default_blksize_buffer, + 1 + } +}; + int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt) { uint8_t count; @@ -445,27 +457,32 @@ int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpk // find the block option opt = coap_findOptions(inpkt, COAP_OPTION_BLOCK2, &count); - if (!opt || count != 1) - return COAP_ERR_OPTION_LEN_INVALID; + if (!opt) { + count = 1; + opt = &_default_blksize; + } // decode the block request option - int size, offset, copy = 0; - if (opt->buf.len == 1) { - coap_opt_block2_t *blk = (coap_opt_block2_t*)(opt->buf.p); - size = 2 << (blk->szx + 3); - offset = size * blk->num; - } - else if (opt->buf.len == 2) { - coap_opt_block2_lng_t *blk = (coap_opt_block2_lng_t*)(opt->buf.p); - size = 2 << (blk->szx + 3); - uint16_t num = ((uint16_t)blk->num1) | (((uint16_t)blk->num2) << 4); - offset = size * num; - } - else if (opt->buf.len == 3) { - coap_opt_block3_lng_t *blk = (coap_opt_block3_lng_t*)(opt->buf.p); - size = 2 << (blk->szx + 3); - uint32_t num = ((uint32_t)blk->num1) | (((uint32_t)blk->num2) << 4) | (((uint32_t)blk->num3) << 12); - offset = size * num; + int size = 4096, offset = 0, copy = 0; + if (opt) + { + if (opt->buf.len == 1) { + coap_opt_block2_t *blk = (coap_opt_block2_t*)(opt->buf.p); + size = 2 << (blk->szx + 3); + offset = size * blk->num; + } + else if (opt->buf.len == 2) { + coap_opt_block2_lng_t *blk = (coap_opt_block2_lng_t*)(opt->buf.p); + size = 2 << (blk->szx + 3); + uint16_t num = ((uint16_t)blk->num1) | (((uint16_t)blk->num2) << 4); + offset = size * num; + } + else if (opt->buf.len == 3) { + coap_opt_block3_lng_t *blk = (coap_opt_block3_lng_t*)(opt->buf.p); + size = 2 << (blk->szx + 3); + uint32_t num = ((uint32_t)blk->num1) | (((uint32_t)blk->num2) << 4) | (((uint32_t)blk->num3) << 12); + offset = size * num; + } } uint8_t buffer[size]; @@ -585,20 +602,30 @@ int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpk coap_make_response(scratch, outpkt, buffer, spc_left >= 0 ? size - spc_left : size, inpkt, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT, COAP_TYPE_ACK); - if (opt->buf.len == 1) { - coap_opt_block2_t *blk = (coap_opt_block2_t*)(opt->buf.p); - blk->more = (spc_left <= 0); - coap_add_option(outpkt, COAP_OPTION_BLOCK2, blk, sizeof(coap_opt_block2_t)); - } - else if (opt->buf.len == 2) { - coap_opt_block2_lng_t *blk = (coap_opt_block2_lng_t*)(opt->buf.p); - blk->more = (spc_left <= 0); - coap_add_option(outpkt, COAP_OPTION_BLOCK2, blk, sizeof(coap_opt_block2_lng_t)); + if (opt) + { + if (opt->buf.len == 1) { + coap_opt_block2_t *blk = (coap_opt_block2_t*)(opt->buf.p); + blk->more = (spc_left <= 0); + coap_add_option(outpkt, COAP_OPTION_BLOCK2, blk, sizeof(coap_opt_block2_t)); + } + else if (opt->buf.len == 2) { + coap_opt_block2_lng_t *blk = (coap_opt_block2_lng_t*)(opt->buf.p); + blk->more = (spc_left <= 0); + coap_add_option(outpkt, COAP_OPTION_BLOCK2, blk, sizeof(coap_opt_block2_lng_t)); + } + else if (opt->buf.len == 3) { + coap_opt_block3_lng_t *blk = (coap_opt_block3_lng_t*)(opt->buf.p); + blk->more = (spc_left <= 0); + coap_add_option(outpkt, COAP_OPTION_BLOCK2, blk, sizeof(coap_opt_block3_lng_t)); + } } return 0; } +#define _COAP_HEADER_TO_METHOD(x) (1 << (x - 1)) + // FIXME, if this looked in the table at the path before the method then // it could more easily return 405 errors int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt) @@ -614,28 +641,19 @@ int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_ return 0; } + // get the URI-Path + opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count); + // special case, if this is a get of .well-known.core - if (inpkt->hdr.code == COAP_METHOD_GET) { - opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count); - if (opt && count == 2) { - if (!strncmp((char*)opt[0].buf.p, STAT_STR(.well-known)) - && !strncmp((char*)opt[1].buf.p, STAT_STR(core))) - return coap_send_endpoint_list(scratch, inpkt, outpkt); - } + if (opt && count == 2 && inpkt->hdr.code == COAP_METHOD_GET) { + if (!strncmp((char*)opt[0].buf.p, STAT_STR(.well-known)) + && !strncmp((char*)opt[1].buf.p, STAT_STR(core))) + return coap_send_endpoint_list(scratch, inpkt, outpkt); } // search trough all the handles to find a response for (ep = endpoints; ep->handler; ++ep) { - // check if the endpoint handles the request code - if (!(ep->method & (1 << (inpkt->hdr.code - 1)))) - continue; - - // get the URI path options - opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count); - if (!opt) - continue; - // validate the path length if (count != ep->path->count) continue; @@ -646,12 +664,19 @@ int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_ match = (strncmp(ep->path->elems[i].str, (char*)opt[i].buf.p, opt[i].buf.len) == 0); // if we have our endpoint handle it - if (match) - return ep->handler(scratch, inpkt, outpkt); + if (!match) + continue; + + // check if the endpoint handles the request code + if (ep->method & _COAP_HEADER_TO_METHOD(inpkt->hdr.code)) + return ep->handler(scratch, inpkt, outpkt, _COAP_HEADER_TO_METHOD(inpkt->hdr.code), ep); + + // method not supported + coap_make_response(scratch, outpkt, NULL, 0, inpkt, COAP_RSPCODE_METHOD_NOT_ALLOWED, COAP_CONTENTTYPE_NONE, COAP_TYPE_ACK); + return 0; } - // couldn't find the response0 + // couldn't find the response coap_make_response(scratch, outpkt, NULL, 0, inpkt, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE, COAP_TYPE_ACK); - return 0; } diff --git a/coap.h b/coap.h index ce4719d..835ffc1 100644 --- a/coap.h +++ b/coap.h @@ -101,17 +101,41 @@ typedef enum typedef enum { COAP_RSPCODE_EMPTY = MAKE_RSPCODE(0, 0), + + // Success + COAP_RSPCODE_CREATED = MAKE_RSPCODE(2, 1), + COAP_RSPCODE_DELETED = MAKE_RSPCODE(2, 2), + COAP_RSPCODE_VALID = MAKE_RSPCODE(2, 3), + COAP_RSPCODE_CHANGED = MAKE_RSPCODE(2, 4), COAP_RSPCODE_CONTENT = MAKE_RSPCODE(2, 5), - COAP_RSPCODE_NOT_FOUND = MAKE_RSPCODE(4, 4), + + // Client Errors COAP_RSPCODE_BAD_REQUEST = MAKE_RSPCODE(4, 0), - COAP_RSPCODE_CHANGED = MAKE_RSPCODE(2, 4) + COAP_RSPCODE_UNAUTHORIZED = MAKE_RSPCODE(4, 1), + COAP_RSPCODE_BAD_OPTION = MAKE_RSPCODE(4, 2), + COAP_RSPCODE_FORBIDDEN = MAKE_RSPCODE(4, 3), + COAP_RSPCODE_NOT_FOUND = MAKE_RSPCODE(4, 4), + COAP_RSPCODE_METHOD_NOT_ALLOWED = MAKE_RSPCODE(4, 5), + COAP_RSPCODE_NOT_ACCEPTABLE = MAKE_RSPCODE(4, 6), + COAP_RSPCODE_PRECONDITION_FAILED = MAKE_RSPCODE(4, 12), + COAP_RSPCODE_REQUEST_ENTITY_TO_LARGE = MAKE_RSPCODE(4, 13), + COAP_RSPCODE_UNSUPPORTED_CONTENT_FMT = MAKE_RSPCODE(4, 15), + + // Server Errors + COAP_RSPCODE_INTERNAL_SERVER_ERROR = MAKE_RSPCODE(5, 0), + COAP_RSPCODE_NOT_IMPLEMENTED = MAKE_RSPCODE(5, 1), + COAP_RSPCODE_BAD_GATEWAY = MAKE_RSPCODE(5, 2), + COAP_RSPCODE_SERVICE_UNAVAILABLE = MAKE_RSPCODE(5, 3), + COAP_RSPCODE_GATEWAY_TIMEOUT = MAKE_RSPCODE(5, 4), + COAP_RSPCODE_NO_PROXY_SUPPORT = MAKE_RSPCODE(5, 5), + } coap_responsecode_t; //http://tools.ietf.org/html/rfc7252#section-12.3 typedef enum { COAP_CONTENTTYPE_NONE = -1, // bogus to allow us not to send option block - COAP_CONTENTTYPE_TEXT_PLAIN = 0, + COAP_CONTENTTYPE_TEXT_PLAIN = 0, COAP_CONTENTTYPE_APPLICATION_LINKFORMAT = 40, COAP_CONTENTTYPE_APPLICATION_XML = 41, COAP_CONTENTTYPE_APPLICATION_OCT_STREAM = 42, @@ -139,7 +163,6 @@ typedef enum /////////////////////// -typedef int (*coap_endpoint_func)(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt); /* To increase COAP_MAX_SEGMENTS, set CFLAGS to -DCOAP_MAX_SEGMENTS=. */ #ifndef COAP_MAX_SEGMENTS #define MAX_SEGMENTS 2 // 2 = /foo/bar, 3 = /foo/bar/baz @@ -155,6 +178,10 @@ typedef struct uint8_t len; } coap_str_element_t; +struct coap_endpoint; + +typedef int (*coap_endpoint_func)(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, coap_method_t method, const struct coap_endpoint *endpoint); + #define STAT_STR(str) #str, sizeof(#str) - 1 #define STAT_STR_EL(str) { STAT_STR(str) } @@ -177,7 +204,7 @@ typedef struct coap_str_element_t elems[MAX_SEGMENTS]; } coap_endpoint_path_t; -typedef struct +typedef struct coap_endpoint { coap_method_t method; /* (i.e. POST, PUT or GET) */ coap_endpoint_func handler; /* callback function which handles this From f01beeb6abc1f5f3b18f71e2164ef499ac623075 Mon Sep 17 00:00:00 2001 From: DipSwitch Date: Wed, 21 Oct 2015 14:11:31 +0200 Subject: [PATCH 8/9] changes --- coap.c | 4 ++-- coap.h | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/coap.c b/coap.c index 3998e1f..2426005 100644 --- a/coap.c +++ b/coap.c @@ -628,7 +628,7 @@ int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpk // FIXME, if this looked in the table at the path before the method then // it could more easily return 405 errors -int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt) +int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, void *args) { const coap_endpoint_t *ep = endpoints; const coap_option_t *opt; @@ -669,7 +669,7 @@ int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_ // check if the endpoint handles the request code if (ep->method & _COAP_HEADER_TO_METHOD(inpkt->hdr.code)) - return ep->handler(scratch, inpkt, outpkt, _COAP_HEADER_TO_METHOD(inpkt->hdr.code), ep); + return ep->handler(scratch, inpkt, outpkt, _COAP_HEADER_TO_METHOD(inpkt->hdr.code), ep, args); // method not supported coap_make_response(scratch, outpkt, NULL, 0, inpkt, COAP_RSPCODE_METHOD_NOT_ALLOWED, COAP_CONTENTTYPE_NONE, COAP_TYPE_ACK); diff --git a/coap.h b/coap.h index 835ffc1..a27a125 100644 --- a/coap.h +++ b/coap.h @@ -180,7 +180,10 @@ typedef struct struct coap_endpoint; -typedef int (*coap_endpoint_func)(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, coap_method_t method, const struct coap_endpoint *endpoint); +typedef int (*coap_endpoint_func)(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, coap_method_t method, const struct coap_endpoint *endpoint, void *args); + +typedef coap_responsecode_t (*coap_endpoint_request)(coap_method_t method, const char *name, uint8_t *value, size_t *len, size_t max_len); + #define STAT_STR(str) #str, sizeof(#str) - 1 #define STAT_STR_EL(str) { STAT_STR(str) } @@ -243,7 +246,7 @@ int coap_make_response(coap_rw_buffer_t *scratch, coap_packet_t *pkt, const uint const coap_packet_t *inpkt, coap_responsecode_t rspcode, coap_content_type_t content_type, coap_msgtype_t msg_type); -int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt); +int coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, void *args); void coap_option_nibble(uint32_t value, uint8_t *nibble); From 160833a4e35bf3068e42d7da60f4bca7a07cd8a5 Mon Sep 17 00:00:00 2001 From: DipSwitch Date: Thu, 22 Oct 2015 16:43:33 +0200 Subject: [PATCH 9/9] fix offset calculation fault --- coap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/coap.c b/coap.c index 2426005..febd7eb 100644 --- a/coap.c +++ b/coap.c @@ -491,9 +491,9 @@ int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpk spc_left -= (x); \ copy = spc_left >= 0 ? (x) : (x) + spc_left -#define OFF_TAKE(x) (offset <= 0 \ - || ((offset -= (x)) < 0 \ - && (offset = (x) + offset) >= 0)) +#define OFF_TAKE(x) (offset == 0 \ + || ((offset -= (x)) < 0 \ + && (offset = ((x) + offset)) > 0)) #define CLR_OFFSET() offset -= offset @@ -544,7 +544,7 @@ int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpk } if (OFF_TAKE(6)) { - BUF_TAKE(6); + BUF_TAKE(6 - offset); memcpy(buf, "title=" + offset, copy); buf += copy; CLR_OFFSET(); @@ -574,7 +574,7 @@ int coap_send_endpoint_list(coap_rw_buffer_t *scratch, const coap_packet_t *inpk } if (OFF_TAKE(3)) { - BUF_TAKE(3); + BUF_TAKE(3 - offset); memcpy(buf, "ct=" + offset, copy); buf += copy; CLR_OFFSET();