iotivity 0.9.0
[platform/upstream/iotivity.git] / resource / csdk / libcoap-4.1.1 / block.c
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 #ifdef WITH_ARDUINO
16 /* On Arduino the abort function, needed for assert, is defined in std lib */
17 #include <stdlib.h>
18 #endif
19
20 #include "debug.h"
21 #include "block.h"
22
23 #define min(a,b) ((a) < (b) ? (a) : (b))
24
25 #ifndef WITHOUT_BLOCK
26 unsigned int
27 coap_opt_block_num(const coap_opt_t *block_opt) {
28   unsigned int num = 0;
29   unsigned short len;
30   
31   len = coap_opt_length(block_opt);
32
33   if (len == 0) {
34     return 0;
35   }
36   
37   if (len > 1) {
38     num = coap_decode_var_bytes(COAP_OPT_VALUE(block_opt), 
39                                 COAP_OPT_LENGTH(block_opt) - 1);
40   }
41   
42   return (num << 4) | ((*COAP_OPT_BLOCK_LAST(block_opt) & 0xF0) >> 4);
43 }
44
45 int
46 coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block) {
47   coap_opt_iterator_t opt_iter;
48   coap_opt_t *option;
49
50   assert(block);
51   memset(block, 0, sizeof(coap_block_t));
52
53   if (pdu && (option = coap_check_option(pdu, type, &opt_iter))) {
54     block->szx = COAP_OPT_BLOCK_SZX(option);
55     if (COAP_OPT_BLOCK_MORE(option))
56       block->m = 1;
57     block->num = coap_opt_block_num(option);
58     return 1;
59   }
60
61   return 0;
62 }
63
64 int
65 coap_write_block_opt(coap_block_t *block, unsigned short type,
66                      coap_pdu_t *pdu, size_t data_length) {
67   size_t start, want, avail;
68   unsigned char buf[3];
69
70   assert(pdu);
71
72   /* Block2 */
73   if (type != COAP_OPTION_BLOCK2) {
74     warn("coap_write_block_opt: skipped unknown option\n");
75     return -1;
76   }
77
78   start = block->num << (block->szx + 4);
79   if (data_length <= start) {
80     debug("illegal block requested\n");
81     return -2;
82   }
83   
84   avail = pdu->max_size - pdu->length - 4;
85   want = 1 << (block->szx + 4);
86
87   /* check if entire block fits in message */
88   if (want <= avail) {
89     block->m = want < data_length - start;
90   } else {
91     /* Sender has requested a block that is larger than the remaining
92      * space in pdu. This is ok if the remaining data fits into the pdu
93      * anyway. The block size needs to be adjusted only if there is more
94      * data left that cannot be delivered in this message. */
95
96     if (data_length - start <= avail) {
97
98       /* it's the final block and everything fits in the message */
99       block->m = 0;
100     } else {
101       unsigned char szx;
102
103       /* we need to decrease the block size */
104       if (avail < 16) {         /* bad luck, this is the smallest block size */
105         debug("not enough space, even the smallest block does not fit");
106         return -3;
107       }
108       debug("decrease block size for %d to %d\n", avail, coap_fls(avail) - 5);
109       szx = block->szx;
110       block->szx = coap_fls(avail) - 5;
111       block->m = 1;
112       block->num <<= szx - block->szx;
113     }
114   }
115
116   /* to re-encode the block option */
117   coap_add_option(pdu, type, coap_encode_var_bytes(buf, ((block->num << 4) | 
118                                                          (block->m << 3) | 
119                                                          block->szx)), 
120                   buf);
121
122   return 1;
123 }
124
125 int 
126 coap_add_block(coap_pdu_t *pdu, unsigned int len, const unsigned char *data,
127                unsigned int block_num, unsigned char block_szx) {
128   size_t start;
129   start = block_num << (block_szx + 4);
130
131   if (len <= start)
132     return 0;
133   
134   return coap_add_data(pdu, 
135                        min(len - start, (unsigned int)(1 << (block_szx + 4))),
136                        data + start);
137 }
138 #endif /* WITHOUT_BLOCK  */