CoAP server ported from Arduino microcoap
Dependencies: EthernetInterface Socket mbed-rtos mbed
Revision 0:64df7fc091da, committed 2017-03-23
- Comitter:
- rfrenken
- Date:
- Thu Mar 23 16:29:41 2017 +0000
- Commit message:
- Coap Server ported from Arduino microcoap
Changed in this revision
diff -r 000000000000 -r 64df7fc091da EthernetInterface.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EthernetInterface.lib Thu Mar 23 16:29:41 2017 +0000 @@ -0,0 +1,1 @@ +https://developer.mbed.org/users/rfrenken/code/EthernetInterface/#99407e48004d
diff -r 000000000000 -r 64df7fc091da Socket.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Socket.lib Thu Mar 23 16:29:41 2017 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/mbed_official/code/Socket/#434906b5b977
diff -r 000000000000 -r 64df7fc091da coap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/coap.h Thu Mar 23 16:29:41 2017 +0000 @@ -0,0 +1,179 @@ +#ifndef COAP_H +#define COAP_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> + +#define MAXOPT 16 + +//http://tools.ietf.org/html/rfc7252#section-3 +typedef struct +{ + 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; + +typedef struct +{ + const uint8_t *p; + size_t len; +} coap_buffer_t; + +typedef struct +{ + uint8_t *p; + size_t len; +} coap_rw_buffer_t; + +typedef struct +{ + 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; /* 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_packet_t; + +///////////////////////////////////////// + +//http://tools.ietf.org/html/rfc7252#section-12.2 +typedef enum +{ + COAP_OPTION_IF_MATCH = 1, + COAP_OPTION_URI_HOST = 3, + COAP_OPTION_ETAG = 4, + COAP_OPTION_IF_NONE_MATCH = 5, + COAP_OPTION_OBSERVE = 6, + COAP_OPTION_URI_PORT = 7, + COAP_OPTION_LOCATION_PATH = 8, + COAP_OPTION_URI_PATH = 11, + COAP_OPTION_CONTENT_FORMAT = 12, + COAP_OPTION_MAX_AGE = 14, + COAP_OPTION_URI_QUERY = 15, + COAP_OPTION_ACCEPT = 17, + COAP_OPTION_LOCATION_QUERY = 20, + COAP_OPTION_PROXY_URI = 35, + COAP_OPTION_PROXY_SCHEME = 39 +} coap_option_num_t; + +//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_t; + +//http://tools.ietf.org/html/rfc7252#section-12.1.1 +typedef enum +{ + COAP_TYPE_CON = 0, + COAP_TYPE_NONCON = 1, + COAP_TYPE_ACK = 2, + COAP_TYPE_RESET = 3 +} coap_msgtype_t; + +//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 +{ + COAP_RSPCODE_CONTENT = MAKE_RSPCODE(2, 5), + COAP_RSPCODE_NOT_FOUND = MAKE_RSPCODE(4, 4), + COAP_RSPCODE_BAD_REQUEST = MAKE_RSPCODE(4, 0), + COAP_RSPCODE_CHANGED = MAKE_RSPCODE(2, 4) +} coap_responsecode_t; + +//http://tools.ietf.org/html/rfc7252#section-12.3 +typedef enum +{ + COAP_CONTENTTYPE_NONE = -1, // bodge 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_OCTECT_STREAM = 42, + COAP_CONTENTTYPE_APPLICATION_EXI = 47, + COAP_CONTENTTYPE_APPLICATION_JSON = 50, +} coap_content_type_t; + +/////////////////////// + +typedef enum +{ + COAP_ERR_NONE = 0, + COAP_ERR_HEADER_TOO_SHORT = 1, + COAP_ERR_VERSION_NOT_1 = 2, + COAP_ERR_TOKEN_TOO_SHORT = 3, + COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER = 4, + COAP_ERR_OPTION_TOO_SHORT = 5, + COAP_ERR_OPTION_OVERRUNS_PACKET = 6, + COAP_ERR_OPTION_TOO_BIG = 7, + COAP_ERR_OPTION_LEN_INVALID = 8, + COAP_ERR_BUFFER_TOO_SMALL = 9, + COAP_ERR_UNSUPPORTED = 10, + COAP_ERR_OPTION_DELTA_INVALID = 11, +} coap_error_t; + +/////////////////////// + +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); +#define MAX_SEGMENTS 2 // 2 = /foo/bar, 3 = /foo/bar/baz +typedef struct +{ + int count; + const char *elems[MAX_SEGMENTS]; +} coap_endpoint_path_t; + +typedef struct +{ + 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_endpoint_t; + + +/////////////////////// +void coap_dumpPacket(coap_packet_t *pkt); +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_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 +} +#endif + +#endif + +extern const coap_endpoint_t endpoints[]; \ No newline at end of file
diff -r 000000000000 -r 64df7fc091da endpoints.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/endpoints.cpp Thu Mar 23 16:29:41 2017 +0000 @@ -0,0 +1,234 @@ +#include "mbed.h" +#include <stdbool.h> +#include <string.h> + +#include "coap.h" + +static char light = '0'; +static char led0 = '0'; +static char led1 = '0'; +static char led2 = '0'; +static char led3 = '0'; +DigitalOut myled(LED1); +DigitalOut myled1(LED2); +DigitalOut myled2(LED3); +DigitalOut myled3(LED4); + +const uint16_t rsplen = 1500; +static char rsp[1500] = ""; +void build_rsp(void); + +#include <stdio.h> +void endpoint_setup(void) +{ + build_rsp(); +} + +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 const coap_endpoint_path_t path_led0 = {2, {"led", "0"}}; + +static const coap_endpoint_path_t path_led1 = {2, {"led", "1"}}; + +static const coap_endpoint_path_t path_led2 = {2, {"led", "2"}}; + +static const coap_endpoint_path_t path_led3 = {2, {"led", "3"}}; + +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_get_led0(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 *)&led0, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN); +} + +static int handle_get_led1(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 *)&led1, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN); +} + +static int handle_get_led2(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 *)&led2, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN); +} + +static int handle_get_led3(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 *)&led3, 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 + myled = 1; + 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 + myled = 0; + 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); + } +} + +static int handle_put_led0(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') + { + led0 = '1'; + myled = 1; + printf("ON\n"); + return coap_make_response(scratch, outpkt, (const uint8_t *)&led0, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN); + } + else + { + led0 = '0'; + myled = 0; + printf("OFF\n"); + return coap_make_response(scratch, outpkt, (const uint8_t *)&led0, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN); + } +} + +static int handle_put_led1(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') + { + led1 = '1'; + myled1 = 1; + printf("ON\n"); + return coap_make_response(scratch, outpkt, (const uint8_t *)&led1, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN); + } + else + { + led1 = '0'; + myled1 = 0; + printf("OFF\n"); + return coap_make_response(scratch, outpkt, (const uint8_t *)&led1, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN); + } +} + +static int handle_put_led2(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') + { + led2 = '1'; + myled2 = 1; + printf("ON\n"); + return coap_make_response(scratch, outpkt, (const uint8_t *)&led2, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN); + } + else + { + led2 = '0'; + myled2 = 0; + printf("OFF\n"); + return coap_make_response(scratch, outpkt, (const uint8_t *)&led2, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN); + } +} + +static int handle_put_led3(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') + { + led3 = '1'; + myled3 = 1; + printf("ON\n"); + return coap_make_response(scratch, outpkt, (const uint8_t *)&led3, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN); + } + else + { + led3 = '0'; + myled3 = 0; + printf("OFF\n"); + return coap_make_response(scratch, outpkt, (const uint8_t *)&led3, 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_GET, handle_get_led0, &path_led0, "ct=0"}, + {COAP_METHOD_PUT, handle_put_led0, &path_led0, NULL}, + {COAP_METHOD_GET, handle_get_led1, &path_led1, "ct=0"}, + {COAP_METHOD_PUT, handle_put_led1, &path_led1, NULL}, + {COAP_METHOD_GET, handle_get_led2, &path_led2, "ct=0"}, + {COAP_METHOD_PUT, handle_put_led2, &path_led2, NULL}, + {COAP_METHOD_GET, handle_get_led3, &path_led3, "ct=0"}, + {COAP_METHOD_PUT, handle_put_led3, &path_led3, 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++; + } +} + \ No newline at end of file
diff -r 000000000000 -r 64df7fc091da main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Thu Mar 23 16:29:41 2017 +0000 @@ -0,0 +1,520 @@ +#include "mbed.h" +#include "EthernetInterface.h" +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <stddef.h> +#include "coap.h" + +#define PORT 5683 + +extern void endpoint_setup(void); +extern const coap_endpoint_t endpoints[]; +#define UDP_TX_PACKET_MAX_SIZE 256 + + + +#ifdef DEBUG +void coap_dumpHeader(coap_header_t *hdr) +{ + printf("Header:\n"); + printf(" ver 0x%02X\n", hdr->ver); + printf(" t 0x%02X\n", hdr->t); + printf(" tkl 0x%02X\n", hdr->tkl); + printf(" code 0x%02X\n", hdr->code); + printf(" id 0x%02X%02X\n", hdr->id[0], hdr->id[1]); +} +#endif + +#ifdef DEBUG +void coap_dump(const uint8_t *buf, size_t buflen, bool bare) +{ + if (bare) + { + while(buflen--) + printf("%02X%s", *buf++, (buflen > 0) ? " " : ""); + } + else + { + printf("Dump: "); + while(buflen--) + printf("%02X%s", *buf++, (buflen > 0) ? " " : ""); + printf("\n"); + } +} +#endif + +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) + { + printf("hdr versions is %d\n", hdr->ver); + return COAP_ERR_VERSION_NOT_1; + } + hdr->t = (buf[0] & 0x30) >> 4; + hdr->tkl = buf[0] & 0x0F; + hdr->code = buf[1]; + hdr->id[0] = buf[2]; + hdr->id[1] = buf[3]; + return 0; +} + +int coap_parseToken(coap_buffer_t *tokbuf, const coap_header_t *hdr, const uint8_t *buf, size_t buflen) +{ + if (hdr->tkl == 0) + { + tokbuf->p = NULL; + tokbuf->len = 0; + return 0; + } + else + if (hdr->tkl <= 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; + return 0; + } + else + { + // invalid size + return COAP_ERR_TOKEN_TOO_SHORT; + } +} + +// advances p +int coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8_t **buf, size_t buflen) +{ + const uint8_t *p = *buf; + uint8_t headlen = 1; + uint16_t len, delta; + + if (buflen < headlen) // too small + return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER; + + delta = (p[0] & 0xF0) >> 4; + len = p[0] & 0x0F; + + // These are untested and may be buggy + if (delta == 13) + { + headlen++; + if (buflen < headlen) + return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER; + delta = p[1] + 13; + p++; + } + else + if (delta == 14) + { + headlen += 2; + if (buflen < headlen) + return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER; + delta = ((p[1] << 8) | p[2]) + 269; + p+=2; + } + else + if (delta == 15) + return COAP_ERR_OPTION_DELTA_INVALID; + + if (len == 13) + { + headlen++; + if (buflen < headlen) + return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER; + len = p[1] + 13; + p++; + } + 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) + 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; + *running_delta += delta; + + return 0; +} + +// 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; + 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 + { + payload->p = p+1; + payload->len = end-(p+1); + } + else + { + payload->p = NULL; + payload->len = 0; + } + + return 0; +} + +#ifdef DEBUG +void coap_dumpOptions(coap_option_t *opts, size_t numopt) +{ + size_t i; + printf(" Options:\n"); + for (i=0;i<numopt;i++) + { + printf(" 0x%02X [ ", opts[i].num); + coap_dump(opts[i].buf.p, opts[i].buf.len, true); + printf(" ]\n"); + } +} +#endif + +#ifdef DEBUG +void coap_dumpPacket(coap_packet_t *pkt) +{ + coap_dumpHeader(&pkt->hdr); + coap_dumpOptions(pkt->opts, pkt->numopts); + printf("Payload: "); + coap_dump(pkt->payload.p, pkt->payload.len, true); + printf("\n"); +} +#endif + +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))) + return rc; +// coap_dumpHeader(&hdr); + if (0 != (rc = coap_parseToken(&pkt->tok, &pkt->hdr, buf, buflen))) + return rc; + pkt->numopts = MAXOPT; + if (0 != (rc = coap_parseOptionsAndPayload(pkt->opts, &(pkt->numopts), &(pkt->payload), &pkt->hdr, buf, buflen))) + return rc; +// coap_dumpOptions(opts, numopt); + return 0; +} + +// 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) +{ + // FIXME, options is always sorted, can find faster than this + size_t i; + const coap_option_t *first = NULL; + *count = 0; + for (i=0;i<pkt->numopts;i++) + { + if (pkt->opts[i].num == num) + { + if (NULL == first) + first = &pkt->opts[i]; + (*count)++; + } + else + { + if (NULL != first) + break; + } + } + return first; +} + +int coap_buffer_to_string(char *strbuf, size_t strbuflen, const coap_buffer_t *buf) +{ + if (buf->len+1 > strbuflen) + return COAP_ERR_BUFFER_TOO_SMALL; + memcpy(strbuf, buf->p, buf->len); + strbuf[buf->len] = 0; + return 0; +} + +int coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt) +{ + size_t opts_len = 0; + size_t i; + uint8_t *p; + uint16_t running_delta = 0; + + // build header + if (*buflen < (4U + pkt->hdr.tkl)) + return COAP_ERR_BUFFER_TOO_SMALL; + + buf[0] = (pkt->hdr.ver & 0x03) << 6; + buf[0] |= (pkt->hdr.t & 0x03) << 4; + buf[0] |= (pkt->hdr.tkl & 0x0F); + buf[1] = pkt->hdr.code; + buf[2] = pkt->hdr.id[0]; + buf[3] = pkt->hdr.id[1]; + + // inject token + p = buf + 4; + if ((pkt->hdr.tkl > 0) && (pkt->hdr.tkl != pkt->tok.len)) + return COAP_ERR_UNSUPPORTED; + + if (pkt->hdr.tkl > 0) + memcpy(p, pkt->tok.p, pkt->hdr.tkl); + + // // http://tools.ietf.org/html/rfc7252#section-3.1 + // inject options + p += pkt->hdr.tkl; + + for (i=0;i<pkt->numopts;i++) + { + uint32_t optDelta; + uint8_t len, delta = 0; + + if (((size_t)(p-buf)) > *buflen) + return COAP_ERR_BUFFER_TOO_SMALL; + optDelta = pkt->opts[i].num - running_delta; + coap_option_nibble(optDelta, &delta); + coap_option_nibble((uint32_t)pkt->opts[i].buf.len, &len); + + *p++ = (0xFF & (delta << 4 | len)); + if (delta == 13) + { + *p++ = (optDelta - 13); + } + 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) + { + *p++ = (pkt->opts[i].buf.len >> 8); + *p++ = (0xFF & (pkt->opts[i].buf.len-269)); + } + + memcpy(p, pkt->opts[i].buf.p, pkt->opts[i].buf.len); + p += pkt->opts[i].buf.len; + running_delta = pkt->opts[i].num; + } + + opts_len = (p - buf) - 4; // number of bytes used by options + + if (pkt->payload.len > 0) + { + 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) + { + *nibble = 13; + } 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) +{ + pkt->hdr.ver = 0x01; + pkt->hdr.t = COAP_TYPE_ACK; + pkt->hdr.tkl = 0; + pkt->hdr.code = rspcode; + pkt->hdr.id[0] = msgid_hi; + pkt->hdr.id[1] = msgid_lo; + pkt->numopts = 1; + + // need token in response + if (tok) { + pkt->hdr.tkl = tok->len; + pkt->tok = *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; + pkt->payload.p = content; + pkt->payload.len = content_len; + 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) +{ + const coap_option_t *opt; + uint8_t count; + int i; + const coap_endpoint_t *ep = endpoints; + + while(NULL != ep->handler) + { + 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;i<count;i++) + { + if (opt[i].buf.len != strlen(ep->path->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++; + } + + coap_make_response(scratch, outpkt, NULL, 0, inpkt->hdr.id[0], inpkt->hdr.id[1], &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE); + + return 0; +} + +void coap_setup(void) +{ +} + +Serial pc(USBTX, USBRX); +static uint8_t scratch_raw[32]; +static coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)}; + +int main(void) { + + + EthernetInterface eth; + eth.init(); //Use DHCP + eth.connect(); + printf("IP Address is %s\n", eth.getIPAddress()); + + UDPSocket coapServer; + coapServer.bind(PORT); + + coap_setup(); + endpoint_setup(); + Endpoint client; + char buffer[256]; + uint8_t packetbuf[256]; + coap_packet_t pkt; + + while (true) { + printf("\nWaiting for UDP packet...\n"); + int sz = coapServer.receiveFrom(client, buffer, sizeof(buffer)); + buffer[sz] = '\0'; + + printf("Received packet from: %s\n", client.get_address()); + + printf("Packet contents : '%s'\n",buffer); + +#ifdef DEBUG + for (int i=0;i<sz;i++) + { + printf("%x",buffer[i]); + printf(" "); + } + printf("\n"); +#endif + int rc; + + if (0 != (rc = coap_parse(&pkt, (uint8_t *)buffer, sz))) + { + printf("Bad packet rc=%d\n", rc); + } + else + { + size_t rsplen = sizeof(buffer); + coap_packet_t rsppkt; + coap_handle_req(&scratch_buf, &pkt, &rsppkt); + + memset(buffer, 0, UDP_TX_PACKET_MAX_SIZE); + if (0 != (rc = coap_build((uint8_t *)buffer, &rsplen, &rsppkt))) + { + printf("coap_build failed rc=%d\n", rc); + } + else + { + coapServer.sendTo(client, (char *) buffer, rsplen); + } + } + } +} + + + //coap_setup(); + //endpoint_setup(); +// override the default weak function to provide a specific mac address +/*extern "C" void mbed_mac_address(char *mac) +{ + mac[0] = 0x01; + mac[1] = 0x23; + mac[2] = 0x45; + mac[3] = 0x67; + mac[4] = 0x89; + mac[5] = 0xAB; +};*/ +
diff -r 000000000000 -r 64df7fc091da mbed-rtos.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rtos.lib Thu Mar 23 16:29:41 2017 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed-rtos/#58563e6cba1e
diff -r 000000000000 -r 64df7fc091da mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Thu Mar 23 16:29:41 2017 +0000 @@ -0,0 +1,1 @@ +https://mbed.org/users/mbed_official/code/mbed/builds/093f2bd7b9eb \ No newline at end of file