Beispiel #1
0
void coap_pretty_print(coap_pdu *pdu)
{
  coap_option opt;

  opt.num = 0;

  if (coap_validate_pkt(pdu) == CE_NONE){
      printf(" ------ Valid CoAP Packet (%zi) ------ \n", pdu->len);
      printf("Type:  %i\n",coap_get_type(pdu));
      printf("Code:  %i.%02i\n", coap_get_code_class(pdu), coap_get_code_detail(pdu));
      printf("MID:   0x%X\n", coap_get_mid(pdu));
      printf("Token: 0x%llX\n", coap_get_token(pdu));

      while ((opt = coap_get_option(pdu, &opt)).num != 0){
        if (opt.num == 0)
          break;

        printf("Option: %i\n", opt.num);
        if (opt.val != NULL && opt.len != 0)
          printf(" Value: %.*s (%zi)\n", (int)opt.len, opt.val, opt.len);
      }
      // Note: get_option returns payload pointer when it finds the payload marker
      if (opt.val != NULL && opt.len != 0)
        printf("Payload: %.*s (%zi)\n", (int)opt.len, opt.val, opt.len);
    } else {
      printf(" ------ Non-CoAP Message (%zi) ------ \n", pdu->len);
      hex_dump(pdu->buf, pdu->len);
    }
}
Beispiel #2
0
ssize_t coap_handle_req(coap_pkt_t *pkt, uint8_t *resp_buf, unsigned resp_buf_len)
{
    if (coap_get_code_class(pkt) != COAP_REQ) {
        DEBUG("coap_handle_req(): not a request.\n");
        return -EBADMSG;
    }

    if (pkt->hdr->code == 0) {
        return coap_build_reply(pkt, COAP_CODE_EMPTY, resp_buf, resp_buf_len, 0);
    }

    unsigned method_flag = coap_method2flag(coap_get_code_detail(pkt));

    for (unsigned i = 0; i < coap_resources_numof; i++) {
        const coap_resource_t *resource = &coap_resources[i];
        if (!(resource->methods & method_flag)) {
            continue;
        }

        int res = strcmp((char *)pkt->url, resource->path);
        if (res > 0) {
            continue;
        }
        else if (res < 0) {
            break;
        }
        else {
            return resource->handler(pkt, resp_buf, resp_buf_len, resource->context);
        }
    }

    return coap_build_reply(pkt, COAP_CODE_404, resp_buf, resp_buf_len, 0);
}
Beispiel #3
0
/*
 * Client GET response success case. Test parsing response.
 * Response for /time resource from libcoap example
 */
static void test_gcoap__client_get_resp(void)
{
    uint8_t buf[GCOAP_PDU_BUF_SIZE];
    coap_pkt_t pdu;
    int res;
    char exp_payload[] = "Oct 22 10:46:48";

    uint8_t pdu_data[] = {
        0x52, 0x45, 0xe6, 0x02, 0x9b, 0xce, 0xc0, 0x21,
        0x01, 0xff, 0x4f, 0x63, 0x74, 0x20, 0x32, 0x32,
        0x20, 0x31, 0x30, 0x3a, 0x34, 0x36, 0x3a, 0x34,
        0x38
    };
    memcpy(buf, pdu_data, sizeof(pdu_data));

    res = coap_parse(&pdu, &buf[0], sizeof(pdu_data));

    TEST_ASSERT_EQUAL_INT(0, res);
    TEST_ASSERT_EQUAL_INT(COAP_CLASS_SUCCESS, coap_get_code_class(&pdu));
    TEST_ASSERT_EQUAL_INT(GCOAP_TOKENLEN, coap_get_token_len(&pdu));
    TEST_ASSERT_EQUAL_INT(4 + GCOAP_TOKENLEN, coap_get_total_hdr_len(&pdu));
    TEST_ASSERT_EQUAL_INT(COAP_TYPE_NON, coap_get_type(&pdu));
    TEST_ASSERT_EQUAL_INT(strlen(exp_payload), pdu.payload_len);

    for (size_t i = 0; i < strlen(exp_payload); i++) {
        TEST_ASSERT_EQUAL_INT(exp_payload[i], pdu.payload[i]);
    }
}
Beispiel #4
0
/*
 * Server GET response success case. Test writing response.
 * Response for libcoap example for gcoap_cli /cli/stats resource
 */
