diff --git a/coap.c b/coap.c index 98f3fe7..90c8c4a 100644 --- a/coap.c +++ b/coap.c @@ -151,7 +151,7 @@ int coap_make_request(const uint16_t msgid, const coap_buffer_t* tok, pkt->hdr.tkl = 0; pkt->hdr.code = resource->method; pkt->hdr.id = msgid; - pkt->numopts = 1; + pkt->numopts = 0; // set token if (tok) { pkt->hdr.tkl = tok->len; @@ -167,12 +167,14 @@ int coap_make_request(const uint16_t msgid, const coap_buffer_t* tok, pkt->opts[i].num = COAP_OPTION_URI_PATH; pkt->opts[i].buf.p = (const uint8_t *) path->items[i]; pkt->opts[i].buf.len = strlen(path->items[i]); + pkt->numopts++; } // set content type, if present afterwards if (COAP_GET_CONTENTTYPE(resource->content_type, 2) != COAP_CONTENTTYPE_NONE) { pkt->opts[i].num = COAP_OPTION_CONTENT_FORMAT; pkt->opts[i].buf.p = resource->content_type; pkt->opts[i].buf.len = 2; + pkt->numopts++; } // attach payload pkt->payload.p = content; @@ -259,6 +261,40 @@ int coap_handle_request(coap_resource_t *resources, NULL, NULL, 0, pkt); } +int coap_handle_response(coap_resource_t *resources, + const coap_packet_t *reqpkt, + coap_packet_t *rsppkt) +{ + if (reqpkt->hdr.id != rsppkt->hdr.id ) + return COAP_ERR_REQUEST_MSGID_MISMATCH; + if (reqpkt->hdr.tkl != rsppkt->hdr.tkl) + return COAP_ERR_REQUEST_TOKEN_MISMATCH; + else if (memcmp(reqpkt->tok.p, rsppkt->tok.p, reqpkt->tok.len) != 0) + return COAP_ERR_REQUEST_TOKEN_MISMATCH; + if (rsppkt->hdr.code >= COAP_RSPCODE_BAD_REQUEST) + return COAP_ERR_RESPONSE; + uint8_t count; + const coap_option_t *opt = _find_options(reqpkt, COAP_OPTION_URI_PATH, &count); + // find handler for requested resource + for (coap_resource_t *rs = resources; rs->handler && opt; ++rs) { + if (count == rs->path->count) { + int i; + for (i = 0; i < count; ++i) { + if (opt[i].buf.len != strlen(rs->path->items[i])) { + break; + } + if (memcmp(rs->path->items[i], opt[i].buf.p, opt[i].buf.len)) { + break; + } + } + if (i == count) { // matching resource found + return rs->handler(rs, reqpkt, rsppkt); + } + } + } + return COAP_ERR_REQUEST_NOT_FOUND; +} + int coap_make_link_format(const coap_resource_t *resources, char *buf, size_t buflen) { diff --git a/coap.h b/coap.h index de1e3a0..db37c0b 100644 --- a/coap.h +++ b/coap.h @@ -222,6 +222,10 @@ typedef enum COAP_ERR_UNSUPPORTED = 10, COAP_ERR_OPTION_DELTA_INVALID = 11, COAP_ERR_OPTION_NOT_FOUND = 12, + COAP_ERR_REQUEST_NOT_FOUND, + COAP_ERR_REQUEST_MSGID_MISMATCH, + COAP_ERR_REQUEST_TOKEN_MISMATCH, + COAP_ERR_RESPONSE, COAP_ERR_MAX = 99, } coap_error_t; #define COAP_SUCCESS COAP_ERR_NONE //!< Success return value if no error occured @@ -230,6 +234,7 @@ typedef enum { COAP_STATE_RDY = (COAP_ERR_MAX + 1), COAP_STATE_ACK, COAP_STATE_RSP, + COAP_STATE_REQ, } coap_state_t; @@ -396,7 +401,9 @@ int coap_handle_request(coap_resource_t *resources, const coap_packet_t *inpkt, coap_packet_t *pkt); -int coap_handle_response(); +int coap_handle_response(coap_resource_t *resources, + const coap_packet_t *reqpkt, + coap_packet_t *rsppkt); int coap_handle_packet(); /** diff --git a/tests/piggyback.c b/tests/piggyback.c index 640bf33..dafa168 100644 --- a/tests/piggyback.c +++ b/tests/piggyback.c @@ -6,7 +6,6 @@ #include #include "coap.h" -#include "coap_dump.h" const uint16_t rsplen = 128; static char rsp[128] = ""; @@ -109,4 +108,5 @@ int main(void) } } } + return 0; } diff --git a/tests/request.c b/tests/request.c new file mode 100644 index 0000000..c4ffbef --- /dev/null +++ b/tests/request.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "coap.h" + +#define DSTADDR "::1" +#define DSTPORT "5683" + +static const coap_resource_path_t path_well_known_core = {2, {".well-known", "core"}}; +static int handle_get_well_known_core(const coap_resource_t *resource, + const coap_packet_t *reqpkt, + coap_packet_t *rsppkt) +{ + printf("handle_get_well_known_core\n"); + printf("%.*s\n", (int)rsppkt->payload.len, (char *)rsppkt->payload.p); + return COAP_STATE_REQ; +} + +coap_resource_t resources[] = +{ + {COAP_STATE_RDY, COAP_METHOD_GET, COAP_TYPE_ACK, + handle_get_well_known_core, &path_well_known_core, + COAP_SET_CONTENTTYPE(COAP_CONTENTTYPE_APP_LINKFORMAT)}, + {(coap_state_t)0, (coap_method_t)0, (coap_msgtype_t)0, + NULL, NULL, + COAP_SET_CONTENTTYPE(COAP_CONTENTTYPE_NONE)} +}; + +int main(void) +{ + int fd; + struct addrinfo hints, *dstinfo, *p; + struct sockaddr_storage cliaddr; + int rv; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + + if ((rv = getaddrinfo(DSTADDR, DSTPORT, &hints, &dstinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return 1; + } + + for (p = dstinfo; p != NULL; p = p->ai_next) { + if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + perror("socket"); + continue; + } + break; + } + if (p == NULL) { + fprintf(stderr, "failed to bind socket\n"); + return 2; + } + + int n, rc; + socklen_t len = sizeof(cliaddr); + coap_packet_t req, rsp; + uint16_t msgid = 1; + printf(" + coap_make_request\n"); + coap_make_request(msgid, NULL, &resources[0], NULL, 0, &req); + uint8_t buf[1024]; + size_t buflen = sizeof(buf); + if (0 != (rc = coap_build(&req, buf, &buflen))) { + printf("coap_build failed rc=%d\n", rc); + return 1; + } + else { + printf(" + send request\n"); + if ((n = sendto(fd, buf, buflen, 0, p->ai_addr, p->ai_addrlen)) == -1) { + perror("sendto"); + return 1; + } + printf(" + wait for response ...\n"); + for (int state = 0; state != COAP_STATE_REQ; ) { + n = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&cliaddr, &len); + printf(" +++ received message of %d bytes\n", n); + if (0 != (rc = coap_parse(buf, n, &rsp))) { + printf("Bad packet rc=%d\n", rc); + return 1; + } + state = coap_handle_response(resources, &req, &rsp); + } + } + // cleanup and exit + freeaddrinfo(dstinfo); + close(fd); + return 0; +}