libcoap  4.0.3
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
block.c
Go to the documentation of this file.
1 /* block.c -- block transfer
2  *
3  * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8 
9 #include "config.h"
10 
11 #if defined(HAVE_ASSERT_H) && !defined(assert)
12 # include <assert.h>
13 #endif
14 
15 #include "debug.h"
16 #include "block.h"
17 
18 #define min(a,b) ((a) < (b) ? (a) : (b))
19 
20 #ifndef WITHOUT_BLOCK
21 int
22 coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block) {
23  coap_opt_iterator_t opt_iter;
24  coap_opt_t *option;
25 
26  assert(block);
27  memset(block, 0, sizeof(coap_block_t));
28 
29  if (pdu && (option = coap_check_option(pdu, type, &opt_iter))) {
30  block->szx = COAP_OPT_BLOCK_SZX(option);
31  if (COAP_OPT_BLOCK_MORE(option))
32  block->m = 1;
33  block->num = COAP_OPT_BLOCK_NUM(option);
34 
35  return 1;
36  }
37 
38  return 0;
39 }
40 
41 int
42 coap_write_block_opt(coap_block_t *block, unsigned short type,
43  coap_pdu_t *pdu, size_t data_length) {
44  size_t start, want, avail;
45  unsigned char buf[3];
46 
47  assert(pdu);
48 
49  /* Block2 */
50  if (type != COAP_OPTION_BLOCK2) {
51  warn("coap_write_block_opt: skipped unknown option\n");
52  return -1;
53  }
54 
55  start = block->num << (block->szx + 4);
56  if (data_length <= start) {
57  debug("illegal block requested\n");
58  return -2;
59  }
60 
61  avail = pdu->max_size - pdu->length - 4;
62  want = 1 << (block->szx + 4);
63 
64  /* check if entire block fits in message */
65  if (want <= avail) {
66  block->m = want < data_length - start;
67  } else {
68  /* Sender has requested a block that is larger than the remaining
69  * space in pdu. This is ok if the remaining data fits into the pdu
70  * anyway. The block size needs to be adjusted only if there is more
71  * data left that cannot be delivered in this message. */
72 
73  if (data_length - start <= avail) {
74 
75  /* it's the final block and everything fits in the message */
76  block->m = 0;
77  } else {
78  unsigned char szx;
79 
80  /* we need to decrease the block size */
81  if (avail < 16) { /* bad luck, this is the smallest block size */
82  debug("not enough space, even the smallest block does not fit");
83  return -3;
84  }
85  debug("decrease block size for %d to %d\n", avail, coap_fls(avail) - 5);
86  szx = block->szx;
87  block->szx = coap_fls(avail) - 5;
88  block->m = 1;
89  block->num <<= szx - block->szx;
90  }
91  }
92 
93  /* to re-encode the block option */
94  coap_add_option(pdu, type, coap_encode_var_bytes(buf, ((block->num << 4) |
95  (block->m << 3) |
96  block->szx)),
97  buf);
98 
99  return 1;
100 }
101 
102 int
103 coap_add_block(coap_pdu_t *pdu, unsigned int len, const unsigned char *data,
104  unsigned int block_num, unsigned char block_szx) {
105  size_t start;
106  start = block_num << (block_szx + 4);
107 
108  if (len <= start)
109  return 0;
110 
111  return coap_add_data(pdu,
112  min(len - start, (unsigned int)(1 << (block_szx + 4))),
113  data + start);
114 }
115 #endif /* WITHOUT_BLOCK */