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); }
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); } }
/* * Server callback for /cli/stats. Accepts either a GET or a PUT. * * GET: Returns the count of packets sent by the CLI. * PUT: Updates the count of packets. Rejects an obviously bad request, but * allows any two byte value for example purposes. Semantically, the only * valid action is to set the value to 0. */ static ssize_t _stats_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len) { /* read coap method type in packet */ unsigned method_flag = coap_method2flag(coap_get_code_detail(pdu)); switch(method_flag) { case COAP_GET: gcoap_resp_init(pdu, buf, len, COAP_CODE_CONTENT); /* write the response buffer with the request count value */ size_t payload_len = fmt_u16_dec((char *)pdu->payload, req_count); return gcoap_finish(pdu, payload_len, COAP_FORMAT_TEXT); case COAP_PUT: /* convert the payload to an integer and update the internal value */ if (pdu->payload_len <= 5) { char payload[6] = { 0 }; memcpy(payload, (char *)pdu->payload, pdu->payload_len); req_count = (uint16_t)strtoul(payload, NULL, 10); return gcoap_response(pdu, buf, len, COAP_CODE_CHANGED); } else { return gcoap_response(pdu, buf, len, COAP_CODE_BAD_REQUEST); } } return 0; }
/* Handler für den "/dino/move"-Pfad */ static ssize_t _dino_move(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx) { (void)ctx; /* Wenn die Anfrage eine POST-Anfrage war */ if (coap_method2flag(coap_get_code_detail(pdu)) == COAP_POST) { /* Wiederverwende den GPIO-IRQ-Callback um den Dino zu bewegen */ _toggle_dino(NULL); /* Sende eine Antwort, dass die Anfrage erfolgreich bearbeitet wurde */ return gcoap_response(pdu, buf, len, COAP_CODE_VALID); } /* sonst */ else { /* lass die Bibliothek das die Antwort erstellen und senden */ return 0; } }
static ssize_t _luke_points(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx) { unsigned p = 0; unsigned code; (void)ctx; switch (coap_method2flag(coap_get_code_detail(pdu))) { case COAP_GET: { size_t payload_len; gcoap_resp_init(pdu, buf, len, COAP_CODE_CONTENT); mutex_lock(&_points_mutex); payload_len = sprintf((char *)pdu->payload, LUKE_PAYLOAD_FMT, _points); mutex_unlock(&_points_mutex); return gcoap_finish(pdu, payload_len, COAP_FORMAT_JSON); } case COAP_POST: printf("POST %s\n", (char *)pdu->url); if ((pdu->payload_len < LUKE_PAYLOAD_MIN_SIZE) || (pdu->payload_len > LUKE_PAYLOAD_MAX_SIZE) || (pdu->content_type != COAP_FORMAT_JSON) || (sscanf((char *)pdu->payload, LUKE_PAYLOAD_FMT, &p) != 1)) { printf("(%u < %u) || (%u > %u) || (%u != %u) || " "(payload unparsable)\n", pdu->payload_len, LUKE_PAYLOAD_MIN_SIZE, pdu->payload_len, LUKE_PAYLOAD_MAX_SIZE, pdu->content_type, COAP_FORMAT_JSON); code = COAP_CODE_BAD_REQUEST; } else { code = COAP_CODE_VALID; _increment_points(p); } puts("Sending response"); return gcoap_response(pdu, buf, len, code); default: return 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"); } }
/* 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; }