static void test_gcoap__server_get_resp(void)
{
    uint8_t buf[GCOAP_PDU_BUF_SIZE];
    coap_pkt_t pdu;

    /* read request */
    _read_cli_stats_req(&pdu, &buf[0]);

    /* generate response */
    gcoap_resp_init(&pdu, &buf[0], sizeof(buf), COAP_CODE_CONTENT);
    char resp_payload[]  = "2";
    memcpy(&pdu.payload[0], &resp_payload[0], strlen(resp_payload));
    ssize_t res = gcoap_finish(&pdu, strlen(resp_payload), COAP_FORMAT_TEXT);

    uint8_t resp_data[] = {
        0x52, 0x45, 0x20, 0xb6, 0x35, 0x61, 0xc0, 0xff,
        0x32
    };

    TEST_ASSERT_EQUAL_INT(COAP_CLASS_SUCCESS, coap_get_code_class(&pdu));
    TEST_ASSERT_EQUAL_INT(2, coap_get_token_len(&pdu));
    TEST_ASSERT_EQUAL_INT(4 + 2, coap_get_total_hdr_len(&pdu));
    TEST_ASSERT_EQUAL_INT(COAP_TYPE_NON, coap_get_type(&pdu));
    TEST_ASSERT_EQUAL_INT(strlen(resp_payload), pdu.payload_len);
    TEST_ASSERT_EQUAL_INT(sizeof(resp_data), res);

    for (size_t i = 0; i < strlen(resp_payload); i++) {
        TEST_ASSERT_EQUAL_INT(resp_payload[i], pdu.payload[i]);
    }
}
Beispiel #5
0
/* Listen for an incoming CoAP message. */
static void _listen(sock_udp_t *sock)
{
    coap_pkt_t pdu;
    uint8_t buf[GCOAP_PDU_BUF_SIZE];
    sock_udp_ep_t remote;
    gcoap_request_memo_t *memo = NULL;
    uint8_t open_reqs = gcoap_op_state();

    ssize_t res = sock_udp_recv(sock, buf, sizeof(buf),
                                open_reqs > 0 ? GCOAP_RECV_TIMEOUT : SOCK_NO_TIMEOUT,
                                &remote);
    if (res <= 0) {
#if ENABLE_DEBUG
        if (res < 0 && res != -ETIMEDOUT) {
            DEBUG("gcoap: udp recv failure: %d\n", res);
        }
#endif
        return;
    }

    res = coap_parse(&pdu, buf, res);
    if (res < 0) {
        DEBUG("gcoap: parse failure: %d\n", res);
        /* If a response, can't clear memo, but it will timeout later. */
        return;
    }

    if (pdu.hdr->code == COAP_CODE_EMPTY) {
        DEBUG("gcoap: empty messages not handled yet\n");
        return;

    /* incoming request */
    } else if (coap_get_code_class(&pdu) == COAP_CLASS_REQ) {
        if (coap_get_type(&pdu) == COAP_TYPE_NON
                || coap_get_type(&pdu) == COAP_TYPE_CON) {
            size_t pdu_len = _handle_req(&pdu, buf, sizeof(buf), &remote);
            if (pdu_len > 0) {
                sock_udp_send(sock, buf, pdu_len, &remote);
            }
        }
        else {
            DEBUG("gcoap: illegal request type: %u\n", coap_get_type(&pdu));
            return;
        }
    }

    /* incoming response */
    else {
        _find_req_memo(&memo, &pdu, &remote);
        if (memo) {
            xtimer_remove(&memo->response_timer);
            memo->state = GCOAP_MEMO_RESP;
            memo->resp_handler(memo->state, &pdu, &remote);
            memo->state = GCOAP_MEMO_UNUSED;
        }
    }
}
Beispiel #6
0
/*
 * Response callback.
 */
