libcoap  4.1.2
block.c
Go to the documentation of this file.
1 /* block.c -- block transfer
2  *
3  * Copyright (C) 2010--2012,2015-2016 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 "coap_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 #if (COAP_MAX_PDU_SIZE - 6) < (1 << (COAP_MAX_BLOCK_SZX + 4))
19 #error "COAP_MAX_BLOCK_SZX too large"
20 #endif
21 
22 #define min(a,b) ((a) < (b) ? (a) : (b))
23 
24 #ifndef WITHOUT_BLOCK
25 unsigned int
26 coap_opt_block_num(const coap_opt_t *block_opt) {
27  unsigned int num = 0;
28  unsigned short len;
29 
30  len = coap_opt_length(block_opt);
31 
32  if (len == 0) {
33  return 0;
34  }
35 
36  if (len > 1) {
37  num = coap_decode_var_bytes(COAP_OPT_VALUE(block_opt),
38  COAP_OPT_LENGTH(block_opt) - 1);
39  }
40 
41  return (num << 4) | ((*COAP_OPT_BLOCK_LAST(block_opt) & 0xF0) >> 4);
42 }
43 
44 int
45 coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block) {
46  coap_opt_iterator_t opt_iter;
47  coap_opt_t *option;
48 
49  assert(block);
50  memset(block, 0, sizeof(coap_block_t));
51 
52  if (pdu && (option = coap_check_option(pdu, type, &opt_iter))) {
53  unsigned int num;
54 
55  block->szx = COAP_OPT_BLOCK_SZX(option);
56  if (COAP_OPT_BLOCK_MORE(option))
57  block->m = 1;
58 
59  /* The block number is at most 20 bits, so values above 2^20 - 1
60  * are illegal. */
61  num = coap_opt_block_num(option);
62  if (num > 0xFFFFF) {
63  return 0;
64  }
65  block->num = num;
66  return 1;
67  }
68 
69  return 0;
70 }
71 
72 int
73 coap_write_block_opt(coap_block_t *block, unsigned short type,
74  coap_pdu_t *pdu, size_t data_length) {
75  size_t start, want, avail;
76  unsigned char buf[4];
77 
78  assert(pdu);
79 
80  start = block->num << (block->szx + 4);
81  if (data_length <= start) {
82  debug("illegal block requested\n");
83  return -2;
84  }
85 
86  avail = pdu->max_size - pdu->length - 4;
87  want = 1 << (block->szx + 4);
88 
89  /* check if entire block fits in message */
90  if (want <= avail) {
91  block->m = want < data_length - start;
92  } else {
93  /* Sender has requested a block that is larger than the remaining
94  * space in pdu. This is ok if the remaining data fits into the pdu
95  * anyway. The block size needs to be adjusted only if there is more
96  * data left that cannot be delivered in this message. */
97 
98  if (data_length - start <= avail) {
99 
100  /* it's the final block and everything fits in the message */
101  block->m = 0;
102  } else {
103  unsigned char szx;
104 
105  /* we need to decrease the block size */
106  if (avail < 16) { /* bad luck, this is the smallest block size */
107  debug("not enough space, even the smallest block does not fit");
108  return -3;
109  }
110  debug("decrease block size for %zu to %d\n", avail, coap_fls(avail) - 5);
111  szx = block->szx;
112  block->szx = coap_fls(avail) - 5;
113  block->m = 1;
114  block->num <<= szx - block->szx;
115  }
116  }
117 
118  /* to re-encode the block option */
119  coap_add_option(pdu, type, coap_encode_var_bytes(buf, ((block->num << 4) |
120  (block->m << 3) |
121  block->szx)),
122  buf);
123 
124  return 1;
125 }
126 
127 int
128 coap_add_block(coap_pdu_t *pdu, unsigned int len, const unsigned char *data,
129  unsigned int block_num, unsigned char block_szx) {
130  size_t start;
131  start = block_num << (block_szx + 4);
132 
133  if (len <= start)
134  return 0;
135 
136  return coap_add_data(pdu,
137  min(len - start, (unsigned int)(1 << (block_szx + 4))),
138  data + start);
139 }
140 #endif /* WITHOUT_BLOCK */
int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block)
Initializes block from pdu.
Definition: block.c:45
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:26
#define min(a, b)
Definition: block.c:22
int coap_write_block_opt(coap_block_t *block, unsigned short type, coap_pdu_t *pdu, size_t data_length)
Writes a block option of type type to message pdu.
Definition: block.c:73
unsigned short length
PDU length (including header, options, data)
Definition: pdu.h:234
int coap_fls(unsigned int i)
Definition: encode.c:17
#define debug(...)
Definition: debug.h:66
Header structure for CoAP PDUs.
Definition: pdu.h:227
#define assert(...)
Definition: mem.c:17
unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val)
Encodes multiple-length byte sequences.
Definition: encode.c:34
#define COAP_OPT_BLOCK_LAST(opt)
Returns the value of the least significant byte of a Block option opt.
Definition: block.h:44
size_t max_size
allocated storage for options and data
Definition: pdu.h:228
int coap_add_block(coap_pdu_t *pdu, unsigned int len, const unsigned char *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:128
Iterator to run through PDU options.
Definition: option.h:253
size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data)
de-duplicate code with coap_add_option_later
Definition: pdu.c:171
int coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data)
Adds given data to the pdu that is passed as first parameter.
Definition: pdu.c:234
Structure of Block options.
Definition: block.h:33
#define COAP_OPT_LENGTH(opt)
Definition: option.h:392
#define COAP_OPT_BLOCK_SZX(opt)
Returns the value of the SZX-field of a Block option opt.
Definition: block.h:52
unsigned char coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: option.h:25
coap_opt_t * coap_check_option(coap_pdu_t *pdu, unsigned short type, coap_opt_iterator_t *oi)
Retrieves the first option of type type from pdu.
Definition: option.c:209
#define COAP_OPT_BLOCK_MORE(opt)
Returns the value of the More-bit of a Block option opt.
Definition: block.h:48
unsigned int coap_decode_var_bytes(unsigned char *buf, unsigned int len)
Decodes multiple-length byte sequences.
Definition: encode.c:25
unsigned short coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: option.c:251
#define COAP_OPT_VALUE(opt)
Definition: option.h:406
unsigned int m
1 if more blocks follow, 0 otherwise
Definition: block.h:35
unsigned int szx
block size
Definition: block.h:36
unsigned int num
block number
Definition: block.h:34