1 /*
2 * Copyright (c) 2018 Intel Corporation
3 * Copyright (c) 2023 Basalte bv
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(net_coap_service_sample);
10
11 #include <zephyr/sys/printk.h>
12 #include <zephyr/net/coap_service.h>
13
14 #define BLOCK_WISE_TRANSFER_SIZE_GET 2048
15
large_get(struct coap_resource * resource,struct coap_packet * request,struct sockaddr * addr,socklen_t addr_len)16 static int large_get(struct coap_resource *resource,
17 struct coap_packet *request,
18 struct sockaddr *addr, socklen_t addr_len)
19
20 {
21 uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
22 static struct coap_block_context ctx;
23 struct coap_packet response;
24 uint8_t payload[64];
25 uint8_t token[COAP_TOKEN_MAX_LEN];
26 uint16_t size;
27 uint16_t id;
28 uint8_t code;
29 uint8_t type;
30 uint8_t tkl;
31 int r;
32
33 if (ctx.total_size == 0) {
34 coap_block_transfer_init(&ctx, COAP_BLOCK_64, BLOCK_WISE_TRANSFER_SIZE_GET);
35 }
36
37 r = coap_update_from_block(request, &ctx);
38 if (r < 0) {
39 return -EINVAL;
40 }
41
42 code = coap_header_get_code(request);
43 type = coap_header_get_type(request);
44 id = coap_header_get_id(request);
45 tkl = coap_header_get_token(request, token);
46
47 LOG_INF("*******");
48 LOG_INF("type: %u code %u id %u", type, code, id);
49 LOG_INF("*******");
50
51 r = coap_packet_init(&response, data, sizeof(data),
52 COAP_VERSION_1, COAP_TYPE_ACK, tkl, token,
53 COAP_RESPONSE_CODE_CONTENT, id);
54 if (r < 0) {
55 return -EINVAL;
56 }
57
58 r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT,
59 COAP_CONTENT_FORMAT_TEXT_PLAIN);
60 if (r < 0) {
61 return r;
62 }
63
64 r = coap_append_block2_option(&response, &ctx);
65 if (r < 0) {
66 return r;
67 }
68
69 r = coap_packet_append_payload_marker(&response);
70 if (r < 0) {
71 return r;
72 }
73
74 size = MIN(coap_block_size_to_bytes(ctx.block_size),
75 ctx.total_size - ctx.current);
76
77 memset(payload, 'A', MIN(size, sizeof(payload)));
78
79 r = coap_packet_append_payload(&response, (uint8_t *)payload, size);
80 if (r < 0) {
81 return r;
82 }
83
84 r = coap_next_block(&response, &ctx);
85 if (!r) {
86 /* Will return 0 when it's the last block. */
87 memset(&ctx, 0, sizeof(ctx));
88 }
89
90 r = coap_resource_send(resource, &response, addr, addr_len, NULL);
91
92 return r;
93 }
94
large_update_put(struct coap_resource * resource,struct coap_packet * request,struct sockaddr * addr,socklen_t addr_len)95 static int large_update_put(struct coap_resource *resource,
96 struct coap_packet *request,
97 struct sockaddr *addr, socklen_t addr_len)
98 {
99 uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
100 static struct coap_block_context ctx;
101 struct coap_packet response;
102 const uint8_t *payload;
103 uint8_t token[COAP_TOKEN_MAX_LEN];
104 uint16_t id;
105 uint16_t len;
106 uint8_t code;
107 uint8_t type;
108 uint8_t tkl;
109 int r;
110 bool last_block;
111
112 r = coap_get_option_int(request, COAP_OPTION_BLOCK1);
113 if (r < 0) {
114 return -EINVAL;
115 }
116
117 last_block = !GET_MORE(r);
118
119 /* initialize block context upon the arrival of first block */
120 if (!GET_BLOCK_NUM(r)) {
121 coap_block_transfer_init(&ctx, COAP_BLOCK_64, 0);
122 }
123
124 r = coap_update_from_block(request, &ctx);
125 if (r < 0) {
126 LOG_ERR("Invalid block size option from request");
127 return -EINVAL;
128 }
129
130 payload = coap_packet_get_payload(request, &len);
131 if (!last_block && payload == NULL) {
132 LOG_ERR("Packet without payload");
133 return -EINVAL;
134 }
135
136 LOG_INF("**************");
137 LOG_INF("[ctx] current %zu block_size %u total_size %zu",
138 ctx.current, coap_block_size_to_bytes(ctx.block_size),
139 ctx.total_size);
140 LOG_INF("**************");
141
142 code = coap_header_get_code(request);
143 type = coap_header_get_type(request);
144 id = coap_header_get_id(request);
145 tkl = coap_header_get_token(request, token);
146
147 LOG_INF("*******");
148 LOG_INF("type: %u code %u id %u", type, code, id);
149 LOG_INF("*******");
150
151 /* Do something with the payload */
152
153 if (!last_block) {
154 code = COAP_RESPONSE_CODE_CONTINUE;
155 } else {
156 code = COAP_RESPONSE_CODE_CHANGED;
157 }
158
159 r = coap_ack_init(&response, request, data, sizeof(data), code);
160 if (r < 0) {
161 return r;
162 }
163
164 r = coap_append_block1_option(&response, &ctx);
165 if (r < 0) {
166 LOG_ERR("Could not add Block1 option to response");
167 return r;
168 }
169
170 r = coap_resource_send(resource, &response, addr, addr_len, NULL);
171
172 return r;
173 }
174
large_create_post(struct coap_resource * resource,struct coap_packet * request,struct sockaddr * addr,socklen_t addr_len)175 static int large_create_post(struct coap_resource *resource,
176 struct coap_packet *request,
177 struct sockaddr *addr, socklen_t addr_len)
178 {
179 uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
180 static struct coap_block_context ctx;
181 struct coap_packet response;
182 const uint8_t *payload;
183 uint8_t token[COAP_TOKEN_MAX_LEN];
184 uint16_t len;
185 uint16_t id;
186 uint8_t code;
187 uint8_t type;
188 uint8_t tkl;
189 int r;
190 bool last_block;
191
192 r = coap_get_option_int(request, COAP_OPTION_BLOCK1);
193 if (r < 0) {
194 return -EINVAL;
195 }
196
197 last_block = !GET_MORE(r);
198
199 /* initialize block context upon the arrival of first block */
200 if (!GET_BLOCK_NUM(r)) {
201 coap_block_transfer_init(&ctx, COAP_BLOCK_32, 0);
202 }
203
204 r = coap_update_from_block(request, &ctx);
205 if (r < 0) {
206 LOG_ERR("Invalid block size option from request");
207 return -EINVAL;
208 }
209
210 payload = coap_packet_get_payload(request, &len);
211 if (!last_block && payload) {
212 LOG_ERR("Packet without payload");
213 return -EINVAL;
214 }
215
216 code = coap_header_get_code(request);
217 type = coap_header_get_type(request);
218 id = coap_header_get_id(request);
219 tkl = coap_header_get_token(request, token);
220
221 LOG_INF("*******");
222 LOG_INF("type: %u code %u id %u", type, code, id);
223 LOG_INF("*******");
224
225 if (!last_block) {
226 code = COAP_RESPONSE_CODE_CONTINUE;
227 } else {
228 code = COAP_RESPONSE_CODE_CREATED;
229 }
230
231 r = coap_ack_init(&response, request, data, sizeof(data), code);
232 if (r < 0) {
233 return r;
234 }
235
236 r = coap_append_block1_option(&response, &ctx);
237 if (r < 0) {
238 LOG_ERR("Could not add Block1 option to response");
239 return r;
240 }
241
242 r = coap_resource_send(resource, &response, addr, addr_len, NULL);
243
244 return r;
245 }
246
247 static const char * const large_path[] = { "large", NULL };
248 COAP_RESOURCE_DEFINE(large, coap_server,
249 {
250 .get = large_get,
251 .path = large_path,
252 });
253
254 static const char * const large_update_path[] = { "large-update", NULL };
255 COAP_RESOURCE_DEFINE(large_update, coap_server,
256 {
257 .put = large_update_put,
258 .path = large_update_path,
259 });
260
261 static const char * const large_create_path[] = { "large-create", NULL };
262 COAP_RESOURCE_DEFINE(large_create, coap_server,
263 {
264 .post = large_create_post,
265 .path = large_create_path,
266 });
267