diff --git a/examples/gcoap/gcoap_cli.c b/examples/gcoap/gcoap_cli.c index a6ef88bacec7c1fbf423fa7474504d8b43798927..95c405e89ec466b06e922edbf56d6813a59ae783 100644 --- a/examples/gcoap/gcoap_cli.c +++ b/examples/gcoap/gcoap_cli.c @@ -72,8 +72,9 @@ static void _resp_handler(unsigned req_state, coap_pkt_t* pdu, 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 + unsigned content_type = coap_get_content_type(pdu); + if (content_type == COAP_FORMAT_TEXT + || 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 */ diff --git a/sys/include/net/gcoap.h b/sys/include/net/gcoap.h index 8ec4c3b7a04acb51ce9918d8879da4cb2a9a3b30..92b221fdec151f6238550ef682ffe0f7203e0568 100644 --- a/sys/include/net/gcoap.h +++ b/sys/include/net/gcoap.h @@ -252,28 +252,6 @@ extern "C" { #define GCOAP_PDU_BUF_SIZE (128) #endif -/** - * @brief Size of the buffer used to write options, other than Uri-Path, in a - * request - * - * Accommodates Content-Format and Uri-Queries - */ -#define GCOAP_REQ_OPTIONS_BUF (40) - -/** - * @brief Size of the buffer used to write options in a response - * - * Accommodates Content-Format. - */ -#define GCOAP_RESP_OPTIONS_BUF (8) - -/** - * @brief Size of the buffer used to write options in an Observe notification - * - * Accommodates Content-Format and Observe. - */ -#define GCOAP_OBS_OPTIONS_BUF (8) - /** * @brief Maximum number of requests awaiting a response */ @@ -506,6 +484,11 @@ void gcoap_register_listener(gcoap_listener_t *listener); /** * @brief Initializes a CoAP request PDU on a buffer. + + * @warning After you use this function, you may not add Options with option + * number less than COAP_OPT_URI_PATH. Otherwise, use the struct-based API + * described with @link net_nanocoap nanocoap @endlink to initialize the + * message. See the implementation of gcoap_req_init() itself as an example. * * @param[out] pdu Request metadata * @param[out] buf Buffer containing the PDU @@ -525,8 +508,14 @@ int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, /** * @brief Finishes formatting a CoAP PDU after the payload has been written * - * Assumes the PDU has been initialized with gcoap_req_init() or - * gcoap_resp_init(). + * Assumes the PDU has been initialized with a gcoap_xxx_init() function, like + * gcoap_req_init(). + * + * @warning To use this function, you only may have added an Option with + * option number less than COAP_OPT_CONTENT_FORMAT. Otherwise, use the + * struct-based API described with @link net_nanocoap nanocoap. @endlink With + * this API, you specify the format with coap_opt_add_uint(), prepare for the + * payload with coap_opt_finish(), and then write the payload. * * @param[in,out] pdu Request metadata * @param[in] payload_len Length of the payload, or 0 if none diff --git a/sys/include/net/nanocoap.h b/sys/include/net/nanocoap.h index ab2b3502403eb523e9e4c2ea59ee909192ca1b95..a6ed28efe5acaf218b16e74e11ab3966169371a0 100644 --- a/sys/include/net/nanocoap.h +++ b/sys/include/net/nanocoap.h @@ -175,7 +175,7 @@ extern "C" { /** * @brief Nanocoap-specific value to indicate no format specified */ -#define COAP_FORMAT_NONE (65535) +#define COAP_FORMAT_NONE (UINT16_MAX) /** * @name Nanocoap specific maximum values @@ -232,9 +232,6 @@ typedef struct { uint16_t options_len; /**< length of options array */ coap_optpos_t options[NANOCOAP_NOPTS_MAX]; /**< option offset array */ #ifdef MODULE_GCOAP - uint8_t url[NANOCOAP_URI_MAX]; /**< parsed request URL */ - uint8_t qs[NANOCOAP_QS_MAX]; /**< parsed query string */ - uint16_t content_type; /**< content type */ uint32_t observe_value; /**< observe value */ #endif } coap_pkt_t; diff --git a/sys/net/application_layer/cord/ep/cord_ep.c b/sys/net/application_layer/cord/ep/cord_ep.c index a2ea5f28f257fe74cd81814ba6cc047dc3ccc297..19af6a173e63931b862e9bcdc812ea074b00adcd 100644 --- a/sys/net/application_layer/cord/ep/cord_ep.c +++ b/sys/net/application_layer/cord/ep/cord_ep.c @@ -273,8 +273,11 @@ int cord_ep_register(const sock_udp_ep_t *remote, const char *regif) } /* set some packet options and write query string */ coap_hdr_set_type(pkt.hdr, COAP_TYPE_CON); + coap_opt_add_uint(&pkt, COAP_OPT_CONTENT_FORMAT, COAP_FORMAT_LINK); cord_common_add_qstring(&pkt); + pkt_len = coap_opt_finish(&pkt, COAP_OPT_FINISH_PAYLOAD); + /* add the resource description as payload */ res = gcoap_get_resource_list(pkt.payload, pkt.payload_len, COAP_FORMAT_LINK); @@ -282,9 +285,7 @@ int cord_ep_register(const sock_udp_ep_t *remote, const char *regif) retval = CORD_EP_ERR; goto end; } - - /* finish up the packet */ - pkt_len = gcoap_finish(&pkt, res, COAP_FORMAT_LINK); + pkt_len += res; /* send out the request */ res = gcoap_req_send2(buf, pkt_len, remote, _on_register); diff --git a/sys/net/application_layer/gcoap/gcoap.c b/sys/net/application_layer/gcoap/gcoap.c index ac0f770337874ef85aa8147469b79acb3fd3caed..79c26dc87b485aeaee9e4299282090f25824611e 100644 --- a/sys/net/application_layer/gcoap/gcoap.c +++ b/sys/net/application_layer/gcoap/gcoap.c @@ -38,14 +38,21 @@ #define GCOAP_RESOURCE_WRONG_METHOD -1 #define GCOAP_RESOURCE_NO_PATH -2 +/* + * Reduce payload length by this value for a request created with + * gcoap_req_init(), gcoap_resp_init(), and gcoap_obs_init(), respectively. + * Accommodates writing Content-Format option in gcoap_finish(). + */ +#define GCOAP_REQ_OPTIONS_BUF (4) +#define GCOAP_RESP_OPTIONS_BUF (4) +#define GCOAP_OBS_OPTIONS_BUF (4) + /* Internal functions */ static void *_event_loop(void *arg); static void _listen(sock_udp_t *sock); static ssize_t _well_known_core_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx); -static ssize_t _write_options(coap_pkt_t *pdu, uint8_t *buf, size_t len); static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len, sock_udp_ep_t *remote); -static ssize_t _finish_pdu(coap_pkt_t *pdu, uint8_t *buf, size_t len); static void _expire_request(gcoap_request_memo_t *memo); static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *pdu, const sock_udp_ep_t *remote); @@ -337,9 +344,6 @@ static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len, memcpy(&memo->token[0], pdu->token, memo->token_len); } DEBUG("gcoap: Registered observer for: %s\n", memo->resource->path); - /* generate initial notification value */ - uint32_t now = xtimer_now_usec(); - pdu->observe_value = (now >> GCOAP_OBS_TICK_EXPONENT) & 0xFFFFFF; } } else if (coap_get_observe(pdu) == COAP_OBS_DEREGISTER) { @@ -391,6 +395,12 @@ static int _find_resource(coap_pkt_t *pdu, const coap_resource_t **resource_ptr, /* Find path for CoAP msg among listener resources and execute callback. */ gcoap_listener_t *listener = _coap_state.listeners; + + uint8_t uri[NANOCOAP_URI_MAX]; + if (coap_get_uri_path(pdu, uri) <= 0) { + return GCOAP_RESOURCE_NO_PATH; + } + while (listener) { const coap_resource_t *resource = listener->resources; for (size_t i = 0; i < listener->resources_len; i++) { @@ -398,7 +408,7 @@ static int _find_resource(coap_pkt_t *pdu, const coap_resource_t **resource_ptr, resource++; } - int res = strcmp((char *)&pdu->url[0], resource->path); + int res = strcmp((char *)&uri[0], resource->path); if (res > 0) { continue; } @@ -423,29 +433,6 @@ static int _find_resource(coap_pkt_t *pdu, const coap_resource_t **resource_ptr, return ret; } -/* - * Finishes handling a PDU -- write options and reposition payload. - * - * Returns the size of the PDU within the buffer, or < 0 on error. - */ -static ssize_t _finish_pdu(coap_pkt_t *pdu, uint8_t *buf, size_t len) -{ - ssize_t hdr_len = _write_options(pdu, buf, len); - DEBUG("gcoap: header length: %i\n", (int)hdr_len); - - if (hdr_len > 0) { - /* move payload over unused space after options */ - if (pdu->payload_len) { - memmove(buf + hdr_len, pdu->payload, pdu->payload_len); - } - - return hdr_len + pdu->payload_len; - } - else { - return -1; /* generic failure code */ - } -} - /* * Finds the memo for an outstanding request within the _coap_state.open_reqs * array. Matches on remote endpoint and token. @@ -529,69 +516,6 @@ static ssize_t _well_known_core_handler(coap_pkt_t* pdu, uint8_t *buf, size_t le return gcoap_finish(pdu, (size_t)plen, COAP_FORMAT_LINK); } -/* - * Creates CoAP options and sets payload marker, if any. - * - * Returns length of header + options, or -EINVAL on illegal path. - */ -static ssize_t _write_options(coap_pkt_t *pdu, uint8_t *buf, size_t len) -{ - uint8_t last_optnum = 0; - (void)len; - - uint8_t *bufpos = buf + coap_get_total_hdr_len(pdu); /* position for write */ - - /* Observe for notification or registration response */ - if (coap_get_code_class(pdu) == COAP_CLASS_SUCCESS && coap_has_observe(pdu)) { - uint32_t nval = htonl(pdu->observe_value); - uint8_t *nbyte = (uint8_t *)&nval; - unsigned i; - /* find address of non-zero MSB; max 3 bytes */ - for (i = 1; i < 4; i++) { - if (*(nbyte+i) > 0) { - break; - } - } - bufpos += coap_put_option(bufpos, last_optnum, COAP_OPT_OBSERVE, - nbyte+i, 4-i); - last_optnum = COAP_OPT_OBSERVE; - } - - /* Uri-Path for request */ - if (coap_get_code_class(pdu) == COAP_CLASS_REQ) { - size_t url_len = strlen((char *)pdu->url); - if (url_len) { - if (pdu->url[0] != '/') { - DEBUG("gcoap: _write_options: path does not start with '/'\n"); - return -EINVAL; - } - bufpos += coap_opt_put_uri_path(bufpos, last_optnum, - (char *)pdu->url); - last_optnum = COAP_OPT_URI_PATH; - } - } - - /* Content-Format */ - if (pdu->content_type != COAP_FORMAT_NONE) { - bufpos += coap_put_option_ct(bufpos, last_optnum, pdu->content_type); - last_optnum = COAP_OPT_CONTENT_FORMAT; - } - - /* Uri-query for requests */ - if (coap_get_code_class(pdu) == COAP_CLASS_REQ) { - bufpos += coap_opt_put_uri_query(bufpos, last_optnum, - (char *)pdu->qs); - /* uncomment when further options are added below ... */ - /* last_optnum = COAP_OPT_URI_QUERY; */ - } - - /* write payload marker */ - if (pdu->payload_len) { - *bufpos++ = GCOAP_PAYLOAD_MARKER; - } - return bufpos - buf; -} - /* * Find registered observer for a remote address and port. * @@ -723,11 +647,7 @@ int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, { assert((path != NULL) && (path[0] == '/')); - (void)len; - pdu->hdr = (coap_hdr_t *)buf; - memset(pdu->url, 0, NANOCOAP_URL_MAX); - memset(pdu->qs, 0, NANOCOAP_QS_MAX); /* generate token */ #if GCOAP_TOKENLEN @@ -748,15 +668,8 @@ int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, #endif if (hdrlen > 0) { - /* Reserve some space between the header and payload to write options later */ - pdu->payload = buf + coap_get_total_hdr_len(pdu) + strlen(path) - + GCOAP_REQ_OPTIONS_BUF; - /* Payload length really zero at this point, but we set this to the available - * length in the buffer. Allows us to reconstruct buffer length later. */ - pdu->payload_len = len - (pdu->payload - buf); - pdu->content_type = COAP_FORMAT_NONE; - - memcpy(&pdu->url[0], path, strlen(path)); + coap_pkt_init(pdu, buf, len - GCOAP_REQ_OPTIONS_BUF, hdrlen); + coap_opt_add_string(pdu, COAP_OPT_URI_PATH, path, '/'); return 0; } else { @@ -765,14 +678,43 @@ int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, } } +/* + * Assumes pdu.payload_len attribute was reduced in gcoap_xxx_init() to + * ensure enough space in PDU buffer to write Content-Format option and + * payload marker here. + */ ssize_t gcoap_finish(coap_pkt_t *pdu, size_t payload_len, unsigned format) { - /* reconstruct full PDU buffer length */ - size_t len = pdu->payload_len + (pdu->payload - (uint8_t *)pdu->hdr); + assert( !(pdu->options_len) || + !(payload_len) || + (format == COAP_FORMAT_NONE) || + (pdu->options[pdu->options_len-1].opt_num < COAP_OPT_CONTENT_FORMAT)); + + if (payload_len) { + /* determine Content-Format option length */ + unsigned format_optlen = 1; + if (format == COAP_FORMAT_NONE) { + format_optlen = 0; + } + else if (format > 255) { + format_optlen = 3; + } + else if (format > 0) { + format_optlen = 2; + } - pdu->content_type = format; - pdu->payload_len = payload_len; - return _finish_pdu(pdu, (uint8_t *)pdu->hdr, len); + /* move payload to accommodate option and payload marker */ + memmove(pdu->payload+format_optlen+1, pdu->payload, payload_len); + + if (format_optlen) { + coap_opt_add_uint(pdu, COAP_OPT_CONTENT_FORMAT, format); + } + *pdu->payload++ = 0xFF; + } + /* must write option before updating PDU with actual length */ + pdu->payload_len = payload_len; + + return pdu->payload_len + (pdu->payload - (uint8_t *)pdu->hdr); } size_t gcoap_req_send(const uint8_t *buf, size_t len, const ipv6_addr_t *addr, @@ -906,12 +848,18 @@ int gcoap_resp_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, unsigned code) } coap_hdr_set_code(pdu->hdr, code); - /* Reserve some space between the header and payload to write options later */ - pdu->payload = buf + coap_get_total_hdr_len(pdu) + GCOAP_RESP_OPTIONS_BUF; - /* Payload length really zero at this point, but we set this to the available - * length in the buffer. Allows us to reconstruct buffer length later. */ - pdu->payload_len = len - (pdu->payload - buf); - pdu->content_type = COAP_FORMAT_NONE; + unsigned header_len = coap_get_total_hdr_len(pdu); + + pdu->options_len = 0; + pdu->payload = buf + header_len; + pdu->payload_len = len - header_len - GCOAP_RESP_OPTIONS_BUF; + + if (coap_get_observe(pdu) == COAP_OBS_REGISTER) { + /* generate initial notification value */ + uint32_t now = xtimer_now_usec(); + pdu->observe_value = (now >> GCOAP_OBS_TICK_EXPONENT) & 0xFFFFFF; + coap_opt_add_uint(pdu, COAP_OPT_OBSERVE, pdu->observe_value); + } return 0; } @@ -933,15 +881,11 @@ int gcoap_obs_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, memo->token_len, COAP_CODE_CONTENT, msgid); if (hdrlen > 0) { + coap_pkt_init(pdu, buf, len - GCOAP_OBS_OPTIONS_BUF, hdrlen); + uint32_t now = xtimer_now_usec(); pdu->observe_value = (now >> GCOAP_OBS_TICK_EXPONENT) & 0xFFFFFF; - - /* Reserve some space between the header and payload to write options later */ - pdu->payload = buf + coap_get_total_hdr_len(pdu) + GCOAP_OBS_OPTIONS_BUF; - /* Payload length really zero at this point, but we set this to the available - * length in the buffer. Allows us to reconstruct buffer length later. */ - pdu->payload_len = len - (pdu->payload - buf); - pdu->content_type = COAP_FORMAT_NONE; + coap_opt_add_uint(pdu, COAP_OPT_OBSERVE, pdu->observe_value); return GCOAP_OBS_INIT_OK; } @@ -1023,26 +967,25 @@ int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf) int gcoap_add_qstring(coap_pkt_t *pdu, const char *key, const char *val) { - size_t qs_len = strlen((char *)pdu->qs); - size_t key_len = strlen(key); + char qs[NANOCOAP_QS_MAX]; + size_t len = strlen(key); size_t val_len = (val) ? (strlen(val) + 1) : 0; - /* make sure if url_len + the new query string fit into the url buffer */ - if ((qs_len + key_len + val_len + 2) >= NANOCOAP_QS_MAX) { + /* test if the query string fits, account for the zero termination */ + if ((len + val_len + 1) >= NANOCOAP_QS_MAX) { return -1; } - pdu->qs[qs_len++] = '&'; - memcpy(&pdu->qs[qs_len], key, key_len); - qs_len += key_len; + memcpy(&qs[0], key, len); if (val) { - pdu->qs[qs_len++] = '='; - memcpy(&pdu->qs[qs_len], val, val_len); - qs_len += val_len; + qs[len] = '='; + /* the `=` character was already counted in `val_len`, so subtract it here */ + memcpy(&qs[len + 1], val, (val_len - 1)); + len += val_len; } - pdu->qs[qs_len] = '\0'; + qs[len] = '\0'; - return (int)qs_len; + return coap_opt_add_string(pdu, COAP_OPT_URI_QUERY, qs, '&'); } /** @} */ diff --git a/sys/net/application_layer/nanocoap/nanocoap.c b/sys/net/application_layer/nanocoap/nanocoap.c index cb887ca673bffb9ac4a4405ce325a5c6bd97348c..672d31b101bfd5c7fee100b418a754f5f11f14b7 100644 --- a/sys/net/application_layer/nanocoap/nanocoap.c +++ b/sys/net/application_layer/nanocoap/nanocoap.c @@ -128,9 +128,6 @@ int coap_parse(coap_pkt_t *pkt, uint8_t *buf, size_t len) } #ifdef MODULE_GCOAP - coap_get_uri_path(pkt, pkt->url); - pkt->content_type = coap_get_content_type(pkt); - if (coap_get_option_uint(pkt, COAP_OPT_OBSERVE, &pkt->observe_value) != 0) { pkt->observe_value = UINT32_MAX; } @@ -309,14 +306,10 @@ ssize_t coap_handle_req(coap_pkt_t *pkt, uint8_t *resp_buf, unsigned resp_buf_le unsigned method_flag = coap_method2flag(coap_get_code_detail(pkt)); -#ifdef MODULE_GCOAP - uint8_t *uri = pkt->url; -#else uint8_t uri[NANOCOAP_URI_MAX]; if (coap_get_uri_path(pkt, uri) <= 0) { return -EBADMSG; } -#endif DEBUG("nanocoap: URI path: \"%s\"\n", uri); for (unsigned i = 0; i < coap_resources_numof; i++) { diff --git a/tests/unittests/tests-gcoap/tests-gcoap.c b/tests/unittests/tests-gcoap/tests-gcoap.c index fd20ae4b993954eac889bbaa2a14c867fbb88e45..d24517d8aadba716a63907985355e6c1978d72a6 100644 --- a/tests/unittests/tests-gcoap/tests-gcoap.c +++ b/tests/unittests/tests-gcoap/tests-gcoap.c @@ -83,7 +83,10 @@ static void test_gcoap__client_get_req(void) TEST_ASSERT_EQUAL_INT(GCOAP_TOKENLEN, coap_get_token_len(&pdu)); TEST_ASSERT_EQUAL_INT(hdr_fixed_len + GCOAP_TOKENLEN, coap_get_total_hdr_len(&pdu)); TEST_ASSERT_EQUAL_INT(COAP_TYPE_NON, coap_get_type(&pdu)); - TEST_ASSERT_EQUAL_STRING(&path[0], (char *)&pdu.url[0]); + + char uri[NANOCOAP_URI_MAX] = {0}; + coap_get_uri_path(&pdu, (uint8_t *)&uri[0]); + TEST_ASSERT_EQUAL_STRING(&path[0], &uri[0]); TEST_ASSERT_EQUAL_INT(0, pdu.payload_len); TEST_ASSERT_EQUAL_INT(sizeof(pdu_data), len); } @@ -124,6 +127,61 @@ static void test_gcoap__client_get_resp(void) } } +/* + * Client PUT request success case. Test request generation. + * Set value of /riot/value resource to 1 from nanocoap server example. + */ +static void test_gcoap__client_put_req(void) +{ + uint8_t buf[GCOAP_PDU_BUF_SIZE]; + coap_pkt_t pdu; + size_t len; + char path[] = "/riot/value"; + char payload[] = "1"; + + gcoap_req_init(&pdu, buf, GCOAP_PDU_BUF_SIZE, COAP_METHOD_PUT, path); + memcpy(pdu.payload, payload, 1); + len = gcoap_finish(&pdu, 1, COAP_FORMAT_TEXT); + + coap_parse(&pdu, buf, len); + + TEST_ASSERT_EQUAL_INT(COAP_METHOD_PUT, coap_get_code(&pdu)); + TEST_ASSERT_EQUAL_INT(1, pdu.payload_len); + TEST_ASSERT_EQUAL_INT('1', (char)*pdu.payload); +} + +/* + * Builds on get_req test, to test gcoap_add_qstring() to add Uri-Query + * options. + */ +static void test_gcoap__client_get_query(void) +{ + uint8_t buf[GCOAP_PDU_BUF_SIZE]; + coap_pkt_t pdu; + char path[] = "/time"; + char key1[] = "ab"; + char val1[] = "cde"; + char key2[] = "f"; + char expected[] = "ab=cde&f"; + int optlen; + + gcoap_req_init(&pdu, buf, GCOAP_PDU_BUF_SIZE, COAP_METHOD_GET, path); + + optlen = gcoap_add_qstring(&pdu, key1, val1); + TEST_ASSERT_EQUAL_INT(7, optlen); + optlen = gcoap_add_qstring(&pdu, key2, NULL); + TEST_ASSERT_EQUAL_INT(2, optlen); + + size_t len = gcoap_finish(&pdu, 0, COAP_FORMAT_NONE); + + coap_parse(&pdu, buf, len); + + char query[20] = {0}; + coap_get_uri_query(&pdu, (uint8_t *)&query[0]); + /* skip initial '&' from coap_get_uri_query() */ + TEST_ASSERT_EQUAL_STRING(&expected[0], &query[1]); +} + /* * Helper for server_get tests below. * Request from libcoap example for gcoap_cli /cli/stats resource @@ -158,7 +216,10 @@ static void test_gcoap__server_get_req(void) 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(0, pdu.payload_len); - TEST_ASSERT_EQUAL_STRING("/cli/stats", (char *) &pdu.url[0]); + + char uri[NANOCOAP_URI_MAX] = {0}; + coap_get_uri_path(&pdu, (uint8_t *)&uri[0]); + TEST_ASSERT_EQUAL_STRING("/cli/stats", &uri[0]); } /* @@ -283,6 +344,8 @@ Test *tests_gcoap_tests(void) EMB_UNIT_TESTFIXTURES(fixtures) { new_TestFixture(test_gcoap__client_get_req), new_TestFixture(test_gcoap__client_get_resp), + new_TestFixture(test_gcoap__client_put_req), + new_TestFixture(test_gcoap__client_get_query), new_TestFixture(test_gcoap__server_get_req), new_TestFixture(test_gcoap__server_get_resp), new_TestFixture(test_gcoap__server_con_req),