[
  {
    "path": ".gitignore",
    "content": "# Executable\ncoap\n\n# Object files\n*.o\n*.ko\n*.obj\n*.elf\n\n# Dependency files\n*.d\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Libraries\n*.lib\n*.a\n*.la\n*.lo\n\n# Shared objects (inc. Windows DLLs)\n*.dll\n*.so\n*.so.*\n*.dylib\n\n# Executables\n*.exe\n*.out\n*.app\n*.i*86\n*.x86_64\n*.hex\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Copyright (c) 2013 Toby Jaffey <toby@1248.io>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "CFLAGS += -Wall -DDEBUG\n# -DIPV6\nSRC = $(wildcard *.c)\nOBJ = $(SRC:%.c=%.o)\nDEPS = $(SRC:%.c=%.d)\nEXEC = coap\n\nall: $(EXEC)\n\n-include $(DEPS)\n\n$(EXEC): $(OBJ)\n\t@$(CC) $(CFLAGS) -o $@ $^\n\n%.o: %.c %.d\n\t@$(CC) -c $(CFLAGS) -o $@ $<\n\n%.d: %.c\n\t@$(CC) -MM $(CFLAGS) $< > $@\n\nclean:\n\t@$(RM) $(EXEC) $(OBJ) $(DEPS)\n"
  },
  {
    "path": "README.md",
    "content": "microcoap\n=========\n\nA tiny CoAP server for microcontrollers.\nSee http://tools.ietf.org/html/rfc7252\n\nEndpoint handlers are defined in endpoints.c\n\n * Arduino demo (Mega + Ethernet shield, LED + 220R on pin 6, PUT \"0\" or \"1\" to /light)\n * POSIX (OS X/Linux) demo\n * GET/PUT/POST\n * No retries\n * Piggybacked ACK only\n\n\nFor linux/OSX\n\n    make\n    ./coap\n\nFor Arduino\n\n    open microcoap.ino\n\nTo test, use libcoap\n\n    ./coap-client -v 100 -m get coap://127.0.0.1/.well-known/core\n    ./coap-client -v 100 -m get coap://127.0.0.1/light\n    ./coap-client -e \"1\" -m put coap://127.0.0.1/light\n    ./coap-client -e \"0\" -m put coap://127.0.0.1/light\n\nOr use copper (Firefox plugin)\n\n    coap://127.0.0.1\n\nArduino problem\n===============\n\nArduino, by default, has a UDP transmit buffer of 24 bytes. This is too small\nfor some endpoints and will result in an error.\n\n"
  },
  {
    "path": "coap.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdbool.h>\n#include <string.h>\n#include <stddef.h>\n#include \"coap.h\"\n\nextern void endpoint_setup(void);\nextern const coap_endpoint_t endpoints[];\n\n#ifdef DEBUG\nvoid coap_dumpHeader(coap_header_t *hdr)\n{\n    printf(\"Header:\\n\");\n    printf(\"  ver  0x%02X\\n\", hdr->ver);\n    printf(\"  t    0x%02X\\n\", hdr->t);\n    printf(\"  tkl  0x%02X\\n\", hdr->tkl);\n    printf(\"  code 0x%02X\\n\", hdr->code);\n    printf(\"  id   0x%02X%02X\\n\", hdr->id[0], hdr->id[1]);\n}\n#endif\n\n#ifdef DEBUG\nvoid coap_dump(const uint8_t *buf, size_t buflen, bool bare)\n{\n    if (bare)\n    {\n        while(buflen--)\n            printf(\"%02X%s\", *buf++, (buflen > 0) ? \" \" : \"\");\n    }\n    else\n    {\n        printf(\"Dump: \");\n        while(buflen--)\n            printf(\"%02X%s\", *buf++, (buflen > 0) ? \" \" : \"\");\n        printf(\"\\n\");\n    }\n}\n#endif\n\nint coap_parseHeader(coap_header_t *hdr, const uint8_t *buf, size_t buflen)\n{\n    if (buflen < 4)\n        return COAP_ERR_HEADER_TOO_SHORT;\n    hdr->ver = (buf[0] & 0xC0) >> 6;\n    if (hdr->ver != 1)\n        return COAP_ERR_VERSION_NOT_1;\n    hdr->t = (buf[0] & 0x30) >> 4;\n    hdr->tkl = buf[0] & 0x0F;\n    hdr->code = buf[1];\n    hdr->id[0] = buf[2];\n    hdr->id[1] = buf[3];\n    return 0;\n}\n\nint coap_parseToken(coap_buffer_t *tokbuf, const coap_header_t *hdr, const uint8_t *buf, size_t buflen)\n{\n    if (hdr->tkl == 0)\n    {\n        tokbuf->p = NULL;\n        tokbuf->len = 0;\n        return 0;\n    }\n    else\n    if (hdr->tkl <= 8)\n    {\n        if (4U + hdr->tkl > buflen)\n            return COAP_ERR_TOKEN_TOO_SHORT;   // tok bigger than packet\n        tokbuf->p = buf+4;  // past header\n        tokbuf->len = hdr->tkl;\n        return 0;\n    }\n    else\n    {\n        // invalid size\n        return COAP_ERR_TOKEN_TOO_SHORT;\n    }\n}\n\n// advances p\nint coap_parseOption(coap_option_t *option, uint16_t *running_delta, const uint8_t **buf, size_t buflen)\n{\n    const uint8_t *p = *buf;\n    uint8_t headlen = 1;\n    uint16_t len, delta;\n\n    if (buflen < headlen) // too small\n        return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;\n\n    delta = (p[0] & 0xF0) >> 4;\n    len = p[0] & 0x0F;\n\n    // These are untested and may be buggy\n    if (delta == 13)\n    {\n        headlen++;\n        if (buflen < headlen)\n            return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;\n        delta = p[1] + 13;\n        p++;\n    }\n    else\n    if (delta == 14)\n    {\n        headlen += 2;\n        if (buflen < headlen)\n            return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;\n        delta = ((p[1] << 8) | p[2]) + 269;\n        p+=2;\n    }\n    else\n    if (delta == 15)\n        return COAP_ERR_OPTION_DELTA_INVALID;\n\n    if (len == 13)\n    {\n        headlen++;\n        if (buflen < headlen)\n            return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;\n        len = p[1] + 13;\n        p++;\n    }\n    else\n    if (len == 14)\n    {\n        headlen += 2;\n        if (buflen < headlen)\n            return COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER;\n        len = ((p[1] << 8) | p[2]) + 269;\n        p+=2;\n    }\n    else\n    if (len == 15)\n        return COAP_ERR_OPTION_LEN_INVALID;\n\n    if ((p + 1 + len) > (*buf + buflen))\n        return COAP_ERR_OPTION_TOO_BIG;\n\n    //printf(\"option num=%d\\n\", delta + *running_delta);\n    option->num = delta + *running_delta;\n    option->buf.p = p+1;\n    option->buf.len = len;\n    //coap_dump(p+1, len, false);\n\n    // advance buf\n    *buf = p + 1 + len;\n    *running_delta += delta;\n\n    return 0;\n}\n\n// http://tools.ietf.org/html/rfc7252#section-3.1\nint 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)\n{\n    size_t optionIndex = 0;\n    uint16_t delta = 0;\n    const uint8_t *p = buf + 4 + hdr->tkl;\n    const uint8_t *end = buf + buflen;\n    int rc;\n    if (p > end)\n        return COAP_ERR_OPTION_OVERRUNS_PACKET;   // out of bounds\n\n    //coap_dump(p, end - p);\n\n    // 0xFF is payload marker\n    while((optionIndex < *numOptions) && (p < end) && (*p != 0xFF))\n    {\n        if (0 != (rc = coap_parseOption(&options[optionIndex], &delta, &p, end-p)))\n            return rc;\n        optionIndex++;\n    }\n    *numOptions = optionIndex;\n\n    if (p+1 < end && *p == 0xFF)  // payload marker\n    {\n        payload->p = p+1;\n        payload->len = end-(p+1);\n    }\n    else\n    {\n        payload->p = NULL;\n        payload->len = 0;\n    }\n\n    return 0;\n}\n\n#ifdef DEBUG\nvoid coap_dumpOptions(coap_option_t *opts, size_t numopt)\n{\n    size_t i;\n    printf(\" Options:\\n\");\n    for (i=0;i<numopt;i++)\n    {\n        printf(\"  0x%02X [ \", opts[i].num);\n        coap_dump(opts[i].buf.p, opts[i].buf.len, true);\n        printf(\" ]\\n\");\n    }\n}\n#endif\n\n#ifdef DEBUG\nvoid coap_dumpPacket(coap_packet_t *pkt)\n{\n    coap_dumpHeader(&pkt->hdr);\n    coap_dumpOptions(pkt->opts, pkt->numopts);\n    printf(\"Payload: \");\n    coap_dump(pkt->payload.p, pkt->payload.len, true);\n    printf(\"\\n\");\n}\n#endif\n\nint coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen)\n{\n    int rc;\n\n    // coap_dump(buf, buflen, false);\n\n    if (0 != (rc = coap_parseHeader(&pkt->hdr, buf, buflen)))\n        return rc;\n//    coap_dumpHeader(&hdr);\n    if (0 != (rc = coap_parseToken(&pkt->tok, &pkt->hdr, buf, buflen)))\n        return rc;\n    pkt->numopts = MAXOPT;\n    if (0 != (rc = coap_parseOptionsAndPayload(pkt->opts, &(pkt->numopts), &(pkt->payload), &pkt->hdr, buf, buflen)))\n        return rc;\n//    coap_dumpOptions(opts, numopt);\n    return 0;\n}\n\n// options are always stored consecutively, so can return a block with same option num\nconst coap_option_t *coap_findOptions(const coap_packet_t *pkt, uint8_t num, uint8_t *count)\n{\n    // FIXME, options is always sorted, can find faster than this\n    size_t i;\n    const coap_option_t *first = NULL;\n    *count = 0;\n    for (i=0;i<pkt->numopts;i++)\n    {\n        if (pkt->opts[i].num == num)\n        {\n            if (NULL == first)\n                first = &pkt->opts[i];\n            (*count)++;\n        }\n        else\n        {\n            if (NULL != first)\n                break;\n        }\n    }\n    return first;\n}\n\nint coap_buffer_to_string(char *strbuf, size_t strbuflen, const coap_buffer_t *buf)\n{\n    if (buf->len+1 > strbuflen)\n        return COAP_ERR_BUFFER_TOO_SMALL;\n    memcpy(strbuf, buf->p, buf->len);\n    strbuf[buf->len] = 0;\n    return 0;\n}\n\nint coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt)\n{\n    size_t opts_len = 0;\n    size_t i;\n    uint8_t *p;\n    uint16_t running_delta = 0;\n\n    // build header\n    if (*buflen < (4U + pkt->hdr.tkl))\n        return COAP_ERR_BUFFER_TOO_SMALL;\n\n    buf[0] = (pkt->hdr.ver & 0x03) << 6;\n    buf[0] |= (pkt->hdr.t & 0x03) << 4;\n    buf[0] |= (pkt->hdr.tkl & 0x0F);\n    buf[1] = pkt->hdr.code;\n    buf[2] = pkt->hdr.id[0];\n    buf[3] = pkt->hdr.id[1];\n\n    // inject token\n    p = buf + 4;\n    if ((pkt->hdr.tkl > 0) && (pkt->hdr.tkl != pkt->tok.len))\n        return COAP_ERR_UNSUPPORTED;\n    \n    if (pkt->hdr.tkl > 0)\n        memcpy(p, pkt->tok.p, pkt->hdr.tkl);\n\n    // // http://tools.ietf.org/html/rfc7252#section-3.1\n    // inject options\n    p += pkt->hdr.tkl;\n\n    for (i=0;i<pkt->numopts;i++)\n    {\n        uint32_t optDelta;\n        uint8_t len, delta = 0;\n\n        if (((size_t)(p-buf)) > *buflen)\n             return COAP_ERR_BUFFER_TOO_SMALL;\n        optDelta = pkt->opts[i].num - running_delta;\n        coap_option_nibble(optDelta, &delta);\n        coap_option_nibble((uint32_t)pkt->opts[i].buf.len, &len);\n\n        *p++ = (0xFF & (delta << 4 | len));\n        if (delta == 13)\n        {\n            *p++ = (optDelta - 13);\n        }\n        else\n        if (delta == 14)\n        {\n            *p++ = ((optDelta-269) >> 8);\n            *p++ = (0xFF & (optDelta-269));\n        }\n        if (len == 13)\n        {\n            *p++ = (pkt->opts[i].buf.len - 13);\n        }\n        else\n        if (len == 14)\n  \t    {\n            *p++ = (pkt->opts[i].buf.len >> 8);\n            *p++ = (0xFF & (pkt->opts[i].buf.len-269));\n        }\n\n        memcpy(p, pkt->opts[i].buf.p, pkt->opts[i].buf.len);\n        p += pkt->opts[i].buf.len;\n        running_delta = pkt->opts[i].num;\n    }\n\n    opts_len = (p - buf) - 4;   // number of bytes used by options\n\n    if (pkt->payload.len > 0)\n    {\n        if (*buflen < 4 + 1 + pkt->payload.len + opts_len)\n            return COAP_ERR_BUFFER_TOO_SMALL;\n        buf[4 + opts_len] = 0xFF;  // payload marker\n        memcpy(buf+5 + opts_len, pkt->payload.p, pkt->payload.len);\n        *buflen = opts_len + 5 + pkt->payload.len;\n    }\n    else\n        *buflen = opts_len + 4;\n    return 0;\n}\n\nvoid coap_option_nibble(uint32_t value, uint8_t *nibble)\n{\n    if (value<13)\n    {\n        *nibble = (0xFF & value);\n    }\n    else\n    if (value<=0xFF+13)\n    {\n        *nibble = 13;\n    } else if (value<=0xFFFF+269)\n    {\n        *nibble = 14;\n    }\n}\n\nint 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)\n{\n    pkt->hdr.ver = 0x01;\n    pkt->hdr.t = COAP_TYPE_ACK;\n    pkt->hdr.tkl = 0;\n    pkt->hdr.code = rspcode;\n    pkt->hdr.id[0] = msgid_hi;\n    pkt->hdr.id[1] = msgid_lo;\n    pkt->numopts = 1;\n\n    // need token in response\n    if (tok) {\n        pkt->hdr.tkl = tok->len;\n        pkt->tok = *tok;\n    }\n\n    // safe because 1 < MAXOPT\n    pkt->opts[0].num = COAP_OPTION_CONTENT_FORMAT;\n    pkt->opts[0].buf.p = scratch->p;\n    if (scratch->len < 2)\n        return COAP_ERR_BUFFER_TOO_SMALL;\n    scratch->p[0] = ((uint16_t)content_type & 0xFF00) >> 8;\n    scratch->p[1] = ((uint16_t)content_type & 0x00FF);\n    pkt->opts[0].buf.len = 2;\n    pkt->payload.p = content;\n    pkt->payload.len = content_len;\n    return 0;\n}\n\n// FIXME, if this looked in the table at the path before the method then\n// it could more easily return 405 errors\nint coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt)\n{\n    const coap_option_t *opt;\n    uint8_t count;\n    int i;\n    const coap_endpoint_t *ep = endpoints;\n\n    while(NULL != ep->handler)\n    {\n        if (ep->method != inpkt->hdr.code)\n            goto next;\n        if (NULL != (opt = coap_findOptions(inpkt, COAP_OPTION_URI_PATH, &count)))\n        {\n            if (count != ep->path->count)\n                goto next;\n            for (i=0;i<count;i++)\n            {\n                if (opt[i].buf.len != strlen(ep->path->elems[i]))\n                    goto next;\n                if (0 != memcmp(ep->path->elems[i], opt[i].buf.p, opt[i].buf.len))\n                    goto next;\n            }\n            // match!\n            return ep->handler(scratch, inpkt, outpkt, inpkt->hdr.id[0], inpkt->hdr.id[1]);\n        }\nnext:\n        ep++;\n    }\n\n    coap_make_response(scratch, outpkt, NULL, 0, inpkt->hdr.id[0], inpkt->hdr.id[1], &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);\n\n    return 0;\n}\n\nvoid coap_setup(void)\n{\n}\n\n"
  },
  {
    "path": "coap.h",
    "content": "#ifndef COAP_H\n#define COAP_H 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <stddef.h>\n\n#define MAXOPT 16\n\n//http://tools.ietf.org/html/rfc7252#section-3\ntypedef struct\n{\n    uint8_t ver;                /* CoAP version number */\n    uint8_t t;                  /* CoAP Message Type */\n    uint8_t tkl;                /* Token length: indicates length of the Token field */\n    uint8_t code;               /* CoAP status code. Can be request (0.xx), success reponse (2.xx), \n                                 * client error response (4.xx), or rever error response (5.xx) \n                                 * For possible values, see http://tools.ietf.org/html/rfc7252#section-12.1 */\n    uint8_t id[2];\n} coap_header_t;\n\ntypedef struct\n{\n    const uint8_t *p;\n    size_t len;\n} coap_buffer_t;\n\ntypedef struct\n{\n    uint8_t *p;\n    size_t len;\n} coap_rw_buffer_t;\n\ntypedef struct\n{\n    uint8_t num;                /* Option number. See http://tools.ietf.org/html/rfc7252#section-5.10 */\n    coap_buffer_t buf;          /* Option value */\n} coap_option_t;\n\ntypedef struct\n{\n    coap_header_t hdr;          /* Header of the packet */\n    coap_buffer_t tok;          /* Token value, size as specified by hdr.tkl */\n    uint8_t numopts;            /* Number of options */\n    coap_option_t opts[MAXOPT]; /* Options of the packet. For possible entries see\n                                 * http://tools.ietf.org/html/rfc7252#section-5.10 */\n    coap_buffer_t payload;      /* Payload carried by the packet */\n} coap_packet_t;\n\n/////////////////////////////////////////\n\n//http://tools.ietf.org/html/rfc7252#section-12.2\ntypedef enum\n{\n    COAP_OPTION_IF_MATCH = 1,\n    COAP_OPTION_URI_HOST = 3,\n    COAP_OPTION_ETAG = 4,\n    COAP_OPTION_IF_NONE_MATCH = 5,\n    COAP_OPTION_OBSERVE = 6,\n    COAP_OPTION_URI_PORT = 7,\n    COAP_OPTION_LOCATION_PATH = 8,\n    COAP_OPTION_URI_PATH = 11,\n    COAP_OPTION_CONTENT_FORMAT = 12,\n    COAP_OPTION_MAX_AGE = 14,\n    COAP_OPTION_URI_QUERY = 15,\n    COAP_OPTION_ACCEPT = 17,\n    COAP_OPTION_LOCATION_QUERY = 20,\n    COAP_OPTION_PROXY_URI = 35,\n    COAP_OPTION_PROXY_SCHEME = 39\n} coap_option_num_t;\n\n//http://tools.ietf.org/html/rfc7252#section-12.1.1\ntypedef enum\n{\n    COAP_METHOD_GET = 1,\n    COAP_METHOD_POST = 2,\n    COAP_METHOD_PUT = 3,\n    COAP_METHOD_DELETE = 4\n} coap_method_t;\n\n//http://tools.ietf.org/html/rfc7252#section-12.1.1\ntypedef enum\n{\n    COAP_TYPE_CON = 0,\n    COAP_TYPE_NONCON = 1,\n    COAP_TYPE_ACK = 2,\n    COAP_TYPE_RESET = 3\n} coap_msgtype_t;\n\n//http://tools.ietf.org/html/rfc7252#section-5.2\n//http://tools.ietf.org/html/rfc7252#section-12.1.2\n#define MAKE_RSPCODE(clas, det) ((clas << 5) | (det))\ntypedef enum\n{\n    COAP_RSPCODE_CONTENT = MAKE_RSPCODE(2, 5),\n    COAP_RSPCODE_NOT_FOUND = MAKE_RSPCODE(4, 4),\n    COAP_RSPCODE_BAD_REQUEST = MAKE_RSPCODE(4, 0),\n    COAP_RSPCODE_CHANGED = MAKE_RSPCODE(2, 4)\n} coap_responsecode_t;\n\n//http://tools.ietf.org/html/rfc7252#section-12.3\ntypedef enum\n{\n    COAP_CONTENTTYPE_NONE = -1, // bodge to allow us not to send option block\n    COAP_CONTENTTYPE_TEXT_PLAIN = 0,\n    COAP_CONTENTTYPE_APPLICATION_LINKFORMAT = 40,\n    COAP_CONTENTTYPE_APPLICATION_XML = 41,\n    COAP_CONTENTTYPE_APPLICATION_OCTECT_STREAM = 42,\n    COAP_CONTENTTYPE_APPLICATION_EXI = 47,\n    COAP_CONTENTTYPE_APPLICATION_JSON = 50,\n} coap_content_type_t;\n\n///////////////////////\n\ntypedef enum\n{\n    COAP_ERR_NONE = 0,\n    COAP_ERR_HEADER_TOO_SHORT = 1,\n    COAP_ERR_VERSION_NOT_1 = 2,\n    COAP_ERR_TOKEN_TOO_SHORT = 3,\n    COAP_ERR_OPTION_TOO_SHORT_FOR_HEADER = 4,\n    COAP_ERR_OPTION_TOO_SHORT = 5,\n    COAP_ERR_OPTION_OVERRUNS_PACKET = 6,\n    COAP_ERR_OPTION_TOO_BIG = 7,\n    COAP_ERR_OPTION_LEN_INVALID = 8,\n    COAP_ERR_BUFFER_TOO_SMALL = 9,\n    COAP_ERR_UNSUPPORTED = 10,\n    COAP_ERR_OPTION_DELTA_INVALID = 11,\n} coap_error_t;\n\n///////////////////////\n\ntypedef 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);\n#define MAX_SEGMENTS 2  // 2 = /foo/bar, 3 = /foo/bar/baz\ntypedef struct\n{\n    int count;\n    const char *elems[MAX_SEGMENTS];\n} coap_endpoint_path_t;\n\ntypedef struct\n{\n    coap_method_t method;               /* (i.e. POST, PUT or GET) */\n    coap_endpoint_func handler;         /* callback function which handles this \n                                         * type of endpoint (and calls \n                                         * coap_make_response() at some point) */\n    const coap_endpoint_path_t *path;   /* path towards a resource (i.e. foo/bar/) */ \n    const char *core_attr;              /* the 'ct' attribute, as defined in RFC7252, section 7.2.1.:\n                                         * \"The Content-Format code \"ct\" attribute \n                                         * provides a hint about the \n                                         * Content-Formats this resource returns.\" \n                                         * (Section 12.3. lists possible ct values.) */\n} coap_endpoint_t;\n\n\n///////////////////////\nvoid coap_dumpPacket(coap_packet_t *pkt);\nint coap_parse(coap_packet_t *pkt, const uint8_t *buf, size_t buflen);\nint coap_buffer_to_string(char *strbuf, size_t strbuflen, const coap_buffer_t *buf);\nconst coap_option_t *coap_findOptions(const coap_packet_t *pkt, uint8_t num, uint8_t *count);\nint coap_build(uint8_t *buf, size_t *buflen, const coap_packet_t *pkt);\nvoid coap_dump(const uint8_t *buf, size_t buflen, bool bare);\nint 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);\nint coap_handle_req(coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt);\nvoid coap_option_nibble(uint32_t value, uint8_t *nibble);\nvoid coap_setup(void);\nvoid endpoint_setup(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "endpoints.c",
    "content": "#include <stdbool.h>\n#include <string.h>\n#include \"coap.h\"\n\nstatic char light = '0';\n\nconst uint16_t rsplen = 1500;\nstatic char rsp[1500] = \"\";\nvoid build_rsp(void);\n\n#ifdef ARDUINO\n#include \"Arduino.h\"\nstatic int led = 6;\nvoid endpoint_setup(void)\n{                \n    pinMode(led, OUTPUT);     \n    build_rsp();\n}\n#else\n#include <stdio.h>\nvoid endpoint_setup(void)\n{\n    build_rsp();\n}\n#endif\n\nstatic const coap_endpoint_path_t path_well_known_core = {2, {\".well-known\", \"core\"}};\nstatic 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)\n{\n    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);\n}\n\nstatic const coap_endpoint_path_t path_light = {1, {\"light\"}};\nstatic 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)\n{\n    return coap_make_response(scratch, outpkt, (const uint8_t *)&light, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);\n}\n\nstatic 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)\n{\n    if (inpkt->payload.len == 0)\n        return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_BAD_REQUEST, COAP_CONTENTTYPE_TEXT_PLAIN);\n    if (inpkt->payload.p[0] == '1')\n    {\n        light = '1';\n#ifdef ARDUINO\n        digitalWrite(led, HIGH);\n#else\n        printf(\"ON\\n\");\n#endif\n        return coap_make_response(scratch, outpkt, (const uint8_t *)&light, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN);\n    }\n    else\n    {\n        light = '0';\n#ifdef ARDUINO\n        digitalWrite(led, LOW);\n#else\n        printf(\"OFF\\n\");\n#endif\n        return coap_make_response(scratch, outpkt, (const uint8_t *)&light, 1, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CHANGED, COAP_CONTENTTYPE_TEXT_PLAIN);\n    }\n}\n\nconst coap_endpoint_t endpoints[] =\n{\n    {COAP_METHOD_GET, handle_get_well_known_core, &path_well_known_core, \"ct=40\"},\n    {COAP_METHOD_GET, handle_get_light, &path_light, \"ct=0\"},\n    {COAP_METHOD_PUT, handle_put_light, &path_light, NULL},\n    {(coap_method_t)0, NULL, NULL, NULL}\n};\n\nvoid build_rsp(void)\n{\n    uint16_t len = rsplen;\n    const coap_endpoint_t *ep = endpoints;\n    int i;\n\n    len--; // Null-terminated string\n\n    while(NULL != ep->handler)\n    {\n        if (NULL == ep->core_attr) {\n            ep++;\n            continue;\n        }\n\n        if (0 < strlen(rsp)) {\n            strncat(rsp, \",\", len);\n            len--;\n        }\n\n        strncat(rsp, \"<\", len);\n        len--;\n\n        for (i = 0; i < ep->path->count; i++) {\n            strncat(rsp, \"/\", len);\n            len--;\n\n            strncat(rsp, ep->path->elems[i], len);\n            len -= strlen(ep->path->elems[i]);\n        }\n\n        strncat(rsp, \">;\", len);\n        len -= 2;\n\n        strncat(rsp, ep->core_attr, len);\n        len -= strlen(ep->core_attr);\n\n        ep++;\n    }\n}\n\n"
  },
  {
    "path": "library.json",
    "content": "{\n  \"name\": \"microcoap\",\n  \"keywords\": \"coap, web\",\n  \"description\": \"A small CoAP implementation for microcontrollers\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/1248/microcoap.git\"\n  },\n  \"authors\": {\n    \"name\": \"Toby Jaffey\",\n    \"url\": \"http://twitter.com/tobyjaffey\"\n  },  \n  \"exclude\": [\n    \"main-posix.c\",\n    \"microcoap.ino\"\n  ],\n  \"examples\": \"microcoap.ino\",\n  \"frameworks\": \"arduino\",\n  \"platforms\": \"*\"\n}\n"
  },
  {
    "path": "main-posix.c",
    "content": "#include <sys/socket.h>\n#include <netinet/in.h>\n#include <stdio.h>\n#include <stdbool.h>\n#include <strings.h>\n\n#include \"coap.h\"\n\n#define PORT 5683\n\nint main(int argc, char **argv)\n{\n    int fd;\n#ifdef IPV6\n    struct sockaddr_in6 servaddr, cliaddr;\n#else /* IPV6 */\n    struct sockaddr_in servaddr, cliaddr;\n#endif /* IPV6 */\n    uint8_t buf[4096];\n    uint8_t scratch_raw[4096];\n    coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)};\n\n#ifdef IPV6\n    fd = socket(AF_INET6,SOCK_DGRAM,0);\n#else /* IPV6 */\n    fd = socket(AF_INET,SOCK_DGRAM,0);\n#endif /* IPV6 */\n\n    bzero(&servaddr,sizeof(servaddr));\n#ifdef IPV6\n    servaddr.sin6_family = AF_INET6;\n    servaddr.sin6_addr = in6addr_any;\n    servaddr.sin6_port = htons(PORT);\n#else /* IPV6 */\n    servaddr.sin_family = AF_INET;\n    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);\n    servaddr.sin_port = htons(PORT);\n#endif /* IPV6 */\n    bind(fd,(struct sockaddr *)&servaddr, sizeof(servaddr));\n\n    endpoint_setup();\n\n    while(1)\n    {\n        int n, rc;\n        socklen_t len = sizeof(cliaddr);\n        coap_packet_t pkt;\n\n        n = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&cliaddr, &len);\n#ifdef DEBUG\n        printf(\"Received: \");\n        coap_dump(buf, n, true);\n        printf(\"\\n\");\n#endif\n\n        if (0 != (rc = coap_parse(&pkt, buf, n)))\n            printf(\"Bad packet rc=%d\\n\", rc);\n        else\n        {\n            size_t rsplen = sizeof(buf);\n            coap_packet_t rsppkt;\n#ifdef DEBUG\n            coap_dumpPacket(&pkt);\n#endif\n            coap_handle_req(&scratch_buf, &pkt, &rsppkt);\n\n            if (0 != (rc = coap_build(buf, &rsplen, &rsppkt)))\n                printf(\"coap_build failed rc=%d\\n\", rc);\n            else\n            {\n#ifdef DEBUG\n                printf(\"Sending: \");\n                coap_dump(buf, rsplen, true);\n                printf(\"\\n\");\n#endif\n#ifdef DEBUG\n                coap_dumpPacket(&rsppkt);\n#endif\n\n                sendto(fd, buf, rsplen, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "microcoap.ino",
    "content": "/*\n* WARNING - UDP_TX_PACKET_MAX_SIZE is hardcoded by Arduino to 24 bytes\n* This limits the size of possible outbound UDP packets\n*/\n\n#include <SPI.h>\n#include <Ethernet.h>\n#include <stdint.h>\n#include <EthernetUdp.h>\n#include \"coap.h\"\n\n#define PORT 5683\nstatic uint8_t mac[] = {0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02};\n\nEthernetClient client;\nEthernetUDP udp;\nuint8_t packetbuf[256];\nstatic uint8_t scratch_raw[32];\nstatic coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)};\n\nvoid setup()\n{\n    int i;\n    Serial.begin(9600);\n    while (!Serial) \n    {\n        ; // wait for serial port to connect. Needed for Leonardo only\n    }\n\n    // start the Ethernet connection:\n    if (Ethernet.begin(mac) == 0)\n    {\n        Serial.println(\"Failed to configure Ethernet using DHCP\");\n        while(1);\n    }\n    Serial.print(\"My IP address: \");\n    for (i=0;i<4;i++)\n    {\n        Serial.print(Ethernet.localIP()[i], DEC);\n        Serial.print(\".\"); \n    }\n    Serial.println();\n    udp.begin(PORT);\n\n    coap_setup();\n    endpoint_setup();\n}\n\nvoid udp_send(const uint8_t *buf, int buflen)\n{\n    udp.beginPacket(udp.remoteIP(), udp.remotePort());\n    while(buflen--)\n        udp.write(*buf++);\n    udp.endPacket();\n}\n\nvoid loop()\n{\n    int sz;\n    int rc;\n    coap_packet_t pkt;\n    int i;\n    \n    if ((sz = udp.parsePacket()) > 0)\n    {\n        udp.read(packetbuf, sizeof(packetbuf));\n\n        for (i=0;i<sz;i++)\n        {\n            Serial.print(packetbuf[i], HEX);\n            Serial.print(\" \");\n        }\n        Serial.println(\"\");\n\n        if (0 != (rc = coap_parse(&pkt, packetbuf, sz)))\n        {\n            Serial.print(\"Bad packet rc=\");\n            Serial.println(rc, DEC);\n        }\n        else\n        {\n            size_t rsplen = sizeof(packetbuf);\n            coap_packet_t rsppkt;\n            coap_handle_req(&scratch_buf, &pkt, &rsppkt);\n\n            memset(packetbuf, 0, UDP_TX_PACKET_MAX_SIZE);\n            if (0 != (rc = coap_build(packetbuf, &rsplen, &rsppkt)))\n            {\n                Serial.print(\"coap_build failed rc=\");\n                Serial.println(rc, DEC);\n            }\n            else\n            {\n                udp_send(packetbuf, rsplen);\n            }\n        }\n    }\n}\n\n"
  }
]