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