• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libcoap unit tests
2  *
3  * Copyright (C) 2013--2021 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * SPDX-License-Identifier: BSD-2-Clause
6  *
7  * This file is part of the CoAP library libcoap. Please see
8  * README for terms of use.
9  */
10 
11 #include "test_common.h"
12 #include "test_wellknown.h"
13 
14 #include <assert.h>
15 #ifdef HAVE_NETINET_IN_H
16 #include <netinet/in.h>
17 #endif
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 #define TEST_PDU_SIZE 120
23 #define TEST_URI_LEN    4
24 
25 static coap_context_t *ctx;       /* Holds the coap context for most tests */
26 static coap_pdu_t *pdu;           /* Holds the parsed PDU for most tests */
27 static coap_session_t *session;   /* Holds a reference-counted session object
28                                    * that is passed to coap_wellknown_response(). */
29 
30 static void
t_wellknown1(void)31 t_wellknown1(void) {
32   coap_print_status_t result;
33   coap_resource_t *r;
34   unsigned char buf[40];
35   size_t buflen, offset, ofs;
36 
37   char teststr[] = {  /* </>;title="some attribute";ct=0 (31 chars) */
38     '<', '/', '>', ';', 't', 'i', 't', 'l',
39     'e', '=', '"', 's', 'o', 'm', 'e', ' ',
40     'a', 't', 't', 'r', 'i', 'b', 'u', 't',
41     'e', '"', ';', 'c', 't', '=', '0'
42   };
43 
44   r = coap_resource_init(NULL, 0);
45 
46   coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
47   coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"some attribute\""), 0);
48 
49   coap_add_resource(ctx, r);
50 
51   for (offset = 0; offset < sizeof(teststr); offset++) {
52     ofs = offset;
53     buflen = sizeof(buf);
54 
55     result = coap_print_link(r, buf, &buflen, &ofs);
56 
57     CU_ASSERT(result == sizeof(teststr) - offset);
58     CU_ASSERT(buflen == sizeof(teststr));
59     CU_ASSERT(memcmp(buf, teststr + offset, sizeof(teststr) - offset) == 0);
60   }
61 
62   /* offset points behind teststr */
63   ofs = offset;
64   buflen = sizeof(buf);
65   result = coap_print_link(r, buf, &buflen, &ofs);
66 
67   CU_ASSERT(result == 0);
68     CU_ASSERT(buflen == sizeof(teststr));
69 
70   /* offset exceeds buffer */
71   buflen = sizeof(buf);
72   ofs = buflen;
73   result = coap_print_link(r, buf, &buflen, &ofs);
74 
75   CU_ASSERT(result == 0);
76   CU_ASSERT(buflen == sizeof(teststr));
77 }
78 
79 static void
t_wellknown2(void)80 t_wellknown2(void) {
81   coap_print_status_t result;
82   coap_resource_t *r;
83   unsigned char buf[10];        /* smaller than teststr */
84   size_t buflen, offset, ofs;
85 
86   char teststr[] = {  /* ,</abcd>;if="one";obs (21 chars) */
87     '<', '/', 'a', 'b', 'c', 'd', '>', ';',
88     'i', 'f', '=', '"', 'o', 'n', 'e', '"',
89     ';', 'o', 'b', 's'
90   };
91 
92   r = coap_resource_init(coap_make_str_const("abcd"), 0);
93   coap_resource_set_get_observable(r, 1);
94   coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"one\""), 0);
95 
96   coap_add_resource(ctx, r);
97 
98   for (offset = 0; offset < sizeof(teststr) - sizeof(buf); offset++) {
99     ofs = offset;
100     buflen = sizeof(buf);
101 
102     result = coap_print_link(r, buf, &buflen, &ofs);
103 
104     CU_ASSERT(result == (COAP_PRINT_STATUS_TRUNC | sizeof(buf)));
105     CU_ASSERT(buflen == sizeof(teststr));
106     CU_ASSERT(ofs == 0);
107     CU_ASSERT(memcmp(buf, teststr + offset, sizeof(buf)) == 0);
108   }
109 
110   /* from here on, the resource description fits into buf */
111   for (; offset < sizeof(teststr); offset++) {
112     ofs = offset;
113     buflen = sizeof(buf);
114     result = coap_print_link(r, buf, &buflen, &ofs);
115 
116     CU_ASSERT(result == sizeof(teststr) - offset);
117     CU_ASSERT(buflen == sizeof(teststr));
118     CU_ASSERT(ofs == 0);
119     CU_ASSERT(memcmp(buf, teststr + offset,
120                      COAP_PRINT_OUTPUT_LENGTH(result)) == 0);
121   }
122 
123   /* offset exceeds buffer */
124   buflen = sizeof(buf);
125   ofs = offset;
126   result = coap_print_link(r, buf, &buflen, &ofs);
127   CU_ASSERT(result == 0);
128   CU_ASSERT(buflen == sizeof(teststr));
129   CU_ASSERT(ofs == offset - sizeof(teststr));
130 }
131 
132 static void
t_wellknown3(void)133 t_wellknown3(void) {
134   coap_print_status_t result;
135   int j;
136   coap_resource_t *r;
137   static char uris[2 * 1024];
138   unsigned char *uribuf = (unsigned char *)uris;
139   unsigned char buf[40];
140   size_t buflen = sizeof(buf);
141   size_t offset;
142   const uint16_t num_resources = (sizeof(uris) / TEST_URI_LEN) - 1;
143 
144   /* ,</0000> (TEST_URI_LEN + 4 chars) */
145   for (j = 0; j < num_resources; j++) {
146     int len = snprintf((char *)uribuf, TEST_URI_LEN + 1,
147                        "%0*d", TEST_URI_LEN, j);
148     coap_str_const_t uri_path = {.length = len, .s = uribuf};
149     r = coap_resource_init(&uri_path, 0);
150     coap_add_resource(ctx, r);
151     uribuf += TEST_URI_LEN;
152   }
153 
154   /* the following test assumes that the first two resources from
155    * t_wellknown1() and t_wellknown2() need more than buflen
156    * characters. Otherwise, CU_ASSERT(result > 0) will fail.
157    */
158   offset = num_resources * (TEST_URI_LEN + 4);
159   result = coap_print_wellknown(ctx, buf, &buflen, offset, NULL);
160   CU_ASSERT((result & COAP_PRINT_STATUS_ERROR) == 0 );
161   CU_ASSERT(COAP_PRINT_OUTPUT_LENGTH(result) > 0);
162 }
163 
164 /* Create wellknown response for request without Block-option. */
165 static void
t_wellknown4(void)166 t_wellknown4(void) {
167   coap_pdu_t *response;
168   coap_block_t block;
169 
170   response = coap_wellknown_response(ctx, session, pdu);
171 
172   CU_ASSERT_PTR_NOT_NULL(response);
173 
174   CU_ASSERT(coap_get_block(response, COAP_OPTION_BLOCK2, &block) != 0);
175 
176   CU_ASSERT(block.num == 0);
177   CU_ASSERT(block.m == 1);
178   CU_ASSERT(1 << (block.szx + 4)
179     == response->token + response->used_size - response->data);
180 
181   coap_delete_pdu(response);
182 }
183 
184 /* Create wellknown response for request with Block2-option and an szx
185  * value smaller than COAP_MAX_BLOCK_SZX.
186  */
187 static void
t_wellknown5(void)188 t_wellknown5(void) {
189   coap_pdu_t *response;
190   coap_block_t inblock = { .num = 1, .m = 0, .szx = 1 };
191   coap_block_t block;
192   unsigned char buf[3];
193 
194   if (!coap_add_option(pdu, COAP_OPTION_BLOCK2,
195                        coap_encode_var_safe(buf, sizeof(buf),
196                                             ((inblock.num << 4) |
197                                              (inblock.m << 3) |
198                                              inblock.szx)), buf)) {
199     CU_FAIL("cannot add Block2 option");
200     return;
201   }
202 
203   response = coap_wellknown_response(ctx, session, pdu);
204 
205   CU_ASSERT_PTR_NOT_NULL(response);
206 
207   CU_ASSERT(coap_get_block(response, COAP_OPTION_BLOCK2, &block) != 0);
208 
209   CU_ASSERT(block.num == inblock.num);
210   CU_ASSERT(block.m == 1);
211   CU_ASSERT(1 << (block.szx + 4)
212     == response->token + response->used_size - response->data);
213 
214   coap_delete_pdu(response);
215 }
216 
217 static void
t_wellknown6(void)218 t_wellknown6(void) {
219   coap_pdu_t *response;
220   coap_block_t block = { .num = 0, .szx = 6 };
221   unsigned char buf[TEST_PDU_SIZE];
222 
223 
224   do {
225     coap_pdu_clear(pdu, pdu->max_size);        /* clear PDU */
226 
227     pdu->type = COAP_MESSAGE_NON;
228     pdu->code = COAP_REQUEST_CODE_GET;
229     pdu->mid = 0x1234;
230 
231     CU_ASSERT_PTR_NOT_NULL(pdu);
232 
233     if (!pdu || !coap_add_option(pdu, COAP_OPTION_BLOCK2,
234                                  coap_encode_var_safe(buf, sizeof(buf),
235                                        ((block.num << 4) | block.szx)), buf)) {
236       CU_FAIL("cannot create request");
237       return;
238     }
239 
240     response = coap_wellknown_response(ctx, session, pdu);
241 
242     CU_ASSERT_PTR_NOT_NULL(response);
243 
244     /* coap_show_pdu(LOG_INFO, response); */
245 
246     CU_ASSERT(coap_get_block(response, COAP_OPTION_BLOCK2, &block) != 0);
247 
248     block.num++;
249     coap_delete_pdu(response);
250   } while (block.m == 1);
251 }
252 
253 static int
t_wkc_tests_create(void)254 t_wkc_tests_create(void) {
255   coap_address_t addr;
256 
257   coap_address_init(&addr);
258 
259   addr.size = sizeof(struct sockaddr_in6);
260   addr.addr.sin6.sin6_family = AF_INET6;
261   addr.addr.sin6.sin6_addr = in6addr_any;
262   addr.addr.sin6.sin6_port = htons(COAP_DEFAULT_PORT);
263 
264   ctx = coap_new_context(&addr);
265 
266   addr.addr.sin6.sin6_addr = in6addr_loopback;
267   session = coap_new_client_session(ctx, NULL, &addr, COAP_PROTO_UDP);
268 
269   pdu = coap_pdu_init(0, 0, 0, TEST_PDU_SIZE);
270 #if 0
271   /* add resources to coap context */
272   if (ctx && pdu) {
273     coap_resource_t *r;
274     static char _buf[2 * 1024];
275     unsigned char *buf = (unsigned char *)_buf;
276     int i;
277 
278     /* </>;title="some attribute";ct=0 (31 chars) */
279     r = coap_resource_init(NULL, 0, 0);
280 
281     coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
282     coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"some attribute\""), 0);
283     coap_add_resource(ctx, r);
284 
285     /* ,</abcd>;if="one";obs (21 chars) */
286     r = coap_resource_init((const uint8_t *)"abcd", 4, 0);
287     r->observable = 1;
288     coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"one\""), 0);
289 
290     coap_add_resource(ctx, r);
291 
292     /* ,</0000> (TEST_URI_LEN + 4 chars) */
293     for (i = 0; i < sizeof(_buf) / (TEST_URI_LEN + 4); i++) {
294       int len = snprintf((char *)buf, TEST_URI_LEN + 1,
295                          "%0*d", TEST_URI_LEN, i);
296       r = coap_resource_init(buf, len, 0);
297       coap_add_resource(ctx, r);
298       buf += TEST_URI_LEN + 1;
299     }
300 
301   }
302 #endif
303   return ctx == NULL || pdu == NULL;
304 }
305 
306 static int
t_wkc_tests_remove(void)307 t_wkc_tests_remove(void) {
308   coap_delete_pdu(pdu);
309   coap_free_context(ctx);
310   return 0;
311 }
312 
313 CU_pSuite
t_init_wellknown_tests(void)314 t_init_wellknown_tests(void) {
315   CU_pSuite suite;
316 
317   suite = CU_add_suite(".well-known/core", t_wkc_tests_create, t_wkc_tests_remove);
318   if (!suite) {                        /* signal error */
319     fprintf(stderr, "W: cannot add .well-known/core test suite (%s)\n",
320             CU_get_error_msg());
321 
322     return NULL;
323   }
324 
325 #define WKC_TEST(s,t)                                             \
326   if (!CU_ADD_TEST(s,t)) {                                        \
327     fprintf(stderr, "W: cannot add .well-known/core test (%s)\n", \
328             CU_get_error_msg());                                  \
329   }
330 
331   WKC_TEST(suite, t_wellknown1);
332   WKC_TEST(suite, t_wellknown2);
333   WKC_TEST(suite, t_wellknown3);
334   WKC_TEST(suite, t_wellknown4);
335   WKC_TEST(suite, t_wellknown5);
336   WKC_TEST(suite, t_wellknown6);
337 
338   return suite;
339 }
340 
341