libcoap  4.3.0rc1
block.c
Go to the documentation of this file.
1 /* block.c -- block transfer
2  *
3  * Copyright (C) 2010--2012,2015-2019 Olaf Bergmann <bergmann@tzi.org> and others
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8 
9 #include "coap2/coap_internal.h"
10 
11 #ifndef min
12 #define min(a,b) ((a) < (b) ? (a) : (b))
13 #endif
14 
15 unsigned int
16 coap_opt_block_num(const coap_opt_t *block_opt) {
17  unsigned int num = 0;
18  uint16_t len;
19 
20  len = coap_opt_length(block_opt);
21 
22  if (len == 0) {
23  return 0;
24  }
25 
26  if (len > 1) {
27  num = coap_decode_var_bytes(coap_opt_value(block_opt),
28  coap_opt_length(block_opt) - 1);
29  }
30 
31  return (num << 4) | ((*COAP_OPT_BLOCK_LAST(block_opt) & 0xF0) >> 4);
32 }
33 
34 int
35 coap_get_block(coap_pdu_t *pdu, uint16_t type, coap_block_t *block) {
36  coap_opt_iterator_t opt_iter;
37  coap_opt_t *option;
38 
39  assert(block);
40  memset(block, 0, sizeof(coap_block_t));
41 
42  if (pdu && (option = coap_check_option(pdu, type, &opt_iter)) != NULL) {
43  unsigned int num;
44 
45  block->szx = COAP_OPT_BLOCK_SZX(option);
46  if (COAP_OPT_BLOCK_MORE(option))
47  block->m = 1;
48 
49  /* The block number is at most 20 bits, so values above 2^20 - 1
50  * are illegal. */
51  num = coap_opt_block_num(option);
52  if (num > 0xFFFFF) {
53  return 0;
54  }
55  block->num = num;
56  return 1;
57  }
58 
59  return 0;
60 }
61 
62 int
63 coap_write_block_opt(coap_block_t *block, uint16_t type,
64  coap_pdu_t *pdu, size_t data_length) {
65  size_t start, want, avail;
66  unsigned char buf[4];
67 
68  assert(pdu);
69 
70  start = block->num << (block->szx + 4);
71  if (block->num != 0 && data_length <= start) {
72  coap_log(LOG_DEBUG, "illegal block requested\n");
73  return -2;
74  }
75 
76  assert(pdu->max_size > 0);
77  avail = pdu->max_size - pdu->used_size - pdu->hdr_size;
78  want = (size_t)1 << (block->szx + 4);
79 
80  /* check if entire block fits in message */
81  if (want <= avail) {
82  block->m = want < data_length - start;
83  } else {
84  /* Sender has requested a block that is larger than the remaining
85  * space in pdu. This is ok if the remaining data fits into the pdu
86  * anyway. The block size needs to be adjusted only if there is more
87  * data left that cannot be delivered in this message. */
88 
89  if (data_length - start <= avail) {
90 
91  /* it's the final block and everything fits in the message */
92  block->m = 0;
93  } else {
94  unsigned int szx;
95  int newBlockSize;
96 
97  /* we need to decrease the block size */
98  if (avail < 16) { /* bad luck, this is the smallest block size */
100  "not enough space, even the smallest block does not fit\n");
101  return -3;
102  }
103  newBlockSize = coap_flsll((long long)avail) - 5;
105  "decrease block size for %zu to %d\n", avail, newBlockSize);
106  szx = block->szx;
107  block->szx = newBlockSize;
108  block->m = 1;
109  block->num <<= szx - block->szx;
110  }
111  }
112 
113  /* to re-encode the block option */
114  coap_add_option(pdu, type, coap_encode_var_safe(buf, sizeof(buf),
115  ((block->num << 4) |
116  (block->m << 3) |
117  block->szx)),
118  buf);
119 
120  return 1;
121 }
122 
123 int
124 coap_add_block(coap_pdu_t *pdu, size_t len, const uint8_t *data,
125  unsigned int block_num, unsigned char block_szx) {
126  unsigned int start;
127  start = block_num << (block_szx + 4);
128 
129  if (len <= start)
130  return 0;
131 
132  return coap_add_data(pdu,
133  min(len - start, ((size_t)1 << (block_szx + 4))),
134  data + start);
135 }
136 
137 /*
138  * Note that the COAP_OPTION_ have to be added in the correct order
139  */
140 void
142  coap_session_t *session,
143  coap_pdu_t *request,
144  coap_pdu_t *response,
145  const coap_binary_t *token,
146  uint16_t media_type,
147  int maxage,
148  size_t length,
149  const uint8_t* data
150 ) {
151  coap_key_t etag;
152  unsigned char buf[4];
153  coap_block_t block2 = { 0, 0, 0 };
154  int block2_requested = 0;
155  coap_subscription_t *subscription = coap_find_observer(resource,
156  session, token);
157 
158  /*
159  * Need to check that a valid block is getting asked for so that the
160  * correct options are put into the PDU.
161  */
162  if (request) {
163  if (coap_get_block(request, COAP_OPTION_BLOCK2, &block2)) {
164  block2_requested = 1;
165  if (block2.num != 0 && length <= (block2.num << (block2.szx + 4))) {
166  coap_log(LOG_DEBUG, "Illegal block requested (%d > last = %zu)\n",
167  block2.num,
168  length >> (block2.szx + 4));
169  response->code = COAP_RESPONSE_CODE(400);
170  goto error;
171  }
172  }
173  }
174  else if (subscription && subscription->has_block2) {
175  block2 = subscription->block;
176  block2.num = 0;
177  block2_requested = 1;
178  }
179  response->code = COAP_RESPONSE_CODE(205);
180 
181  /* add etag for the resource */
182  memset(etag, 0, sizeof(etag));
183  coap_hash(data, length, etag);
184  coap_add_option(response, COAP_OPTION_ETAG, sizeof(etag), etag);
185 
186  if ((block2.num == 0) && subscription) {
188  coap_encode_var_safe(buf, sizeof (buf),
189  resource->observe),
190  buf);
191  }
192 
194  coap_encode_var_safe(buf, sizeof(buf),
195  media_type),
196  buf);
197 
198  if (maxage >= 0) {
199  coap_add_option(response,
201  coap_encode_var_safe(buf, sizeof(buf), maxage), buf);
202  }
203 
204  if (block2_requested) {
205  int res;
206 
207  res = coap_write_block_opt(&block2, COAP_OPTION_BLOCK2, response, length);
208 
209  switch (res) {
210  case -2: /* illegal block (caught above) */
211  response->code = COAP_RESPONSE_CODE(400);
212  goto error;
213  case -1: /* should really not happen */
214  assert(0);
215  /* fall through if assert is a no-op */
216  case -3: /* cannot handle request */
217  response->code = COAP_RESPONSE_CODE(500);
218  goto error;
219  default: /* everything is good */
220  ;
221  }
222 
223  coap_add_option(response,
225  coap_encode_var_safe8(buf, sizeof(buf), length),
226  buf);
227 
228  coap_add_block(response, length, data,
229  block2.num, block2.szx);
230  return;
231  }
232 
233  /*
234  * BLOCK2 not requested
235  */
236  if (!coap_add_data(response, length, data)) {
237  /*
238  * Insufficient space to add in data - use block mode
239  * set initial block size, will be lowered by
240  * coap_write_block_opt() automatically
241  */
242  block2.num = 0;
243  block2.szx = 6;
244  coap_write_block_opt(&block2, COAP_OPTION_BLOCK2, response, length);
245 
246  coap_add_option(response,
248  coap_encode_var_safe8(buf, sizeof(buf), length),
249  buf);
250 
251  coap_add_block(response, length, data,
252  block2.num, block2.szx);
253  }
254  return;
255 
256 error:
257  coap_add_data(response,
258  strlen(coap_response_phrase(response->code)),
259  (const unsigned char *)coap_response_phrase(response->code));
260 }
261 
262 void
264  uint8_t block_mode) {
265  context->block_mode = block_mode &= (COAP_BLOCK_USE_LIBCOAP |
267  if (!(block_mode & COAP_BLOCK_USE_LIBCOAP))
268  context->block_mode = 0;
269 }
270 
271 /*
272  * The block token match only matches on the bottom 32 bits
273  * [The upper 32 bits are incremented as different payloads are sent]
274  *
275  */
277 block_token_match(const uint8_t *a, size_t alen,
278  const uint8_t *b, size_t blen) {
279  size_t bias;
280  if (blen < 4)
281  return alen == blen && memcmp(a, b, blen) == 0;
282  bias = blen - 4;
283  return alen == blen && memcmp(a+bias, b+bias, 4) == 0;
284 }
285 
287 full_match(const uint8_t *a, size_t alen,
288  const uint8_t *b, size_t blen) {
289  return alen == blen && (alen == 0 || memcmp(a, b, alen) == 0);
290 }
291 
292 int
294  uint8_t type) {
295  coap_lg_crcv_t *cq;
296 
297  assert(session);
298  if (!session)
299  return 0;
300 
301  LL_FOREACH(session->lg_crcv, cq) {
302  if (cq->observe_set) {
303  if ((!token && !cq->app_token->length) || (token &&
304  full_match(token->s, token->length, cq->app_token->s,
305  cq->app_token->length))) {
306  uint8_t buf[4];
307  coap_mid_t mid;
308  coap_pdu_t * pdu = coap_pdu_duplicate(&cq->pdu,
309  session,
310  cq->base_token_length,
311  cq->base_token,
312  NULL);
313 
314  cq->observe_set = 0;
315  if (pdu == NULL)
316  return 0;
317  /* Need to make sure that this is the correct type */
318  pdu->type = type;
319 
321  coap_encode_var_safe(buf, sizeof(buf),
323  buf);
324  mid = coap_send(session, pdu);
325  if (mid != COAP_INVALID_MID)
326  return 1;
327  break;
328  }
329  }
330  }
331  return 0;
332 }
333 
334 int
336  coap_pdu_t *pdu,
337  coap_resource_t *resource,
338  const coap_string_t *query,
339  int maxage,
340  uint64_t etag,
341  size_t length,
342  const uint8_t *data,
343  coap_release_large_data_t release_func,
344  void *app_ptr) {
345 
346  ssize_t avail;
347  coap_block_t block;
348  size_t chunk;
349  coap_lg_xmit_t *lg_xmit = NULL;
350  uint8_t buf[8];
351  int have_block_defined = 0;
352  uint8_t blk_size;
353  uint16_t option;
354 
355  assert(pdu);
356 
357  if (!(session->block_mode & COAP_BLOCK_USE_LIBCOAP)) {
359  "** %s: coap_send_large: COAP_BLOCK_USE_LIBCOAP not enabled\n",
360  coap_session_str(session));
361  goto add_data;
362  }
363 
364 /* Block NUM max 20 bits and block size is "2**(SZX + 4)" and SZX max of 6 */
365 #define MAX_BLK_LEN (((1 << 20) - 1) * (1 << (6 + 4)))
366 
367  if (length > MAX_BLK_LEN) {
369  "Size of large buffer restricted to 0x%x bytes\n", MAX_BLK_LEN);
370  length = MAX_BLK_LEN;
371  }
372  /* Determine the block size to use, adding in sensible options if needed */
373  if (COAP_PDU_IS_REQUEST(pdu)) {
374  coap_lg_xmit_t *q;
375 
376  option = COAP_OPTION_BLOCK1;
377 
378  /* See if this token is already in use for large bodies (unlikely) */
379  LL_FOREACH_SAFE(session->lg_xmit, lg_xmit, q) {
380  if (full_match(pdu->token, pdu->token_length,
381  lg_xmit->b.b1.app_token->s,
382  lg_xmit->b.b1.app_token->length)) {
383  /* Unfortunately need to free this off as potential size change */
384  LL_DELETE(session->lg_xmit, lg_xmit);
385  coap_block_delete_lg_xmit(session, lg_xmit);
386  lg_xmit = NULL;
387  break;
388  }
389  }
390  }
391  else {
392  /* Have to assume that it is a response even if code is 0.00 */
393  coap_lg_xmit_t *q;
394  coap_string_t empty = { 0, NULL};
395 
396  assert(resource);
397  option = COAP_OPTION_BLOCK2;
398 
399  /* Check if resource+query is already in use for large bodies (unlikely) */
400  LL_FOREACH_SAFE(session->lg_xmit, lg_xmit, q) {
401  if (resource == lg_xmit->b.b2.resource &&
402  coap_string_equal(query ? query : &empty,
403  lg_xmit->b.b2.query ? lg_xmit->b.b2.query : &empty)) {
404  /* Unfortunately need to free this off as potential size change */
405  LL_DELETE(session->lg_xmit, lg_xmit);
406  coap_block_delete_lg_xmit(session, lg_xmit);
407  lg_xmit = NULL;
408  break;
409  }
410  }
411  }
412 
413  avail = pdu->max_size - pdu->used_size - pdu->hdr_size;
414  /* May need token of length 8, so account for this */
415  avail -= (pdu->token_length <= 8) ? pdu->token_length <= 8 : 0;
416  blk_size = coap_flsll((long long)avail) - 4 - 1;
417 
418  /* see if BLOCKx defined - if so update blk_size as given by app */
419  if (coap_get_block(pdu, option, &block)) {
420  if (block.szx < blk_size)
421  blk_size = block.szx;
422  have_block_defined = 1;
423  }
424 
425  if (avail < 16 && ((ssize_t)length > avail || have_block_defined)) {
426  /* bad luck, this is the smallest block size */
428  "not enough space, even the smallest block does not fit\n");
429  goto fail;
430  }
431 
432  chunk = (size_t)1 << (blk_size + 4);
433  if (have_block_defined && block.num != 0) {
434  /* App is defining a single block to send */
435  size_t rem;
436 
437  pdu->body_data = data;
438  pdu->body_length = length;
439  coap_log(LOG_DEBUG, "PDU presented by app\n");
440  coap_show_pdu(LOG_DEBUG, pdu);
441  pdu->body_data = NULL;
442  pdu->body_length = 0;
443  if (length >= block.num * chunk) {
444  rem = chunk;
445  if (chunk > length - block.num * chunk)
446  rem = length - block.num * chunk;
447  if (!coap_add_data(pdu, rem, &data[block.num * chunk]))
448  goto fail;
449  }
450  if (release_func)
451  release_func(session, app_ptr);
452  }
453  else if ((have_block_defined && length > chunk) || (ssize_t)length > avail) {
454  /* Only add in lg_xmit if more than one block needs to be handled */
455  uint64_t token;
456  size_t rem;
457 
458  lg_xmit = coap_malloc_type(COAP_LG_XMIT, sizeof(coap_lg_xmit_t));
459  if (!lg_xmit)
460  goto fail;
461 
462  coap_log(LOG_DEBUG, "** %s: lg_xmit %p initialized\n",
463  coap_session_str(session), (void*)lg_xmit);
464  /* Set up for displaying all the data in the pdu */
465  pdu->body_data = data;
466  pdu->body_length = length;
467  coap_log(LOG_DEBUG, "PDU presented by app\n");
468  coap_show_pdu(LOG_DEBUG, pdu);
469  pdu->body_data = NULL;
470  pdu->body_length = 0;
471  /* Update lg_xmit with large data information */
472  lg_xmit->blk_size = blk_size;
473  lg_xmit->option = option;
474  lg_xmit->data = data;
475  lg_xmit->length = length;
476  lg_xmit->offset = 0;
477  lg_xmit->release_func = release_func;
478  lg_xmit->last_payload = 0;
479  lg_xmit->last_used = 0;
480  lg_xmit->app_ptr = app_ptr;
481  if (COAP_PDU_IS_REQUEST(pdu)) {
482  /* Need to keep original token for updating response PDUs */
483  lg_xmit->b.b1.app_token = coap_new_binary(pdu->token_length);
484  if (!lg_xmit->b.b1.app_token)
485  goto fail;
486  memcpy(lg_xmit->b.b1.app_token->s, pdu->token, pdu->token_length);
487  /*
488  * Need to set up new token for use during transmits
489  */
490  lg_xmit->b.b1.count = 1;
491  token = ((++session->tx_token) & 0xffffffff) +
492  ((uint64_t)lg_xmit->b.b1.count << 32);
493  memset(lg_xmit->b.b1.token, 0, sizeof(lg_xmit->b.b1.token));
494  lg_xmit->b.b1.token_length = coap_encode_var_safe8(lg_xmit->b.b1.token,
495  sizeof(token), token);
496  /*
497  * Token will be updated in pdu later as original pdu may be needed in
498  * coap_send_large()
499  */
500  coap_update_option(pdu,
502  coap_encode_var_safe(buf, sizeof(buf),
503  (unsigned int)length),
504  buf);
505  }
506  else {
507  /*
508  * resource+query match is used for BLOCK2 large body transmissions
509  * token match is used for BLOCK1 large body transmissions
510  */
511  lg_xmit->b.b2.resource = resource;
512  if (query) {
513  lg_xmit->b.b2.query = coap_new_string(query->length);
514  if (lg_xmit->b.b2.query) {
515  memcpy(lg_xmit->b.b2.query->s, query->s, query->length);
516  }
517  }
518  else {
519  lg_xmit->b.b2.query = NULL;
520  }
521  lg_xmit->b.b2.etag = etag;
522  if (maxage >= 0) {
523  coap_tick_t now;
524 
525  coap_ticks(&now);
526  lg_xmit->b.b2.maxage_expire = coap_ticks_to_rt(now) + maxage;
527  }
528  else {
529  lg_xmit->b.b2.maxage_expire = 0;
530  }
531  coap_update_option(pdu,
533  coap_encode_var_safe(buf, sizeof(buf),
534  (unsigned int)length),
535  buf);
536  if (etag == 0) {
537  if (++session->context->etag == 0)
538  ++session->context->etag;
539  etag = session->context->etag;
540  }
541  coap_update_option(pdu,
543  coap_encode_var_safe8(buf, sizeof(buf), etag),
544  buf);
545  }
546 
547  /* Add in with requested block num, more bit and block size */
548  block.m = ((block.num + 1) * chunk) < lg_xmit->length;
549  coap_update_option(pdu,
550  lg_xmit->option,
551  coap_encode_var_safe(buf, sizeof(buf),
552  (block.num << 4) | (block.m << 3) | lg_xmit->blk_size),
553  buf);
554 
555  /* Set up skeletal PDU to use as a basis for all the subsequent blocks */
556  memcpy(&lg_xmit->pdu, pdu, sizeof(lg_xmit->pdu));
557  lg_xmit->pdu.token = coap_malloc_type(COAP_PDU_BUF,
558  8 + lg_xmit->pdu.used_size + lg_xmit->pdu.hdr_size);
559  if (!lg_xmit->pdu.token)
560  goto fail;
561 
562  lg_xmit->pdu.alloc_size = 8 + lg_xmit->pdu.used_size +
563  lg_xmit->pdu.hdr_size;
564  lg_xmit->pdu.token += lg_xmit->pdu.hdr_size;
565  memcpy(lg_xmit->pdu.token, pdu->token, lg_xmit->pdu.used_size);
566  if (pdu->data)
567  lg_xmit->pdu.data = lg_xmit->pdu.token + (pdu->data - pdu->token);
568 
569  /* Check we still have space after adding in some options */
570  avail = pdu->max_size - pdu->used_size - pdu->hdr_size;
571  /* May need token of length 8, so account for this */
572  avail -= (pdu->token_length <= 8) ? pdu->token_length <= 8 : 0;
573  if (avail < (ssize_t)chunk) {
574  /* chunk size change down */
575  if (avail < 16) {
577  "not enough space, even the smallest block does not fit\n");
578  goto fail;
579  }
580  blk_size = coap_flsll((long long)avail) - 4 - 1;
581  block.num = block.num << (lg_xmit->blk_size - blk_size);
582  lg_xmit->blk_size = blk_size;
583  chunk = (size_t)1 << (lg_xmit->blk_size + 4);
584  coap_update_option(pdu,
585  lg_xmit->option,
586  coap_encode_var_safe(buf, sizeof(buf),
587  (block.num << 4) | (block.m << 3) | lg_xmit->blk_size),
588  buf);
589  }
590 
591  rem = chunk;
592  if (chunk > lg_xmit->length - block.num * chunk)
593  rem = lg_xmit->length - block.num * chunk;
594  if (!coap_add_data(pdu, rem, &data[block.num * chunk]))
595  goto fail;
596 
597  lg_xmit->last_block = -1;
598 
599  /* Link the new lg_xmit in */
600  LL_PREPEND(session->lg_xmit,lg_xmit);
601  }
602  else {
603  /* No need to use blocks */
604  if (have_block_defined) {
605  coap_update_option(pdu,
606  option,
607  coap_encode_var_safe(buf, sizeof(buf),
608  (0 << 4) | (0 << 3) | blk_size), buf);
609  }
610 add_data:
611  if (!coap_add_data(pdu, length, data))
612  goto fail;
613 
614  if (release_func)
615  release_func(session, app_ptr);
616  }
617  return 1;
618 
619 fail:
620  if (lg_xmit) {
621  coap_block_delete_lg_xmit(session, lg_xmit);
622  }
623  if (release_func)
624  release_func(session, app_ptr);
625  return 0;
626 }
627 
628 int
630  coap_pdu_t *pdu,
631  size_t length,
632  const uint8_t *data,
633  coap_release_large_data_t release_func,
634  void *app_ptr) {
635  return coap_add_data_large_internal(session, pdu, NULL, NULL, -1,
636  0, length, data, release_func, app_ptr);
637 }
638 
639 int
641  coap_session_t *session,
642  coap_pdu_t *request,
643  coap_pdu_t *response,
644  const coap_binary_t *token,
645  const coap_string_t *query,
646  uint16_t media_type,
647  int maxage,
648  uint64_t etag,
649  size_t length,
650  const uint8_t *data,
651  coap_release_large_data_t release_func,
652  void *app_ptr
653 ) {
654  unsigned char buf[4];
655  coap_block_t block = { 0, 0, 0 };
656  int block_requested = 0;
657  coap_subscription_t *subscription = coap_find_observer(resource, session,
658  token);
659  uint16_t block_opt = COAP_OPTION_BLOCK2;
660 
661  /*
662  * Need to check that a valid block is getting asked for so that the
663  * correct options are put into the PDU.
664  */
665  if (request) {
666  if (coap_get_block(request, COAP_OPTION_BLOCK2, &block)) {
667  block_requested = 1;
668  if (block.num != 0 && length <= (block.num << (block.szx + 4))) {
669  coap_log(LOG_DEBUG, "Illegal block requested (%d > last = %zu)\n",
670  block.num,
671  length >> (block.szx + 4));
672  response->code = COAP_RESPONSE_CODE(400);
673  goto error;
674  }
675  }
676  }
677  else if (subscription && subscription->has_block2) {
678  block = subscription->block;
679  block.num = 0;
680  block_requested = 1;
681  block_opt = COAP_OPTION_BLOCK2;
682  }
683 
684  if ((block.num == 0) && subscription) {
686  coap_encode_var_safe(buf, sizeof (buf),
687  resource->observe),
688  buf);
689  }
690 
692  coap_encode_var_safe(buf, sizeof(buf),
693  media_type),
694  buf);
695 
696  if (maxage >= 0) {
697  coap_add_option(response,
699  coap_encode_var_safe(buf, sizeof(buf), maxage), buf);
700  }
701 
702  if (block_requested) {
703  int res;
704 
705  res = coap_write_block_opt(&block, block_opt, response,
706  length);
707 
708  switch (res) {
709  case -2: /* illegal block (caught above) */
710  response->code = COAP_RESPONSE_CODE(400);
711  goto error;
712  case -1: /* should really not happen */
713  assert(0);
714  /* fall through if assert is a no-op */
715  case -3: /* cannot handle request */
716  response->code = COAP_RESPONSE_CODE(500);
717  goto error;
718  default: /* everything is good */
719  ;
720  }
721 
722  if (!coap_add_data_large_internal(session, response, resource, query,
723  maxage, etag, length, data,
724  release_func, app_ptr)) {
725  response->code = COAP_RESPONSE_CODE(500);
726  goto error;
727  }
728 
729  return 1;
730  }
731 
732  /*
733  * BLOCK2 not requested
734  */
735  if (!coap_add_data_large_internal(session, response, resource, query, maxage,
736  etag, length, data, release_func,
737  app_ptr)) {
738  response->code = COAP_RESPONSE_CODE(400);
739  goto error;
740  }
741 
742  return 1;
743 
744 error:
745  coap_add_data(response,
746  strlen(coap_response_phrase(response->code)),
747  (const unsigned char *)coap_response_phrase(response->code));
748  return 0;
749 }
750 
753  coap_lg_crcv_t *p;
754  coap_lg_crcv_t *q;
755  coap_tick_t partial_timeout = COAP_EXCHANGE_LIFETIME(session);
756  coap_tick_t tim_rem = -1;
757 
758  LL_FOREACH_SAFE(session->lg_crcv, p, q) {
759  if (!p->observe_set && p->last_used &&
760  p->last_used + partial_timeout <= now) {
761  /* Expire this entry */
762  LL_DELETE(session->lg_crcv, p);
763  coap_block_delete_lg_crcv(session, p);
764  }
765  else if (!p->observe_set && p->last_used) {
766  /* Delay until the lg_crcv needs to expire */
767  if (tim_rem > p->last_used + partial_timeout - now)
768  tim_rem = p->last_used + partial_timeout - now;
769  }
770  }
771  return tim_rem;
772 }
773 
774 static int
775 check_if_received_block(coap_rblock_t *rec_blocks, uint32_t block_num) {
776  uint32_t i;
777 
778  for (i = 0; i < rec_blocks->used; i++) {
779  if (block_num < rec_blocks->range[i].begin)
780  return 0;
781  if (block_num <= rec_blocks->range[i].end)
782  return 1;
783  }
784  return 0;
785 }
786 
787 static int
788 check_all_blocks_in(coap_rblock_t *rec_blocks, size_t total_blocks) {
789  uint32_t i;
790  uint32_t block = 0;
791 
792  for (i = 0; i < rec_blocks->used; i++) {
793  if (block < rec_blocks->range[i].begin)
794  return 0;
795  if (block < rec_blocks->range[i].end)
796  block = rec_blocks->range[i].end;
797  }
798  /* total_blocks counts from 1 */
799  if (block + 1 < total_blocks)
800  return 0;
801 
802  return 1;
803 }
804 
807  coap_lg_srcv_t *p;
808  coap_lg_srcv_t *q;
809  coap_tick_t partial_timeout = COAP_EXCHANGE_LIFETIME(session);
810  coap_tick_t tim_rem = -1;
811 
812  LL_FOREACH_SAFE(session->lg_srcv, p, q) {
813  if (p->last_used && p->last_used + partial_timeout <= now) {
814  /* Expire this entry */
815  LL_DELETE(session->lg_srcv, p);
816  coap_block_delete_lg_srcv(session, p);
817  }
818  else if (p->last_used) {
819  /* Delay until the lg_srcv needs to expire */
820  if (tim_rem > p->last_used + partial_timeout - now)
821  tim_rem = p->last_used + partial_timeout - now;
822  }
823  }
824  return tim_rem;
825 }
826 
829  coap_lg_crcv_t *lg_crcv;
830 
831  lg_crcv = coap_malloc_type(COAP_LG_CRCV, sizeof(coap_lg_crcv_t));
832 
833  if (lg_crcv == NULL)
834  return NULL;
835 
836  coap_log(LOG_DEBUG, "** %s: lg_crcv %p initialized\n",
837  coap_session_str(session), (void*)lg_crcv);
838  memset(lg_crcv, 0, sizeof(coap_lg_crcv_t));
839  lg_crcv->initial = 1;
840  /* Set up skeletal PDU to use as a basis for all the subsequent blocks */
841  memcpy(&lg_crcv->pdu, pdu, sizeof(lg_crcv->pdu));
843  lg_crcv->pdu.alloc_size + lg_crcv->pdu.hdr_size);
844  if (!lg_crcv->pdu.token) {
845  coap_block_delete_lg_crcv(session, lg_crcv);
846  return NULL;
847  }
848  lg_crcv->pdu.token += lg_crcv->pdu.hdr_size;
849  memcpy(lg_crcv->pdu.token, pdu->token, lg_crcv->pdu.used_size);
850  if (lg_crcv->pdu.data)
851  lg_crcv->pdu.data = lg_crcv->pdu.token + (pdu->data - pdu->token);
852  /* Check that there is space for increased token + option change */
853  if (lg_crcv->pdu.max_size < lg_crcv->pdu.used_size + 9)
854  lg_crcv->pdu.max_size = lg_crcv->pdu.used_size + 9;
855 
856  assert(pdu->token_length <= 8);
857  lg_crcv->token_length = min(pdu->token_length, 8);
858  memset(lg_crcv->token, 0, sizeof(lg_crcv->token));
859  memcpy(lg_crcv->token, pdu->token, lg_crcv->token_length);
860 
861  /* Need to keep original token for handling observe responses */
862  memset(lg_crcv->base_token, 0, sizeof(lg_crcv->base_token));
863  memcpy(lg_crcv->base_token, pdu->token, lg_crcv->token_length);
864  lg_crcv->base_token_length = lg_crcv->token_length;
865 
866  /* Need to keep original token for updating response PDUs */
867  lg_crcv->app_token = coap_new_binary(lg_crcv->token_length);
868  if (!lg_crcv->app_token) {
869  coap_block_delete_lg_crcv(session, lg_crcv);
870  return NULL;
871  }
872  memcpy(lg_crcv->app_token->s, pdu->token, lg_crcv->token_length);
873  /* In case it is there - must not be in continuing request PDUs */
875 
876  return lg_crcv;
877 }
878 
879 void
881  coap_lg_crcv_t *lg_crcv) {
882  if (lg_crcv == NULL)
883  return;
884 
885  if (lg_crcv->pdu.token)
886  coap_free_type(COAP_PDU_BUF, lg_crcv->pdu.token - lg_crcv->pdu.hdr_size);
888  coap_log(LOG_DEBUG, "** %s: lg_crcv %p released\n",
889  coap_session_str(session), (void*)lg_crcv);
890  coap_delete_binary(lg_crcv->app_token);
891  coap_free_type(COAP_LG_CRCV, lg_crcv);
892 }
893 
894 void
896  coap_lg_srcv_t *lg_srcv) {
897  if (lg_srcv == NULL)
898  return;
899 
902  coap_log(LOG_DEBUG, "** %s: lg_srcv %p released\n",
903  coap_session_str(session), (void*)lg_srcv);
904  coap_free_type(COAP_LG_SRCV, lg_srcv);
905 }
906 
907 void
909  coap_lg_xmit_t *lg_xmit) {
910  if (lg_xmit == NULL)
911  return;
912 
913  if (lg_xmit->release_func) {
914  lg_xmit->release_func(session, lg_xmit->app_ptr);
915  }
916  if (lg_xmit->pdu.token) {
917  coap_free_type(COAP_PDU_BUF, lg_xmit->pdu.token - lg_xmit->pdu.hdr_size);
918  }
919  if (COAP_PDU_IS_REQUEST(&lg_xmit->pdu))
920  coap_delete_binary(lg_xmit->b.b1.app_token);
921  else
922  coap_delete_string(lg_xmit->b.b2.query);
923 
924  coap_log(LOG_DEBUG, "** %s: lg_xmit %p released\n",
925  coap_session_str(session), (void*)lg_xmit);
926  coap_free_type(COAP_LG_XMIT, lg_xmit);
927 }
928 
929 static int
930 add_block_send(uint32_t num, uint32_t *out_blocks,
931  uint32_t *count, uint32_t max_count) {
932  uint32_t i;
933 
934  for (i = 0; i < *count && *count < max_count; i++) {
935  if (num == out_blocks[i])
936  return 0;
937  else if (num < out_blocks[i]) {
938  if (*count - i > 1)
939  memmove(&out_blocks[i], &out_blocks[i+1], *count - i -1);
940  out_blocks[i] = num;
941  (*count)++;
942  return 1;
943  }
944  }
945  if (*count < max_count) {
946  out_blocks[i] = num;
947  (*count)++;
948  return 1;
949  }
950  return 0;
951 }
952 
953 /*
954  * Need to see if this is a request for the next block of a large body
955  * transfer. If so, need to initiate the response with the next blocks
956  * and not trouble the application.
957  *
958  * If additional responses needed, then these are expicitly sent out and
959  * 'response' is updated to be the last response to be sent.
960  *
961  * This is set up using coap_add_data_response_large()
962  *
963  * Server is sending a large data response to GET / observe (BLOCK2)
964  *
965  * Return: 0 Call application handler
966  * 1 Do not call application handler - just send the built response
967  */
968 int
970  coap_pdu_t *pdu,
971  coap_pdu_t *response,
972  coap_resource_t *resource,
973  coap_string_t *query) {
974  coap_lg_xmit_t *p;
975  coap_block_t block;
976  uint16_t block_opt = 0;
977  uint32_t out_blocks[1];
978  const char *error_phrase;
979 
980  if (coap_get_block(pdu, COAP_OPTION_BLOCK2, &block)) {
981  block_opt = COAP_OPTION_BLOCK2;
982  }
983  LL_FOREACH(session->lg_xmit, p) {
984  size_t chunk;
985  coap_opt_iterator_t opt_iter;
986  coap_opt_iterator_t opt_b_iter;
987  coap_opt_t *option;
988  uint32_t request_cnt, i;
989  coap_opt_t *etag_opt = NULL;
990  coap_pdu_t *out_pdu = response;
991  static coap_string_t empty = { 0, NULL};
992 
993  if (COAP_PDU_IS_REQUEST(&p->pdu) || resource != p->b.b2.resource ||
994  !coap_string_equal(query ? query : &empty,
995  p->b.b2.query ? p->b.b2.query : &empty)) {
996  /* try out the next one */
997  continue;
998  }
999  etag_opt = coap_check_option(pdu, COAP_OPTION_ETAG, &opt_iter);
1000  if (etag_opt) {
1001  uint64_t etag = coap_decode_var_bytes8(coap_opt_value(etag_opt),
1002  coap_opt_length(etag_opt));
1003  if (etag != p->b.b2.etag) {
1004  /* try out the next one */
1005  continue;
1006  }
1007  out_pdu->code = COAP_RESPONSE_CODE(203);
1008  return 1;
1009  }
1010  else {
1011  out_pdu->code = p->pdu.code;
1012  }
1013 
1014  /* lg_xmit (response) found */
1015 
1016  chunk = (size_t)1 << (p->blk_size + 4);
1017  if (block_opt) {
1019  "found Block option, block size is %zu, block nr. %u, M %d\n",
1020  (size_t)1 << (block.szx + 4), block.num, block.m);
1021  if (block.szx != p->blk_size) {
1022  if ((p->offset + chunk) % ((size_t)1 << (block.szx + 4)) == 0) {
1023  /*
1024  * Recompute the block number of the previous packet given
1025  * the new block size
1026  */
1027  block.num = (uint32_t)(((p->offset + chunk) >> (block.szx + 4)) - 1);
1028  p->blk_size = block.szx;
1029  chunk = (size_t)1 << (p->blk_size + 4);
1030  p->offset = block.num * chunk;
1032  "new Block size is %u, block number %u completed\n",
1033  1 << (block.szx + 4), block.num);
1034  } else {
1036  "ignoring request to increase Block size, "
1037  "next block is not aligned on requested block size "
1038  "boundary. (%zu x %u mod %u = %zu (which is not 0)\n",
1039  p->offset/chunk + 1, (1 << (p->blk_size + 4)),
1040  (1 << (block.szx + 4)),
1041  (p->offset + chunk) % ((size_t)1 << (block.szx + 4)));
1042  }
1043  }
1044  }
1045 
1046  request_cnt = 0;
1047  coap_option_iterator_init(pdu, &opt_b_iter, COAP_OPT_ALL);
1048  while ((option = coap_option_next(&opt_b_iter))) {
1049  unsigned int num;
1050  if (opt_b_iter.type != p->option)
1051  continue;
1052  num = coap_opt_block_num(option);
1053  if (num > 0xFFFFF) /* 20 bits max for num */
1054  continue;
1055  if (block.szx != COAP_OPT_BLOCK_SZX(option)) {
1056  coap_add_data(response,
1057  sizeof("Changing blocksize during request invalid")-1,
1058  (const uint8_t *)"Changing blocksize during request invalid");
1059  response->code = COAP_RESPONSE_CODE(400);
1060  return 1;
1061  }
1062  add_block_send(num, out_blocks, &request_cnt, 1);
1063  break;
1064  }
1065  if (request_cnt == 0) {
1066  /* Block2 not found - give them the first block */
1067  block.szx = p->blk_size;
1068  p->offset = 0;
1069  out_blocks[0] = 0;
1070  request_cnt = 1;
1071  }
1072 
1073  for (i = 0; i < request_cnt; i++) {
1074  uint8_t buf[8];
1075 
1076  block.num = out_blocks[i];
1077  p->offset = block.num * chunk;
1078 
1079  if (i + 1 < request_cnt) {
1080  /* Need to set up a copy of the pdu to send */
1081  coap_opt_filter_t drop_options;
1082 
1083  memset(&drop_options, 0, sizeof(coap_opt_filter_t));
1084  if (block.num != 0)
1086  out_pdu = coap_pdu_duplicate(&p->pdu, session, pdu->token_length,
1087  pdu->token, &drop_options);
1088  if (!out_pdu) {
1089  response->code = COAP_RESPONSE_CODE(500);
1090  goto fail;
1091  }
1092  }
1093  else {
1094  /*
1095  * Copy the options across and then fix the block option
1096  *
1097  * Need to drop Observe option if BLOCK2 and block.num != 0
1098  */
1099  coap_option_iterator_init(&p->pdu, &opt_iter, COAP_OPT_ALL);
1100  while ((option = coap_option_next(&opt_iter))) {
1101  if (opt_iter.type == COAP_OPTION_OBSERVE && block.num != 0)
1102  continue;
1103  if (!coap_add_option(response, opt_iter.type,
1104  coap_opt_length(option),
1105  coap_opt_value(option))) {
1106  goto internal_issue;
1107  }
1108  }
1109  out_pdu = response;
1110  }
1111  if (pdu->type == COAP_MESSAGE_NON)
1112  out_pdu->type = COAP_MESSAGE_NON;
1113  if (!coap_update_option(out_pdu, p->option,
1115  sizeof(buf),
1116  (block.num << 4) |
1117  ((p->offset + chunk < p->length) << 3) |
1118  block.szx),
1119  buf)) {
1120  goto internal_issue;
1121  }
1122  if (p->b.b2.maxage_expire) {
1123  coap_tick_t now;
1124  coap_time_t rem;
1125 
1126  coap_ticks(&now);
1127  rem = coap_ticks_to_rt(now);
1128  if (p->b.b2.maxage_expire > rem) {
1129  rem = p->b.b2.maxage_expire - rem;
1130  }
1131  else {
1132  rem = 0;
1133  /* Entry needs to be expired */
1134  coap_ticks(&p->last_used);
1135  }
1136  if (!coap_update_option(out_pdu, COAP_OPTION_MAXAGE,
1138  sizeof(buf),
1139  rem),
1140  buf)) {
1141  goto internal_issue;
1142  }
1143  }
1144 
1145  if (!etag_opt && !coap_add_block(out_pdu,
1146  p->length,
1147  p->data,
1148  block.num,
1149  block.szx)) {
1150  goto internal_issue;
1151  }
1152  if (i + 1 < request_cnt) {
1153  coap_send(session, out_pdu);
1154  }
1155  }
1156  goto skip_app_handler;
1157 
1158 fail:
1159  /* Keep in cache for 4 * ACK_TIMOUT */
1160  coap_ticks(&p->last_used);
1161  goto skip_app_handler;
1162  } /* end of LL_FOREACH() */
1163  return 0;
1164 
1165 skip_app_handler:
1166  return 1;
1167 
1168 internal_issue:
1169  response->code = COAP_RESPONSE_CODE(500);
1170  error_phrase = coap_response_phrase(response->code);
1171  coap_add_data(response, strlen(error_phrase),
1172  (const uint8_t *)error_phrase);
1173  goto fail;
1174 }
1175 
1176 static int
1177 update_received_blocks(coap_rblock_t *rec_blocks, uint32_t block_num) {
1178  uint32_t i;
1179 
1180  /* Reset as there is activity */
1181  rec_blocks->retry = 0;
1182 
1183  for (i = 0; i < rec_blocks->used; i++) {
1184  if (block_num >= rec_blocks->range[i].begin &&
1185  block_num <= rec_blocks->range[i].end)
1186  break;
1187 
1188  if (block_num < rec_blocks->range[i].begin) {
1189  if (block_num + 1 == rec_blocks->range[i].begin) {
1190  rec_blocks->range[i].begin = block_num;
1191  }
1192  else {
1193  /* Need to insert a new range */
1194  if (rec_blocks->used == COAP_RBLOCK_CNT -1)
1195  /* Too many losses */
1196  return 0;
1197  memmove(&rec_blocks->range[i+1], &rec_blocks->range[i],
1198  (rec_blocks->used - i) * sizeof (rec_blocks->range[0]));
1199  rec_blocks->range[i].begin = rec_blocks->range[i].end = block_num;
1200  rec_blocks->used++;
1201  }
1202  break;
1203  }
1204  if (block_num == rec_blocks->range[i].end + 1) {
1205  rec_blocks->range[i].end = block_num;
1206  if (i + 1 < rec_blocks->used) {
1207  if (rec_blocks->range[i+1].begin == block_num + 1) {
1208  /* Merge the 2 ranges */
1209  rec_blocks->range[i].end = rec_blocks->range[i+1].end;
1210  if (i+2 < rec_blocks->used) {
1211  memmove (&rec_blocks->range[i+1], &rec_blocks->range[i+2],
1212  (rec_blocks->used - (i+2)) * sizeof (rec_blocks->range[0]));
1213  }
1214  rec_blocks->used--;
1215  }
1216  }
1217  break;
1218  }
1219  }
1220  if (i == rec_blocks->used) {
1221  if (rec_blocks->used == COAP_RBLOCK_CNT -1)
1222  /* Too many losses */
1223  return 0;
1224  rec_blocks->range[i].begin = rec_blocks->range[i].end = block_num;
1225  rec_blocks->used++;
1226  }
1227  coap_ticks(&rec_blocks->last_seen);
1228  return 1;
1229 }
1230 
1231 /*
1232  * Need to check if this is a large PUT / POST using multiple blocks
1233  *
1234  * Server receiving PUT/POST etc. of a large amount of data (BLOCK1)
1235  *
1236  * Return: 0 Call application handler
1237  * 1 Do not call application handler - just send the built response
1238  */
1239 int
1241  coap_session_t *session,
1242  coap_pdu_t *pdu,
1243  coap_pdu_t *response,
1244  coap_resource_t *resource,
1245  coap_string_t *uri_path,
1246  coap_opt_t *observe,
1247  coap_binary_t *token,
1248  coap_string_t *query,
1250  int *added_block) {
1251  size_t length = 0;
1252  const uint8_t *data = NULL;
1253  size_t offset = 0;
1254  size_t total = 0;
1255  coap_block_t block;
1256  coap_opt_iterator_t opt_iter;
1257  uint16_t block_option = 0;
1258 
1259  coap_get_data_large(pdu, &length, &data, &offset, &total);
1260  pdu->body_offset = 0;
1261  pdu->body_total = length;
1262 
1263  if (coap_get_block(pdu, COAP_OPTION_BLOCK1, &block)) {
1264  block_option = COAP_OPTION_BLOCK1;
1265  }
1266  if (block_option) {
1267  coap_lg_srcv_t *p;
1268  coap_opt_t *size_opt = coap_check_option(pdu,
1270  &opt_iter);
1271  coap_opt_t *fmt_opt = coap_check_option(pdu,
1273  &opt_iter);
1274  uint16_t fmt = fmt_opt ? coap_decode_var_bytes(coap_opt_value(fmt_opt),
1275  coap_opt_length(fmt_opt)) :
1277 
1278  total = size_opt ? coap_decode_var_bytes(coap_opt_value(size_opt),
1279  coap_opt_length(size_opt)) : 0;
1280  offset = block.num << (block.szx + 4);
1281 
1282  LL_FOREACH(session->lg_srcv, p) {
1283  if (resource == p->resource) {
1284  break;
1285  }
1286  if ((p->resource == context->unknown_resource ||
1287  resource == context->proxy_uri_resource) &&
1288  coap_string_equal(uri_path, p->uri_path))
1289  break;
1290  }
1291  if (!p && block.num != 0) {
1292  /* random access - no need to track */
1293  pdu->body_data = data;
1294  pdu->body_length = length;
1295  pdu->body_offset = offset;
1296  pdu->body_total = length + offset + (block.m ? 1 : 0);
1297  }
1298  /* Do not do this if this is a single block */
1299  else if (!p && !(offset == 0 && block.m == 0)) {
1301  if (p == NULL) {
1302  coap_add_data(response, sizeof("Memory issue")-1,
1303  (const uint8_t *)"Memory issue");
1304  response->code = COAP_RESPONSE_CODE(500);
1305  goto skip_app_handler;
1306  }
1307  coap_log(LOG_DEBUG, "** %s: lg_srcv %p initialized\n",
1308  coap_session_str(session), (void*)p);
1309  memset(p, 0, sizeof(coap_lg_srcv_t));
1310  p->resource = resource;
1311  if (resource == context->unknown_resource ||
1312  resource == context->proxy_uri_resource)
1313  p->uri_path = coap_new_str_const(uri_path->s, uri_path->length);
1314  p->content_format = fmt;
1315  p->total_len = total;
1316  p->amount_so_far = length;
1317  p->szx = block.szx;
1318  p->block_option = block_option;
1319  if (observe) {
1320  p->observe_length = min(coap_opt_length(observe), 3);
1321  memcpy(p->observe, coap_opt_value(observe), p->observe_length);
1322  p->observe_set = 1;
1323  }
1324  p->body_data = NULL;
1325  LL_PREPEND(session->lg_srcv, p);
1326  }
1327  if (p) {
1328  if (fmt != p->content_format) {
1329  coap_add_data(response, sizeof("Content-Format mismatch")-1,
1330  (const uint8_t *)"Content-Format mismatch");
1331  response->code = COAP_RESPONSE_CODE(408);
1332  goto free_lg_recv;
1333  }
1334  p->last_mid = pdu->mid;
1335  p->last_type = pdu->type;
1336  memcpy(p->last_token, pdu->token, pdu->token_length);
1337  p->last_token_length = pdu->token_length;
1338  if (session->block_mode & (COAP_BLOCK_SINGLE_BODY)) {
1339  size_t chunk = (size_t)1 << (block.szx + 4);
1340  if (!check_if_received_block(&p->rec_blocks, block.num)) {
1341  /* Update list of blocks received */
1342  if (!update_received_blocks(&p->rec_blocks, block.num)) {
1343  coap_handle_event(context, COAP_EVENT_PARTIAL_BLOCK, session);
1344  coap_add_data(response, sizeof("Too many missing blocks")-1,
1345  (const uint8_t *)"Too many missing blocks");
1346  response->code = COAP_RESPONSE_CODE(408);
1347  goto free_lg_recv;
1348  }
1349  /* Update saved data */
1350  p->body_data = coap_block_build_body(p->body_data, length, data,
1351  offset, p->total_len);
1352  if (!p->body_data)
1353  goto call_app_handler;
1354 
1355  }
1357  (uint32_t)(p->total_len + chunk -1)/chunk)) {
1358  /* Not all the payloads of the body have arrived */
1359  if (block.m) {
1360  uint8_t buf[4];
1361 
1362  /* Ask for the next block */
1363  coap_insert_option(response, block_option,
1364  coap_encode_var_safe(buf, sizeof(buf),
1365  (block.num << 4) |
1366  (block.m << 3) |
1367  block.szx),
1368  buf);
1369  response->code = COAP_RESPONSE_CODE(231);
1370  goto skip_app_handler;
1371  }
1372  goto skip_app_handler;
1373  }
1374 
1375  /*
1376  * Remove the BLOCK1 option as passing all of the data to
1377  * application layer. Add back in observe option if appropriate.
1378  * Adjust all other information.
1379  */
1380  if (p->observe_set) {
1382  p->observe_length, p->observe);
1383  }
1384  coap_remove_option(pdu, block_option);
1385  pdu->body_data = p->body_data->s;
1386  pdu->body_length = p->total_len;
1387  pdu->body_offset = 0;
1388  pdu->body_total = p->total_len;
1389  coap_log(LOG_DEBUG, "Server app vesion of updated PDU\n");
1390  coap_show_pdu(LOG_DEBUG, pdu);
1391  /* Need to do this here as we need to free off p */
1392  h(context, resource, session, pdu, token, query, response);
1393  /* Check if lg_xmit generated and update PDU code if so */
1394  coap_check_code_lg_xmit(session, response, resource, query);
1395  /* Last chunk - free off shortly */
1396  coap_ticks(&p->last_used);
1397  goto skip_app_handler;
1398  }
1399  else {
1400  /* No need to update body_data and body_length as a single PDU */
1401  pdu->body_offset = offset;
1402  /* Exact match if last block */
1403  if (block.m) {
1404  uint8_t buf[4];
1405 
1406  if (total > offset + length + block.m)
1407  pdu->body_total = total;
1408  else
1409  pdu->body_total = offset + length + block.m;
1410 
1411  coap_insert_option(response, block_option,
1412  coap_encode_var_safe(buf, sizeof(buf),
1413  (block.num << 4) |
1414  (block.m << 3) |
1415  block.szx),
1416  buf);
1417  h(context, resource, session, pdu, token, query, response);
1418  /* Check if lg_xmit generated and update PDU code if so */
1419  coap_check_code_lg_xmit(session, response, resource, query);
1420  if (COAP_RESPONSE_CLASS(response->code) == 2) {
1421  /* Just in case, as there are more to go */
1422  response->code = COAP_RESPONSE_CODE(231);
1423  }
1424  *added_block = 1;
1425  goto skip_app_handler;
1426  }
1427  else {
1428  pdu->body_total = offset + length + block.m;
1429  }
1430  }
1431 
1432  if (block.m == 0) {
1433  /* Last chunk - free off all */
1434  coap_ticks(&p->last_used);
1435  }
1436  goto call_app_handler;
1437 
1438 free_lg_recv:
1439  LL_DELETE(session->lg_srcv, p);
1440  coap_block_delete_lg_srcv(session, p);
1441  goto skip_app_handler;
1442  }
1443  }
1444 call_app_handler:
1445  return 0;
1446 
1447 skip_app_handler:
1448  return 1;
1449 }
1450 
1451 /*
1452  * Need to see if this is a response to a large body request transfer. If so,
1453  * need to initiate the request containing the next block and not trouble the
1454  * application. Note that Token must unique per request/response.
1455  *
1456  * Client receives large data acknowledgement from server (BLOCK1)
1457  *
1458  * This is set up using coap_add_data_request_large()
1459  *
1460  * Client is sending a large data request using GET etc.
1461  *
1462  * Return: 0 Call application handler
1463  * 1 Do not call application handler - just send the built response
1464  */
1465 int
1467  coap_lg_xmit_t *p;
1468  coap_lg_xmit_t *q;
1469 
1470  LL_FOREACH_SAFE(session->lg_xmit, p, q) {
1471  if (COAP_PDU_IS_REQUEST(&p->pdu) &&
1472  !block_token_match(rcvd->token, rcvd->token_length,
1473  p->b.b1.token, p->b.b1.token_length)) {
1474  }
1475  /* lg_xmit found */
1476  size_t chunk = (size_t)1 << (p->blk_size + 4);
1477  coap_block_t block;
1478 
1479  if (COAP_RESPONSE_CLASS(rcvd->code) == 2 &&
1480  coap_get_block(rcvd, p->option, &block)) {
1482  "found Block option, block size is %u, block nr. %u\n",
1483  1 << (block.szx + 4), block.num);
1484  if (block.szx != p->blk_size) {
1485  if ((p->offset + chunk) % ((size_t)1 << (block.szx + 4)) == 0) {
1486  /*
1487  * Recompute the block number of the previous packet given the
1488  * new block size
1489  */
1490  block.num = (uint32_t)(((p->offset + chunk) >> (block.szx + 4)) - 1);
1491  p->blk_size = block.szx;
1492  chunk = (size_t)1 << (p->blk_size + 4);
1493  p->offset = block.num * chunk;
1495  "new Block size is %u, block number %u completed\n",
1496  1 << (block.szx + 4), block.num);
1497  } else {
1498  coap_log(LOG_DEBUG, "ignoring request to increase Block size, "
1499  "next block is not aligned on requested block size boundary. "
1500  "(%zu x %u mod %u = %zu != 0)\n",
1501  p->offset/chunk + 1, (1 << (p->blk_size + 4)),
1502  (1 << (block.szx + 4)),
1503  (p->offset + chunk) % ((size_t)1 << (block.szx + 4)));
1504  }
1505  }
1506  if (p->last_block == (int)block.num) {
1507  /*
1508  * Duplicate BLOCK ACK
1509  *
1510  * RFCs not clear here, but on a lossy connection, there could
1511  * be multiple BLOCK ACKs, causing the client to retransmit the
1512  * same block multiple times, or the server retransmitting the
1513  * same ACK.
1514  *
1515  * Once a block has been ACKd, there is no need to retransmit it.
1516  */
1517  return 1;
1518  }
1519  p->last_block = block.num;
1520  p->offset = (block.num + 1) * chunk;
1521  if (p->offset < p->length) {
1522  /* Build the next PDU request based off the skeletal PDU */
1523  uint8_t buf[8];
1524  coap_pdu_t *pdu;
1525  uint64_t token = coap_decode_var_bytes8(p->pdu.token,
1526  p->pdu.token_length);
1527  uint8_t ltoken[8];
1528  size_t ltoken_length;
1529 
1530  token = (token & 0xffffffff) + ((uint64_t)(++p->b.b1.count) << 32);
1531  ltoken_length = coap_encode_var_safe8(ltoken, sizeof(token), token);
1532  pdu = coap_pdu_duplicate(&p->pdu, session, ltoken_length, ltoken, NULL);
1533  if (!pdu)
1534  goto fail_body;
1535 
1536  block.num++;
1537  coap_update_option(pdu, p->option,
1538  coap_encode_var_safe(buf, sizeof(buf),
1539  (block.num << 4) |
1540  ((p->offset + chunk < p->length) << 3) |
1541  block.szx),
1542  buf);
1543 
1544  if (!coap_add_block(pdu,
1545  p->length,
1546  p->data,
1547  block.num,
1548  block.szx))
1549  goto fail_body;
1550  if (coap_send(session, pdu) == COAP_INVALID_MID)
1551  goto fail_body;
1552  return 1;
1553  }
1554  }
1555 fail_body:
1556  /* need to put back original token into rcvd */
1557  if (p->b.b1.app_token)
1559  p->b.b1.app_token->s);
1560  coap_log(LOG_DEBUG, "PDU given to app\n");
1561  coap_show_pdu(LOG_DEBUG, rcvd);
1562 
1563  LL_DELETE(session->lg_xmit, p);
1564  coap_block_delete_lg_xmit(session, p);
1565  /*
1566  * There may be a block response after doing the large request
1567  * https://tools.ietf.org/html/rfc7959#section-3.3
1568  */
1569  break;
1570  } /* end of LL_FOREACH_SAFE */
1571  return 0;
1572 }
1573 
1574 /*
1575  * Re-assemble payloads into a body
1576  */
1577 coap_binary_t *
1578 coap_block_build_body(coap_binary_t *body_data, size_t length,
1579  const uint8_t *data, size_t offset, size_t total)
1580 {
1581  if (data == NULL)
1582  return NULL;
1583  if (body_data == NULL && total) {
1584  body_data = coap_new_binary(total);
1585  }
1586  if (body_data == NULL)
1587  return NULL;
1588 
1589  /* Update saved data */
1590  if (offset + length <= total && body_data->length >= total) {
1591  memcpy(&body_data->s[offset], data, length);
1592  }
1593  else {
1594  /*
1595  * total may be inaccurate as per
1596  * https://tools.ietf.org/html/rfc7959#section-4
1597  * o In a request carrying a Block1 Option, to indicate the current
1598  * estimate the client has of the total size of the resource
1599  * representation, measured in bytes ("size indication").
1600  * o In a response carrying a Block2 Option, to indicate the current
1601  * estimate the server has of the total size of the resource
1602  * representation, measured in bytes ("size indication").
1603  */
1604  coap_binary_t *new = coap_resize_binary(body_data, offset + length);
1605 
1606  if (new) {
1607  body_data = new;
1608  memcpy(&body_data->s[offset], data, length);
1609  }
1610  else {
1611  coap_delete_binary(body_data);
1612  return NULL;
1613  }
1614  }
1615  return body_data;
1616 }
1617 
1618 /*
1619  * Need to see if this is a large body response to a request. If so,
1620  * need to initiate the request for the next block and not trouble the
1621  * application. Note that Token must unique per request/response.
1622  *
1623  * This is set up using coap_send_large()
1624  * Client receives large data from server (BLOCK2)
1625  *
1626  * Return: 0 Call application handler
1627  * 1 Do not call application handler - just sent the next request
1628  */
1629 int
1631  coap_session_t *session,
1632  coap_pdu_t *sent,
1633  coap_pdu_t *rcvd,
1634  coap_recurse_t recursive) {
1635  coap_lg_crcv_t *p;
1636  int app_has_response = 0;
1637  coap_block_t block = {0, 0, 0};
1638  int have_block = 0;
1639  uint16_t block_opt = 0;
1640  size_t offset;
1641 
1642  LL_FOREACH(session->lg_crcv, p) {
1643  size_t chunk = 0;
1644  uint8_t buf[8];
1645  coap_opt_iterator_t opt_iter;
1646 
1647  if (!full_match(rcvd->token, rcvd->token_length,
1648  p->token, p->token_length)) {
1649  /* try out the next one */
1650  continue;
1651  }
1652 
1653  /* lg_crcv found */
1654 
1655  if (COAP_RESPONSE_CLASS(rcvd->code) == 2) {
1656  size_t length;
1657  uint8_t *data;
1659  &opt_iter);
1660  size_t size2 = size_opt ?
1662  coap_opt_length(size_opt)) : 0;
1663 
1664  coap_get_data(rcvd, &length, &data);
1665  rcvd->body_offset = 0;
1666  rcvd->body_total = length;
1667  if (coap_get_block(rcvd, COAP_OPTION_BLOCK2, &block)) {
1668  have_block = 1;
1669  block_opt = COAP_OPTION_BLOCK2;
1670  }
1671  if (have_block) {
1672  coap_opt_t *fmt_opt = coap_check_option(rcvd,
1674  &opt_iter);
1675  uint16_t fmt = fmt_opt ?
1677  coap_opt_length(fmt_opt)) :
1679  coap_opt_t *etag_opt = coap_check_option(rcvd,
1681  &opt_iter);
1682  /* Possibility that Size2 not sent, or is too small */
1683  chunk = (size_t)1 << (block.szx + 4);
1684  offset = block.num * chunk;
1685  if (size2 < (offset + length)) {
1686  if (block.m)
1687  size2 = offset + length + 1;
1688  else
1689  size2 = offset + length;
1690  }
1691 
1692  if (p->initial) {
1693  p->initial = 0;
1694  if (etag_opt) {
1695  p->etag_length = coap_opt_length(etag_opt);
1696  memcpy(p->etag, coap_opt_value(etag_opt), p->etag_length);
1697  p->etag_set = 1;
1698  }
1699  else {
1700  p->etag_set = 0;
1701  }
1702  p->total_len = size2;
1703  p->content_format = fmt;
1704  p->szx = block.szx;
1705  p->block_option = block_opt;
1706  p->last_type = rcvd->type;
1707  p->rec_blocks.used = 0;
1708  }
1709  if (p->total_len < size2)
1710  p->total_len = size2;
1711 
1712  if (etag_opt) {
1713  if (!full_match(coap_opt_value(etag_opt),
1714  coap_opt_length(etag_opt),
1715  p->etag, p->etag_length)) {
1716  /* body of data has changed - need to restart request */
1717  size_t len;
1718  coap_pdu_t *pdu;
1719 
1721  "Data body updated during receipt - new request started\n");
1722  if (!(session->block_mode & COAP_BLOCK_SINGLE_BODY))
1723  coap_handle_event(context, COAP_EVENT_PARTIAL_BLOCK, session);
1724 
1725  p->initial = 1;
1727  p->body_data = NULL;
1728 
1729  coap_session_new_token(session, &len, buf);
1730  pdu = coap_pdu_duplicate(&p->pdu, session, len, buf, NULL);
1731  if (!pdu)
1732  goto fail_resp;
1733 
1734  memcpy(p->token, pdu->token, pdu->token_length);
1735  p->token_length = pdu->token_length;
1736 
1737  coap_update_option(pdu, block_opt,
1738  coap_encode_var_safe(buf, sizeof(buf),
1739  (0 << 4) | (0 << 3) | block.szx),
1740  buf);
1741 
1742  if (coap_send(session, pdu) == COAP_INVALID_MID)
1743  goto fail_resp;
1744 
1745  goto skip_app_handler;
1746  }
1747  }
1748  else if (p->etag_set) {
1749  /* Cannot handle this change in ETag to not being there */
1750  coap_log(LOG_WARNING, "Not all blocks have ETag option\n");
1751  session->block_mode &= ~(COAP_BLOCK_SINGLE_BODY);
1752  goto block_mode;
1753  }
1754 
1755  if (fmt != p->content_format) {
1756  coap_log(LOG_WARNING, "Content-Format option mismatch\n");
1757  session->block_mode &= ~(COAP_BLOCK_SINGLE_BODY);
1758  goto block_mode;
1759  }
1761  "found Block option, block size is %u, block nr. %u\n",
1762  1 << (block.szx + 4), block.num);
1763  if (block.num == 0) {
1764  coap_opt_t *obs_opt = coap_check_option(rcvd,
1766  &opt_iter);
1767  if (obs_opt) {
1768  p->observe_length = min(coap_opt_length(obs_opt), 3);
1769  memcpy(p->observe, coap_opt_value(obs_opt), p->observe_length);
1770  p->observe_set = 1;
1771  }
1772  else {
1773  p->observe_set = 0;
1774  }
1775  }
1776  if (!check_if_received_block(&p->rec_blocks, block.num)) {
1777  /* Update list of blocks received */
1778  if (!update_received_blocks(&p->rec_blocks, block.num)) {
1779  coap_handle_event(context, COAP_EVENT_PARTIAL_BLOCK, session);
1780  goto fail_resp;
1781  }
1782 
1783  if (session->block_mode & (COAP_BLOCK_SINGLE_BODY)) {
1784  p->body_data = coap_block_build_body(p->body_data, length, data,
1785  offset, size2);
1786  if (p->body_data == NULL) {
1787  /* Need to do it block by block */
1788  session->block_mode &= ~(COAP_BLOCK_SINGLE_BODY);
1789  goto block_mode;
1790  }
1791  }
1793  (size2 + chunk -1) / chunk)) {
1794  /* Not all the payloads of the body have arrived */
1795  size_t len;
1796  coap_pdu_t *pdu;
1797 
1798  if (block.m) {
1799  block.m = 0;
1800 
1801  /* Ask for the next block */
1802  coap_session_new_token(session, &len, buf);
1803  pdu = coap_pdu_duplicate(&p->pdu, session, len, buf, NULL);
1804  if (!pdu)
1805  goto fail_resp;
1806 
1807  memcpy(p->token, pdu->token, pdu->token_length);
1808  p->token_length = pdu->token_length;
1809 
1810  /* Only sent with the first block */
1812 
1813  coap_update_option(pdu, block_opt,
1814  coap_encode_var_safe(buf, sizeof(buf),
1815  ((block.num + 1) << 4) |
1816  (block.m << 3) | block.szx),
1817  buf);
1818 
1819  if (coap_send(session, pdu) == COAP_INVALID_MID)
1820  goto fail_resp;
1821  }
1822  if (session->block_mode & (COAP_BLOCK_SINGLE_BODY))
1823  goto skip_app_handler;
1824 
1825  /* need to put back original token into rcvd */
1826  coap_update_token(rcvd, p->app_token->length, p->app_token->s);
1827  rcvd->body_offset = block.num*chunk;
1828  rcvd->body_total = size2;
1829  goto call_app_handler;
1830  }
1831  /* need to put back original token into rcvd */
1832  coap_update_token(rcvd, p->app_token->length, p->app_token->s);
1833  if (session->block_mode & (COAP_BLOCK_SINGLE_BODY)) {
1834  /* Pretend that there is no block */
1835  coap_remove_option(rcvd, block_opt);
1836  if (p->observe_set) {
1838  p->observe_length, p->observe);
1839  }
1840  rcvd->body_data = p->body_data->s;
1841  rcvd->body_length = block.num*chunk + length;
1842  rcvd->body_offset = 0;
1843  rcvd->body_total = rcvd->body_length;
1844  }
1845  else {
1846  rcvd->body_offset = block.num*chunk;
1847  rcvd->body_total = size2;
1848  }
1849  if (context->response_handler) {
1850  if (session->block_mode &
1852  coap_log(LOG_DEBUG, "Client app vesion of updated PDU\n");
1853  coap_show_pdu(LOG_DEBUG, rcvd);
1854  }
1855  context->response_handler(context, session, sent, rcvd,
1856  rcvd->mid);
1857  }
1858  app_has_response = 1;
1859  /* Set up for the next data body if observing */
1860  p->initial = 1;
1861  memcpy(p->token, p->base_token, p->base_token_length);
1863  if (p->body_data) {
1865  p->body_data = NULL;
1866  }
1867  else {
1868  goto skip_app_handler;
1869  }
1870  }
1871  else {
1872 block_mode:
1873  /* need to put back original token into rcvd */
1874  coap_update_token(rcvd, p->app_token->length, p->app_token->s);
1875  rcvd->body_offset = block.num*chunk;
1876  /* slightly oversize if there is more data */
1877  if (block.m) {
1878  if(size2 > block.num*chunk + length + block.m)
1879  rcvd->body_total = size2;
1880  else
1881  rcvd->body_total = block.num*chunk + length + block.m;
1882  }
1883  else {
1884  rcvd->body_total = block.num*chunk + length;
1885  /* Set up for the next data body if observing */
1886  p->initial = 1;
1887  memcpy(p->token, p->base_token, p->base_token_length);
1889  }
1890  if (context->response_handler) {
1891  coap_log(LOG_DEBUG, "Client app vesion of updated PDU\n");
1892  coap_show_pdu(LOG_DEBUG, rcvd);
1893  context->response_handler(context, session, sent, rcvd,
1894  rcvd->mid);
1895  }
1896  app_has_response = 1;
1897  }
1898  }
1899  else {
1900  coap_opt_t *obs_opt = coap_check_option(rcvd,
1902  &opt_iter);
1903  if (obs_opt) {
1904  p->observe_length = min(coap_opt_length(obs_opt), 3);
1905  memcpy(p->observe, coap_opt_value(obs_opt), p->observe_length);
1906  p->observe_set = 1;
1907  }
1908  else {
1909  p->observe_set = 0;
1910  }
1911  }
1912  }
1913  if (!block.m && !p->observe_set) {
1914 fail_resp:
1915  /* lg_crcv no longer required - cache it */
1916  coap_ticks(&p->last_used);
1917  }
1918  /* need to put back original token into rcvd */
1919  coap_update_token(rcvd, p->app_token->length, p->app_token->s);
1920  break;
1921  } /* LL_FOREACH() */
1922 
1923  /* Check if receiving a block response and if blocks can be set up */
1924  if (recursive == COAP_RECURSE_OK && !p) {
1925  if (!sent) {
1926  if (coap_get_block(rcvd, COAP_OPTION_BLOCK2, &block)) {
1927  coap_log(LOG_DEBUG, "** %s: large body receive not supported by "
1928  "libcoap unless coap_send_large() is used to transmit "
1929  "request\n", coap_session_str(session));
1930  }
1931  }
1932  else if (COAP_RESPONSE_CLASS(rcvd->code) == 2) {
1933  if (coap_get_block(rcvd, COAP_OPTION_BLOCK2, &block)) {
1934  have_block = 1;
1935  block_opt = COAP_OPTION_BLOCK2;
1936  if (block.num != 0) {
1937  /* Assume random access and just give the single response to app */
1938  size_t length;
1939  uint8_t *data;
1940  size_t chunk = (size_t)1 << (block.szx + 4);
1941 
1942  coap_get_data(rcvd, &length, &data);
1943  rcvd->body_offset = block.num*chunk;
1944  rcvd->body_total = block.num*chunk + length + (block.m ? 1 : 0);
1945  return 0;
1946  }
1947  }
1948  if (have_block) {
1949  coap_lg_crcv_t *lg_crcv = coap_block_new_lg_crcv(session, sent);
1950 
1951  if (lg_crcv) {
1952  LL_PREPEND(session->lg_crcv, lg_crcv);
1953  return coap_handle_response_get_block(context, session, sent, rcvd,
1954  COAP_RECURSE_NO);
1955  }
1956  }
1957  }
1958  }
1959  return app_has_response;
1960 
1961 call_app_handler:
1962  return 0;
1963 
1964 skip_app_handler:
1965  return 1;
1966 }
1967 
1968 /* Check if lg_xmit generated and update PDU code if so */
1969 void
1971  coap_resource_t *resource, coap_string_t *query) {
1972  coap_lg_xmit_t *lg_xmit;
1973  coap_string_t empty = { 0, NULL};
1974 
1975  if (response->code == 0)
1976  return;
1977  LL_FOREACH(session->lg_xmit, lg_xmit) {
1978  if (!COAP_PDU_IS_REQUEST(&lg_xmit->pdu) &&
1979  lg_xmit->b.b2.resource == resource &&
1980  coap_string_equal(query ? query : &empty,
1981  lg_xmit->b.b2.query ? lg_xmit->b.b2.query : &empty)) {
1982  /* lg_xmit found */
1983  if (lg_xmit->pdu.code == 0) {
1984  lg_xmit->pdu.code = response->code;
1985  return;
1986  }
1987  }
1988  }
1989 }
static int add_block_send(uint32_t num, uint32_t *out_blocks, uint32_t *count, uint32_t max_count)
Definition: block.c:930
COAP_STATIC_INLINE int full_match(const uint8_t *a, size_t alen, const uint8_t *b, size_t blen)
Definition: block.c:287
#define MAX_BLK_LEN
static int check_all_blocks_in(coap_rblock_t *rec_blocks, size_t total_blocks)
Definition: block.c:788
static int update_received_blocks(coap_rblock_t *rec_blocks, uint32_t block_num)
Definition: block.c:1177
#define min(a, b)
Definition: block.c:12
static int check_if_received_block(coap_rblock_t *rec_blocks, uint32_t block_num)
Definition: block.c:775
COAP_STATIC_INLINE int block_token_match(const uint8_t *a, size_t alen, const uint8_t *b, size_t blen)
Definition: block.c:277
unsigned char coap_key_t[4]
Definition: coap_hashkey.h:22
#define coap_hash(String, Length, Result)
Definition: coap_hashkey.h:36
Pulls together all the internal only header files.
void coap_session_new_token(coap_session_t *session, size_t *len, uint8_t *data)
Creates a new token for use.
int coap_flsll(long long i)
Definition: encode.c:19
int coap_handle_request_put_block(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu, coap_pdu_t *response, coap_resource_t *resource, coap_string_t *uri_path, coap_opt_t *observe, coap_binary_t *token, coap_string_t *query, coap_method_handler_t h, int *added_block)
Definition: block.c:1240
coap_tick_t coap_block_check_lg_srcv_timeouts(coap_session_t *session, coap_tick_t now)
Definition: block.c:806
int coap_add_data_large_internal(coap_session_t *session, coap_pdu_t *pdu, coap_resource_t *resource, const coap_string_t *query, int maxage, uint64_t etag, size_t length, const uint8_t *data, coap_release_large_data_t release_func, void *app_ptr)
The function that does all the work for the coap_add_data_large*() functions.
Definition: block.c:335
void coap_block_delete_lg_srcv(coap_session_t *session, coap_lg_srcv_t *lg_srcv)
Definition: block.c:895
#define COAP_RBLOCK_CNT
void coap_block_delete_lg_crcv(coap_session_t *session, coap_lg_crcv_t *lg_crcv)
Definition: block.c:880
int coap_handle_response_get_block(coap_context_t *context, coap_session_t *session, coap_pdu_t *sent, coap_pdu_t *rcvd, coap_recurse_t recursive)
Definition: block.c:1630
coap_recurse_t
void coap_block_delete_lg_xmit(coap_session_t *session, coap_lg_xmit_t *lg_xmit)
Definition: block.c:908
void coap_check_code_lg_xmit(coap_session_t *session, coap_pdu_t *response, coap_resource_t *resource, coap_string_t *query)
The function checks that the code in a newly formed lg_xmit created by coap_add_data_large_response()...
Definition: block.c:1970
coap_tick_t coap_block_check_lg_crcv_timeouts(coap_session_t *session, coap_tick_t now)
Definition: block.c:752
int coap_handle_request_send_block(coap_session_t *session, coap_pdu_t *pdu, coap_pdu_t *response, coap_resource_t *resource, coap_string_t *query)
Definition: block.c:969
coap_lg_crcv_t * coap_block_new_lg_crcv(coap_session_t *session, coap_pdu_t *pdu)
Definition: block.c:828
int coap_handle_response_send_block(coap_session_t *session, coap_pdu_t *rcvd)
Definition: block.c:1466
@ COAP_RECURSE_OK
@ COAP_RECURSE_NO
int coap_write_block_opt(coap_block_t *block, uint16_t type, coap_pdu_t *pdu, size_t data_length)
Writes a block option of type type to message pdu.
Definition: block.c:63
void coap_context_set_block_mode(coap_context_t *context, uint8_t block_mode)
Set the context level CoAP block handling bits for handling RFC7959.
Definition: block.c:263
#define COAP_OPT_BLOCK_SZX(opt)
Returns the value of the SZX-field of a Block option opt.
Definition: block.h:55
#define COAP_BLOCK_SINGLE_BODY
Definition: block.h:40
int coap_get_block(coap_pdu_t *pdu, uint16_t type, coap_block_t *block)
Initializes block from pdu.
Definition: block.c:35
int coap_add_block(coap_pdu_t *pdu, size_t len, const uint8_t *data, unsigned int block_num, unsigned char block_szx)
Adds the block_num block of size 1 << (block_szx + 4) from source data to pdu.
Definition: block.c:124
coap_binary_t * coap_block_build_body(coap_binary_t *body_data, size_t length, const uint8_t *data, size_t offset, size_t total)
Re-assemble payloads into a body.
Definition: block.c:1578
int coap_add_data_large_response(coap_resource_t *resource, coap_session_t *session, coap_pdu_t *request, coap_pdu_t *response, const coap_binary_t *token, const coap_string_t *query, uint16_t media_type, int maxage, uint64_t etag, size_t length, const uint8_t *data, coap_release_large_data_t release_func, void *app_ptr)
Associates given data with the response pdu that is passed as fourth parameter.
Definition: block.c:640
void coap_add_data_blocked_response(coap_resource_t *resource, coap_session_t *session, coap_pdu_t *request, coap_pdu_t *response, const coap_binary_t *token, uint16_t media_type, int maxage, size_t length, const uint8_t *data)
Adds the appropriate part of data to the response pdu.
Definition: block.c:141
#define COAP_OPT_BLOCK_MORE(opt)
Returns the value of the More-bit of a Block option opt.
Definition: block.h:51
void(* coap_release_large_data_t)(struct coap_session_t *session, void *app_ptr)
Callback handler for de-allocating the data based on app_ptr provided to coap_add_data_large_*() func...
Definition: block.h:200
unsigned int coap_opt_block_num(const coap_opt_t *block_opt)
Returns the value of field num in the given block option block_opt.
Definition: block.c:16
int coap_cancel_observe(coap_session_t *session, coap_binary_t *token, uint8_t type)
Cancel an observe that is being tracked by the client large receive logic when using coap_send_large(...
Definition: block.c:293
#define COAP_OPT_BLOCK_LAST(opt)
Returns the value of the least significant byte of a Block option opt.
Definition: block.h:47
int coap_add_data_large_request(coap_session_t *session, coap_pdu_t *pdu, size_t length, const uint8_t *data, coap_release_large_data_t release_func, void *app_ptr)
Associates given data with the pdu that is passed as second parameter.
Definition: block.c:629
#define COAP_BLOCK_USE_LIBCOAP
Definition: block.h:39
#define COAP_EXCHANGE_LIFETIME(s)
The EXCHANGE_LIFETIME definition for the session (s).
Definition: coap_session.h:562
void coap_ticks(coap_tick_t *t)
Sets t to the internal time with COAP_TICKS_PER_SECOND resolution.
time_t coap_time_t
CoAP time in seconds since epoch.
Definition: coap_time.h:125
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:120
coap_time_t coap_ticks_to_rt(coap_tick_t t)
Helper function that converts coap ticks to wallclock time.
void(* coap_method_handler_t)(coap_context_t *, coap_resource_t *, coap_session_t *, coap_pdu_t *, coap_binary_t *, coap_string_t *, coap_pdu_t *)
Definition of message handler function.
Definition: resource.h:41
unsigned int coap_encode_var_safe(uint8_t *buf, size_t length, unsigned int val)
Encodes multiple-length byte sequences.
Definition: encode.c:38
unsigned int coap_decode_var_bytes(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition: encode.c:29
uint64_t coap_decode_var_bytes8(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition: encode.c:58
unsigned int coap_encode_var_safe8(uint8_t *buf, size_t length, uint64_t val)
Encodes multiple-length byte sequences.
Definition: encode.c:68
#define COAP_EVENT_PARTIAL_BLOCK
BLOCK2 receive errors.
Definition: coap_event.h:52
void coap_show_pdu(coap_log_t level, const coap_pdu_t *pdu)
Display the contents of the specified pdu.
Definition: coap_debug.c:505
const char * coap_session_str(const coap_session_t *session)
Get session description.
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:150
@ LOG_WARNING
Warning.
Definition: coap_debug.h:54
@ LOG_DEBUG
Debug.
Definition: coap_debug.h:57
#define COAP_OBSERVE_CANCEL
The value COAP_OBSERVE_CANCEL in a GET/FETCH request option COAP_OPTION_OBSERVE indicates that the ob...
Definition: subscribe.h:37
int coap_option_filter_set(coap_opt_filter_t *filter, uint16_t type)
Sets the corresponding entry for type in filter.
Definition: option.c:486
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
Definition: option.c:146
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: option.c:209
#define COAP_OPT_ALL
Pre-defined filter that includes all options.
Definition: option.h:105
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: option.c:246
coap_opt_t * coap_check_option(coap_pdu_t *pdu, uint16_t type, coap_opt_iterator_t *oi)
Retrieves the first option of type type from pdu.
Definition: option.c:196
coap_opt_iterator_t * coap_option_iterator_init(const coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t *filter)
Initializes the given option iterator oi to point to the beginning of the pdu's option list.
Definition: option.c:110
coap_string_t * coap_new_string(size_t size)
Returns a new string object with at least size+1 bytes storage allocated.
Definition: str.c:13
void coap_delete_str_const(coap_str_const_t *s)
Deletes the given const string and releases any memory allocated.
Definition: str.c:51
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
Definition: str.c:89
#define coap_string_equal(string1, string2)
Compares the two strings for equality.
Definition: str.h:181
coap_binary_t * coap_new_binary(size_t size)
Returns a new binary object with at least size bytes storage allocated.
Definition: str.c:65
coap_str_const_t * coap_new_str_const(const uint8_t *data, size_t size)
Returns a new const string object with at least size+1 bytes storage allocated, and the provided data...
Definition: str.c:42
void coap_delete_string(coap_string_t *s)
Deletes the given string and releases any memory allocated.
Definition: str.c:38
coap_binary_t * coap_resize_binary(coap_binary_t *s, size_t size)
Resizes the given coap_binary_t object.
Definition: str.c:69
coap_subscription_t * coap_find_observer(coap_resource_t *resource, coap_session_t *session, const coap_binary_t *token)
Returns a subscription object for given peer.
Definition: resource.c:684
#define COAP_STATIC_INLINE
Definition: libcoap.h:38
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
@ COAP_LG_XMIT
Definition: mem.h:48
@ COAP_LG_CRCV
Definition: mem.h:49
@ COAP_LG_SRCV
Definition: mem.h:50
@ COAP_STRING
Definition: mem.h:30
@ COAP_PDU_BUF
Definition: mem.h:38
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
int coap_handle_event(coap_context_t *context, coap_event_t event, coap_session_t *session)
Invokes the event handler of context for the given event and data.
Definition: net.c:3069
coap_mid_t coap_send(coap_session_t *session, coap_pdu_t *pdu)
Sends a CoAP message to given peer.
Definition: net.c:1109
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: option.h:24
int coap_update_token(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Updates token in pdu with length len and data.
Definition: pdu.c:273
int coap_get_data(const coap_pdu_t *pdu, size_t *len, uint8_t **data)
Retrieves the length and data pointer of specified PDU.
Definition: pdu.c:644
size_t coap_add_option(coap_pdu_t *pdu, uint16_t type, size_t len, const uint8_t *data)
Adds option of given type to pdu that is passed as first parameter.
Definition: pdu.c:535
coap_pdu_t * coap_pdu_duplicate(const coap_pdu_t *old_pdu, coap_session_t *session, size_t token_length, uint8_t *token, coap_opt_filter_t *drop_options)
Duplicate an existing PDU.
Definition: pdu.c:146
int coap_get_data_large(const coap_pdu_t *pdu, size_t *len, const uint8_t **data, size_t *offset, size_t *total)
Retrieves the data from a PDU, with support for large bodies of data that spans multiple PDUs.
Definition: pdu.c:658
const char * coap_response_phrase(unsigned char code)
Returns a human-readable response phrase for the specified CoAP response code.
Definition: pdu.c:722
size_t coap_update_option(coap_pdu_t *pdu, uint16_t type, size_t len, const uint8_t *data)
Updates existing first option of given type in the pdu with the new data.
Definition: pdu.c:494
size_t coap_insert_option(coap_pdu_t *pdu, uint16_t type, size_t len, const uint8_t *data)
Inserts option of given type in the pdu with the appropriate data.
Definition: pdu.c:405
int coap_remove_option(coap_pdu_t *pdu, uint16_t type)
Removes option of given type from the pdu.
Definition: pdu.c:305
int coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds given data to the pdu that is passed as first parameter.
Definition: pdu.c:614
#define COAP_OPTION_BLOCK2
Definition: pdu.h:140
#define COAP_OPTION_CONTENT_FORMAT
Definition: pdu.h:132
#define COAP_OPTION_SIZE2
Definition: pdu.h:142
#define COAP_OPTION_BLOCK1
Definition: pdu.h:141
int coap_mid_t
coap_mid_t is used to store the CoAP Message ID of a CoAP PDU.
Definition: pdu.h:244
#define COAP_RESPONSE_CODE(N)
Definition: pdu.h:156
#define COAP_RESPONSE_CLASS(C)
Definition: pdu.h:159
#define COAP_OPTION_SIZE1
Definition: pdu.h:145
#define COAP_MESSAGE_NON
Definition: pdu.h:76
#define COAP_MEDIATYPE_TEXT_PLAIN
Definition: pdu.h:202
#define COAP_OPTION_CONTENT_TYPE
Definition: pdu.h:133
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition: pdu.h:247
#define COAP_OPTION_MAXAGE
Definition: pdu.h:135
#define COAP_OPTION_ETAG
Definition: pdu.h:125
#define COAP_OPTION_OBSERVE
Definition: pdu.h:127
#define COAP_PDU_IS_REQUEST(pdu)
Definition: pdu.h:319
CoAP binary data definition.
Definition: str.h:48
size_t length
length of binary data
Definition: str.h:49
uint8_t * s
binary data
Definition: str.h:50
Structure of Block options.
Definition: block.h:33
unsigned int num
block number
Definition: block.h:34
unsigned int szx
block size
Definition: block.h:36
unsigned int m
1 if more blocks follow, 0 otherwise
Definition: block.h:35
The CoAP stack's global state is stored in a coap_context_t object.
Definition: net.h:150
uint64_t etag
Next ETag to use.
Definition: net.h:218
coap_response_handler_t response_handler
Definition: net.h:188
coap_resource_t * proxy_uri_resource
can be used for handling proxy URI resources
Definition: net.h:156
uint8_t block_mode
Zero or more COAP_BLOCK_ or'd options.
Definition: net.h:217
coap_resource_t * unknown_resource
can be used for handling unknown resources
Definition: net.h:154
size_t token_length
length of token
uint32_t count
the number of packets sent for payload
coap_binary_t * app_token
original PDU token
uint8_t token[8]
last used token
coap_string_t * query
Associated query for the resource.
uint64_t etag
ETag value.
coap_resource_t * resource
associated resource
coap_time_t maxage_expire
When this entry expires.
Structure to hold large body (many blocks) client receive information.
uint16_t block_option
Block option in use.
uint8_t etag[8]
ETag for block checking.
uint8_t etag_length
ETag length.
uint8_t last_type
Last request type (CON/NON)
uint8_t observe_length
Length of observe data.
uint8_t observe[3]
Observe data (if set) (only 24 bits)
uint8_t etag_set
Set if ETag is in receive PDU.
coap_rblock_t rec_blocks
uint8_t initial
If set, has not been used yet.
uint8_t szx
size of individual blocks
uint16_t content_format
Content format for the set of blocks.
coap_pdu_t pdu
skeletal PDU
coap_tick_t last_used
< list of received blocks
coap_binary_t * app_token
app requesting PDU token
uint8_t token[8]
last used token
uint8_t base_token[8]
established base PDU token
size_t token_length
length of token
size_t base_token_length
length of token
coap_binary_t * body_data
Used for re-assembling entire body.
uint8_t observe_set
Set if this is an observe receive PDU.
size_t total_len
Length as indicated by SIZE2 option.
Structure to hold large body (many blocks) server receive information.
coap_mid_t last_mid
Last received mid for this set of packets.
uint8_t last_token[8]
< list of received blocks
size_t total_len
Length as indicated by SIZE1 option.
uint8_t observe_length
Length of observe data.
coap_rblock_t rec_blocks
set to uri_path if unknown resource
coap_binary_t * body_data
Used for re-assembling entire body.
coap_resource_t * resource
associated resource
size_t last_token_length
length of token
uint8_t observe_set
Set if this is an observe receive PDU.
uint8_t last_type
Last request type (CON/NON)
coap_tick_t last_used
Last time data sent or 0.
uint8_t observe[3]
Observe data (if set) (only 24 bits)
uint16_t content_format
Content format for the set of blocks.
coap_str_const_t * uri_path
Structure to hold large body (many blocks) transmission information.
coap_release_large_data_t release_func
large data de-alloc function
uint8_t blk_size
large block transmission size
union coap_lg_xmit_t::@1 b
const uint8_t * data
large data ptr
int last_block
last acknowledged block number
size_t offset
large data next offset to transmit
coap_pdu_t pdu
skeletal PDU
size_t length
large data length
coap_tick_t last_used
Last time all data sent or 0.
coap_l_block1_t b1
coap_l_block2_t b2
uint16_t option
large block transmisson CoAP option
void * app_ptr
applicaton provided ptr for de-alloc function
Iterator to run through PDU options.
Definition: option.h:169
uint16_t type
decoded option type
Definition: option.h:171
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
Definition: pdu.h:287
uint8_t type
message type
Definition: pdu.h:288
uint8_t * token
first byte of token, if any, or options
Definition: pdu.h:298
size_t body_length
Holds body data length.
Definition: pdu.h:311
size_t max_size
maximum size for token, options and payload, or zero for variable size pdu
Definition: pdu.h:297
const uint8_t * body_data
Holds ptr to re-assembled data or NULL.
Definition: pdu.h:310
size_t body_offset
Holds body data offset.
Definition: pdu.h:312
uint8_t code
request method (value 1–31) or response code (value 64-255)
Definition: pdu.h:289
uint16_t mid
message id, if any, in regular host byte order
Definition: pdu.h:293
uint8_t token_length
length of Token
Definition: pdu.h:292
uint8_t hdr_size
actual size used for protocol-specific header
Definition: pdu.h:291
uint8_t * data
first byte of payload, if any
Definition: pdu.h:299
size_t used_size
used bytes of storage for token, options and payload
Definition: pdu.h:296
size_t alloc_size
allocated storage for token, options and payload
Definition: pdu.h:295
size_t body_total
Holds body data total size.
Definition: pdu.h:313
Structure to keep track of received blocks.
coap_tick_t last_seen
struct coap_lg_range range[COAP_RBLOCK_CNT]
Abstraction of resource that can be attached to coap_context_t.
coap_str_const_t * uri_path
Request URI Path for this resource.
unsigned int observe
The next value for the Observe option.
coap_lg_xmit_t * lg_xmit
list of large transmissions
Definition: coap_session.h:80
uint64_t tx_token
Next token number to use.
Definition: coap_session.h:128
uint8_t block_mode
Zero or more COAP_BLOCK_ or'd options.
Definition: coap_session.h:127
struct coap_context_t * context
session's context
Definition: coap_session.h:73
coap_lg_srcv_t * lg_srcv
Server list of expected large receives.
Definition: coap_session.h:82
coap_lg_crcv_t * lg_crcv
Client list of expected large receives.
Definition: coap_session.h:81
CoAP string data definition.
Definition: str.h:30
uint8_t * s
string data
Definition: str.h:32
size_t length
length of string
Definition: str.h:31
Subscriber information.
coap_block_t block
GET/FETCH request Block definition.
unsigned int has_block2
GET request had Block2 definition.
#define LL_DELETE(head, del)
Definition: utlist.h:385
#define LL_FOREACH(head, el)
Definition: utlist.h:413
#define LL_PREPEND(head, add)
Definition: utlist.h:314
#define LL_FOREACH_SAFE(head, el, tmp)
Definition: utlist.h:419