static void _resp_handler(unsigned req_state, coap_pkt_t* pdu,
                          sock_udp_ep_t *remote)
{
    (void)remote;       /* not interested in the source currently */

    if (req_state == GCOAP_MEMO_TIMEOUT) {
        printf("gcoap: timeout for msg ID %02u\n", coap_get_id(pdu));
        return;
    }
    else if (req_state == GCOAP_MEMO_ERR) {
        printf("gcoap: error in response\n");
        return;
    }

    char *class_str = (coap_get_code_class(pdu) == COAP_CLASS_SUCCESS)
                            ? "Success" : "Error";
    printf("gcoap: response %s, code %1u.%02u", class_str,
                                                coap_get_code_class(pdu),
                                                coap_get_code_detail(pdu));
    if (pdu->payload_len) {
        if (pdu->content_type == COAP_FORMAT_TEXT
                || pdu->content_type == COAP_FORMAT_LINK
                || coap_get_code_class(pdu) == COAP_CLASS_CLIENT_FAILURE
                || coap_get_code_class(pdu) == COAP_CLASS_SERVER_FAILURE) {
            /* Expecting diagnostic payload in failure cases */
            printf(", %u bytes\n%.*s\n", pdu->payload_len, pdu->payload_len,
                                                          (char *)pdu->payload);
        }
        else {
            printf(", %u bytes\n", pdu->payload_len);
            od_hex_dump(pdu->payload, pdu->payload_len, OD_WIDTH_DEFAULT);
        }
    }
    else {
        printf(", empty payload\n");
    }
}
Beispiel #7
0
/* http://tools.ietf.org/html/rfc7252#section-3
 *  0                   1                   2                   3
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |Ver| T |  TKL  |      Code     |          Message ID           |
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |   Token (if any, TKL bytes) ...
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |   Options (if any) ...
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |1 1 1 1 1 1 1 1|    Payload (if any) ...
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
int coap_parse(coap_pkt_t *pkt, uint8_t *buf, size_t len)
{
    uint8_t *urlpos = pkt->url;
    coap_hdr_t *hdr = (coap_hdr_t *)buf;

    pkt->hdr = hdr;

    uint8_t *pkt_pos = hdr->data;
    uint8_t *pkt_end = buf + len;

    memset(pkt->url, '\0', NANOCOAP_URL_MAX);
    pkt->payload_len = 0;
    pkt->observe_value = UINT32_MAX;

    /* token value (tkl bytes) */
    if (coap_get_token_len(pkt)) {
        pkt->token = pkt_pos;
        pkt_pos += coap_get_token_len(pkt);
    }
    else {
        pkt->token = NULL;
    }

    /* parse options */
    int option_nr = 0;
    while (pkt_pos != pkt_end) {
        uint8_t option_byte = *pkt_pos++;
        if (option_byte == 0xff) {
            pkt->payload = pkt_pos;
            pkt->payload_len = buf + len - pkt_pos;
            DEBUG("payload len = %u\n", pkt->payload_len);
            break;
        }
        else {
            int option_delta = _decode_value(option_byte >> 4, &pkt_pos, pkt_end);
            if (option_delta < 0) {
                DEBUG("bad op delta\n");
                return -EBADMSG;
            }
            int option_len = _decode_value(option_byte & 0xf, &pkt_pos, pkt_end);
            if (option_len < 0) {
                DEBUG("bad op len\n");
                return -EBADMSG;
            }
            option_nr += option_delta;
            DEBUG("option nr=%i len=%i\n", option_nr, option_len);

            switch (option_nr) {
                case COAP_OPT_URI_HOST:
                    DEBUG("nanocoap: ignoring Uri-Host option!\n");
                    break;
                case COAP_OPT_URI_PATH:
                    *urlpos++ = '/';
                    memcpy(urlpos, pkt_pos, option_len);
                    urlpos += option_len;
                    break;
                case COAP_OPT_CONTENT_FORMAT:
                    if (option_len == 0) {
                        pkt->content_type = 0;
                    }
                    else if (option_len == 1) {
                        pkt->content_type = *pkt_pos;
                    }
                    else if (option_len == 2) {
                        memcpy(&pkt->content_type, pkt_pos, 2);
                        pkt->content_type = ntohs(pkt->content_type);
                    }
                    break;
                case COAP_OPT_OBSERVE:
                    if (option_len < 4) {
                        pkt->observe_value = _decode_uint(pkt_pos, option_len);
                    }
                    else {
                        DEBUG("nanocoap: discarding packet with invalid option length.\n");
                        return -EBADMSG;
                    }
                    break;
                default:
                    DEBUG("nanocoap: unhandled option nr=%i len=%i critical=%u\n", option_nr, option_len, option_nr & 1);
                    if (option_nr & 1) {
                        DEBUG("nanocoap: discarding packet with unknown critical option.\n");
                        return -EBADMSG;
                    }
            }

            pkt_pos += option_len;
        }
    }

    DEBUG("coap pkt parsed. code=%u detail=%u payload_len=%u, 0x%02x\n",
          coap_get_code_class(pkt),
          coap_get_code_detail(pkt),
          pkt->payload_len, hdr->code);

    return 0;
}
Beispiel #8
0
/* Listen for an incoming CoAP message. */
static void _listen(sock_udp_t *sock)
{
    coap_pkt_t pdu;
    uint8_t buf[GCOAP_PDU_BUF_SIZE];
    sock_udp_ep_t remote;
    gcoap_request_memo_t *memo = NULL;
    uint8_t open_reqs = gcoap_op_state();

    /* We expect a -EINTR response here when unlimited waiting (SOCK_NO_TIMEOUT)
     * is interrupted when sending a message in gcoap_req_send2(). While a
     * request is outstanding, sock_udp_recv() is called here with limited
     * waiting so the request's timeout can be handled in a timely manner in
     * _event_loop(). */
    ssize_t res = sock_udp_recv(sock, buf, sizeof(buf),
                                open_reqs > 0 ? GCOAP_RECV_TIMEOUT : SOCK_NO_TIMEOUT,
                                &remote);
    if (res <= 0) {
#if ENABLE_DEBUG
        if (res < 0 && res != -ETIMEDOUT) {
            DEBUG("gcoap: udp recv failure: %d\n", res);
        }
#endif
        return;
    }

    res = coap_parse(&pdu, buf, res);
    if (res < 0) {
        DEBUG("gcoap: parse failure: %d\n", (int)res);
        /* If a response, can't clear memo, but it will timeout later. */
        return;
    }

    if (pdu.hdr->code == COAP_CODE_EMPTY) {
        DEBUG("gcoap: empty messages not handled yet\n");
        return;
    }

    /* validate class and type for incoming */
    switch (coap_get_code_class(&pdu)) {
    /* incoming request */
    case COAP_CLASS_REQ:
        if (coap_get_type(&pdu) == COAP_TYPE_NON
                || coap_get_type(&pdu) == COAP_TYPE_CON) {
            size_t pdu_len = _handle_req(&pdu, buf, sizeof(buf), &remote);
            if (pdu_len > 0) {
                ssize_t bytes = sock_udp_send(sock, buf, pdu_len, &remote);
                if (bytes <= 0) {
                    DEBUG("gcoap: send response failed: %d\n", (int)bytes);
                }
            }
        }
        else {
            DEBUG("gcoap: illegal request type: %u\n", coap_get_type(&pdu));
        }
        break;

    /* incoming response */
    case COAP_CLASS_SUCCESS:
    case COAP_CLASS_CLIENT_FAILURE:
    case COAP_CLASS_SERVER_FAILURE:
        _find_req_memo(&memo, &pdu, &remote);
        if (memo) {
            switch (coap_get_type(&pdu)) {
            case COAP_TYPE_NON:
            case COAP_TYPE_ACK:
                xtimer_remove(&memo->response_timer);
                memo->state = GCOAP_MEMO_RESP;
                if (memo->resp_handler) {
                    memo->resp_handler(memo->state, &pdu, &remote);
                }

                if (memo->send_limit >= 0) {        /* if confirmable */
                    *memo->msg.data.pdu_buf = 0;    /* clear resend PDU buffer */
                }
                memo->state = GCOAP_MEMO_UNUSED;
                break;
            case COAP_TYPE_CON:
                DEBUG("gcoap: separate CON response not handled yet\n");
                break;
            default:
                DEBUG("gcoap: illegal response type: %u\n", coap_get_type(&pdu));
                break;
            }
        }
        else {
            DEBUG("gcoap: msg not found for ID: %u\n", coap_get_id(&pdu));
        }
        break;
    default:
        DEBUG("gcoap: illegal code class: %u\n", coap_get_code_class(&pdu));
    }
}