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