1 /*
2  * Copyright (c) 2023 Basalte bv
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <string.h>
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(net_coap, CONFIG_COAP_LOG_LEVEL);
10 
11 #include <zephyr/net/socket.h>
12 
13 #include <zephyr/init.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/net/coap.h>
16 #include <zephyr/net/coap_link_format.h>
17 #include <zephyr/net/coap_mgmt.h>
18 #include <zephyr/net/coap_service.h>
19 #include <zephyr/sys/fdtable.h>
20 #include <zephyr/zvfs/eventfd.h>
21 
22 #if defined(CONFIG_NET_TC_THREAD_COOPERATIVE)
23 /* Lowest priority cooperative thread */
24 #define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1)
25 #else
26 #define THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1)
27 #endif
28 
29 #define ADDRLEN(sock) \
30 	(((struct sockaddr *)sock)->sa_family == AF_INET ? \
31 		sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))
32 
33 /* Shortened defines */
34 #define MAX_OPTIONS    CONFIG_COAP_SERVER_MESSAGE_OPTIONS
35 #define MAX_PENDINGS   CONFIG_COAP_SERVICE_PENDING_MESSAGES
36 #define MAX_OBSERVERS  CONFIG_COAP_SERVICE_OBSERVERS
37 #define MAX_POLL_FD    CONFIG_ZVFS_POLL_MAX
38 
39 BUILD_ASSERT(CONFIG_ZVFS_POLL_MAX > 0, "CONFIG_ZVFS_POLL_MAX can't be 0");
40 
41 static K_MUTEX_DEFINE(lock);
42 static int control_sock;
43 
44 #if defined(CONFIG_COAP_SERVER_PENDING_ALLOCATOR_STATIC)
45 K_MEM_SLAB_DEFINE_STATIC(pending_data, CONFIG_COAP_SERVER_MESSAGE_SIZE,
46 			 CONFIG_COAP_SERVER_PENDING_ALLOCATOR_STATIC_BLOCKS, 4);
47 #endif
48 
coap_server_alloc(size_t len)49 static inline void *coap_server_alloc(size_t len)
50 {
51 #if defined(CONFIG_COAP_SERVER_PENDING_ALLOCATOR_STATIC)
52 	void *ptr;
53 	int ret;
54 
55 	if (len > CONFIG_COAP_SERVER_MESSAGE_SIZE) {
56 		return NULL;
57 	}
58 
59 	ret = k_mem_slab_alloc(&pending_data, &ptr, K_NO_WAIT);
60 	if (ret < 0) {
61 		return NULL;
62 	}
63 
64 	return ptr;
65 #elif defined(CONFIG_COAP_SERVER_PENDING_ALLOCATOR_SYSTEM_HEAP)
66 	return k_malloc(len);
67 #else
68 	ARG_UNUSED(len);
69 
70 	return NULL;
71 #endif
72 }
73 
coap_server_free(void * ptr)74 static inline void coap_server_free(void *ptr)
75 {
76 #if defined(CONFIG_COAP_SERVER_PENDING_ALLOCATOR_STATIC)
77 	k_mem_slab_free(&pending_data, ptr);
78 #elif defined(CONFIG_COAP_SERVER_PENDING_ALLOCATOR_SYSTEM_HEAP)
79 	k_free(ptr);
80 #else
81 	ARG_UNUSED(ptr);
82 #endif
83 }
84 
coap_service_remove_observer(const struct coap_service * service,struct coap_resource * resource,const struct sockaddr * addr,const uint8_t * token,uint8_t tkl)85 static int coap_service_remove_observer(const struct coap_service *service,
86 					struct coap_resource *resource,
87 					const struct sockaddr *addr,
88 					const uint8_t *token, uint8_t tkl)
89 {
90 	struct coap_observer *obs;
91 
92 	if (tkl > 0 && addr != NULL) {
93 		/* Prefer addr+token to find the observer */
94 		obs = coap_find_observer(service->data->observers, MAX_OBSERVERS, addr, token, tkl);
95 	} else if (tkl > 0) {
96 		/* Then try to find the observer by token */
97 		obs = coap_find_observer_by_token(service->data->observers, MAX_OBSERVERS, token,
98 						  tkl);
99 	} else if (addr != NULL) {
100 		obs = coap_find_observer_by_addr(service->data->observers, MAX_OBSERVERS, addr);
101 	} else {
102 		/* Either a token or an address is required */
103 		return -EINVAL;
104 	}
105 
106 	if (obs == NULL) {
107 		return 0;
108 	}
109 
110 	if (resource == NULL) {
111 		COAP_SERVICE_FOREACH_RESOURCE(service, it) {
112 			if (coap_remove_observer(it, obs)) {
113 				memset(obs, 0, sizeof(*obs));
114 				return 1;
115 			}
116 		}
117 	} else if (coap_remove_observer(resource, obs)) {
118 		memset(obs, 0, sizeof(*obs));
119 		return 1;
120 	}
121 
122 	return 0;
123 }
124 
coap_server_process(int sock_fd)125 static int coap_server_process(int sock_fd)
126 {
127 	static uint8_t buf[CONFIG_COAP_SERVER_MESSAGE_SIZE];
128 
129 	struct sockaddr client_addr;
130 	socklen_t client_addr_len = sizeof(client_addr);
131 	struct coap_service *service = NULL;
132 	struct coap_packet request;
133 	struct coap_pending *pending;
134 	struct coap_option options[MAX_OPTIONS] = { 0 };
135 	uint8_t opt_num = MAX_OPTIONS;
136 	uint8_t type;
137 	ssize_t received;
138 	int ret;
139 	int flags = ZSOCK_MSG_DONTWAIT;
140 
141 	if (IS_ENABLED(CONFIG_COAP_SERVER_TRUNCATE_MSGS)) {
142 		flags |= ZSOCK_MSG_TRUNC;
143 	}
144 
145 	received = zsock_recvfrom(sock_fd, buf, sizeof(buf), flags, &client_addr, &client_addr_len);
146 
147 	if (received < 0) {
148 		if (errno == EWOULDBLOCK) {
149 			return 0;
150 		}
151 
152 		LOG_ERR("Failed to process client request (%d)", -errno);
153 		return -errno;
154 	}
155 
156 	ret = coap_packet_parse(&request, buf, MIN(received, sizeof(buf)), options, opt_num);
157 	if (ret < 0) {
158 		LOG_ERR("Failed To parse coap message (%d)", ret);
159 		return ret;
160 	}
161 
162 	(void)k_mutex_lock(&lock, K_FOREVER);
163 	/* Find the active service */
164 	COAP_SERVICE_FOREACH(svc) {
165 		if (svc->data->sock_fd == sock_fd) {
166 			service = svc;
167 			break;
168 		}
169 	}
170 	if (service == NULL) {
171 		ret = -ENOENT;
172 		goto unlock;
173 	}
174 
175 	type = coap_header_get_type(&request);
176 
177 	if (received > sizeof(buf)) {
178 		/* The message was truncated and can't be processed further */
179 		struct coap_packet response;
180 		uint8_t token[COAP_TOKEN_MAX_LEN];
181 		uint8_t tkl = coap_header_get_token(&request, token);
182 		uint16_t id = coap_header_get_id(&request);
183 
184 		if (type == COAP_TYPE_CON) {
185 			type = COAP_TYPE_ACK;
186 		} else {
187 			type = COAP_TYPE_NON_CON;
188 		}
189 
190 		ret = coap_packet_init(&response, buf, sizeof(buf), COAP_VERSION_1, type, tkl,
191 				       token, COAP_RESPONSE_CODE_REQUEST_TOO_LARGE, id);
192 		if (ret < 0) {
193 			LOG_ERR("Failed to init response (%d)", ret);
194 			goto unlock;
195 		}
196 
197 		ret = coap_append_option_int(&response, COAP_OPTION_SIZE1,
198 					     CONFIG_COAP_SERVER_MESSAGE_SIZE);
199 		if (ret < 0) {
200 			LOG_ERR("Failed to add SIZE1 option (%d)", ret);
201 			goto unlock;
202 		}
203 
204 		ret = coap_service_send(service, &response, &client_addr, client_addr_len, NULL);
205 		if (ret < 0) {
206 			LOG_ERR("Failed to reply \"Request Entity Too Large\" (%d)", ret);
207 			goto unlock;
208 		}
209 
210 		goto unlock;
211 	}
212 
213 	pending = coap_pending_received(&request, service->data->pending, MAX_PENDINGS);
214 	if (pending) {
215 		uint8_t token[COAP_TOKEN_MAX_LEN];
216 		uint8_t tkl;
217 
218 		switch (type) {
219 		case COAP_TYPE_RESET:
220 			tkl = coap_header_get_token(&request, token);
221 			coap_service_remove_observer(service, NULL, &client_addr, token, tkl);
222 			__fallthrough;
223 		case COAP_TYPE_ACK:
224 			coap_server_free(pending->data);
225 			coap_pending_clear(pending);
226 			break;
227 		default:
228 			LOG_WRN("Unexpected pending type %d", type);
229 			ret = -EINVAL;
230 			goto unlock;
231 		}
232 
233 		goto unlock;
234 	} else if (type == COAP_TYPE_ACK || type == COAP_TYPE_RESET) {
235 		LOG_WRN("Unexpected type %d without pending packet", type);
236 		ret = -EINVAL;
237 		goto unlock;
238 	}
239 
240 	if (IS_ENABLED(CONFIG_COAP_SERVER_WELL_KNOWN_CORE) &&
241 	    coap_header_get_code(&request) == COAP_METHOD_GET &&
242 	    coap_uri_path_match(COAP_WELL_KNOWN_CORE_PATH, options, opt_num)) {
243 		uint8_t well_known_buf[CONFIG_COAP_SERVER_MESSAGE_SIZE];
244 		struct coap_packet response;
245 
246 		ret = coap_well_known_core_get_len(service->res_begin,
247 						   COAP_SERVICE_RESOURCE_COUNT(service),
248 						   &request, &response,
249 						   well_known_buf, sizeof(well_known_buf));
250 		if (ret < 0) {
251 			LOG_ERR("Failed to build well known core for %s (%d)", service->name, ret);
252 			goto unlock;
253 		}
254 
255 		ret = coap_service_send(service, &response, &client_addr, client_addr_len, NULL);
256 	} else {
257 		ret = coap_handle_request_len(&request, service->res_begin,
258 					      COAP_SERVICE_RESOURCE_COUNT(service),
259 					      options, opt_num, &client_addr, client_addr_len);
260 
261 		/* Translate errors to response codes */
262 		switch (ret) {
263 		case -ENOENT:
264 			ret = COAP_RESPONSE_CODE_NOT_FOUND;
265 			break;
266 		case -ENOTSUP:
267 			ret = COAP_RESPONSE_CODE_BAD_REQUEST;
268 			break;
269 		case -EPERM:
270 			ret = COAP_RESPONSE_CODE_NOT_ALLOWED;
271 			break;
272 		}
273 
274 		/* Shortcut for replying a code without a body */
275 		if (ret > 0 && type == COAP_TYPE_CON) {
276 			/* Minimal sized ack buffer */
277 			uint8_t ack_buf[COAP_TOKEN_MAX_LEN + 4U];
278 			struct coap_packet ack;
279 
280 			ret = coap_ack_init(&ack, &request, ack_buf, sizeof(ack_buf), (uint8_t)ret);
281 			if (ret < 0) {
282 				LOG_ERR("Failed to init ACK (%d)", ret);
283 				goto unlock;
284 			}
285 
286 			ret = coap_service_send(service, &ack, &client_addr, client_addr_len, NULL);
287 		}
288 	}
289 
290 unlock:
291 	(void)k_mutex_unlock(&lock);
292 
293 	return ret;
294 }
295 
coap_server_retransmit(void)296 static void coap_server_retransmit(void)
297 {
298 	struct coap_pending *pending;
299 	int64_t remaining;
300 	int64_t now = k_uptime_get();
301 	int ret;
302 
303 	(void)k_mutex_lock(&lock, K_FOREVER);
304 
305 	COAP_SERVICE_FOREACH(service) {
306 		if (service->data->sock_fd < 0) {
307 			continue;
308 		}
309 
310 		pending = coap_pending_next_to_expire(service->data->pending, MAX_PENDINGS);
311 		if (pending == NULL) {
312 			/* No work to be done */
313 			continue;
314 		}
315 
316 		/* Check if the pending request has expired */
317 		remaining = pending->t0 + pending->timeout - now;
318 		if (remaining > 0) {
319 			continue;
320 		}
321 
322 		if (coap_pending_cycle(pending)) {
323 			ret = zsock_sendto(service->data->sock_fd, pending->data, pending->len, 0,
324 					   &pending->addr, ADDRLEN(&pending->addr));
325 			if (ret < 0) {
326 				LOG_ERR("Failed to send pending retransmission for %s (%d)",
327 					service->name, ret);
328 			}
329 			__ASSERT_NO_MSG(ret == pending->len);
330 		} else {
331 			LOG_WRN("Packet retransmission failed for %s", service->name);
332 
333 			coap_service_remove_observer(service, NULL, &pending->addr, NULL, 0U);
334 			coap_server_free(pending->data);
335 			coap_pending_clear(pending);
336 		}
337 	}
338 
339 	(void)k_mutex_unlock(&lock);
340 }
341 
coap_server_poll_timeout(void)342 static int coap_server_poll_timeout(void)
343 {
344 	struct coap_pending *pending;
345 	int64_t result = INT64_MAX;
346 	int64_t remaining;
347 	int64_t now = k_uptime_get();
348 
349 	COAP_SERVICE_FOREACH(svc) {
350 		if (svc->data->sock_fd < -1) {
351 			continue;
352 		}
353 
354 		pending = coap_pending_next_to_expire(svc->data->pending, MAX_PENDINGS);
355 		if (pending == NULL) {
356 			continue;
357 		}
358 
359 		remaining = pending->t0 + pending->timeout - now;
360 		if (result > remaining) {
361 			result = remaining;
362 		}
363 	}
364 
365 	if (result == INT64_MAX) {
366 		return -1;
367 	}
368 
369 	return MAX(result, 0);
370 }
371 
coap_server_update_services(void)372 static void coap_server_update_services(void)
373 {
374 	if (zvfs_eventfd_write(control_sock, 1)) {
375 		LOG_ERR("Failed to notify server thread (%d)", errno);
376 	}
377 }
378 
coap_service_in_section(const struct coap_service * service)379 static inline bool coap_service_in_section(const struct coap_service *service)
380 {
381 	STRUCT_SECTION_START_EXTERN(coap_service);
382 	STRUCT_SECTION_END_EXTERN(coap_service);
383 
384 	return STRUCT_SECTION_START(coap_service) <= service &&
385 	       STRUCT_SECTION_END(coap_service) > service;
386 }
387 
coap_service_raise_event(const struct coap_service * service,uint64_t mgmt_event)388 static inline void coap_service_raise_event(const struct coap_service *service, uint64_t mgmt_event)
389 {
390 #if defined(CONFIG_NET_MGMT_EVENT_INFO)
391 	const struct net_event_coap_service net_event = {
392 		.service = service,
393 	};
394 
395 	net_mgmt_event_notify_with_info(mgmt_event, NULL, (void *)&net_event, sizeof(net_event));
396 #else
397 	ARG_UNUSED(service);
398 
399 	net_mgmt_event_notify(mgmt_event, NULL);
400 #endif
401 }
402 
coap_service_start(const struct coap_service * service)403 int coap_service_start(const struct coap_service *service)
404 {
405 	int ret;
406 
407 	uint8_t af;
408 	socklen_t len;
409 	struct sockaddr_storage addr_storage;
410 	union {
411 		struct sockaddr *addr;
412 		struct sockaddr_in *addr4;
413 		struct sockaddr_in6 *addr6;
414 	} addr_ptrs = {
415 		.addr = (struct sockaddr *)&addr_storage,
416 	};
417 	int proto = IPPROTO_UDP;
418 
419 	if (!coap_service_in_section(service)) {
420 		__ASSERT_NO_MSG(false);
421 		return -EINVAL;
422 	}
423 
424 	k_mutex_lock(&lock, K_FOREVER);
425 
426 	if (service->data->sock_fd >= 0) {
427 		ret = -EALREADY;
428 		goto end;
429 	}
430 
431 	/* set the default address (in6addr_any / INADDR_ANY are all 0) */
432 	addr_storage = (struct sockaddr_storage){0};
433 	if (IS_ENABLED(CONFIG_NET_IPV6) && service->host != NULL &&
434 	    zsock_inet_pton(AF_INET6, service->host, &addr_ptrs.addr6->sin6_addr) == 1) {
435 		/* if a literal IPv6 address is provided as the host, use IPv6 */
436 		af = AF_INET6;
437 		len = sizeof(struct sockaddr_in6);
438 
439 		addr_ptrs.addr6->sin6_family = AF_INET6;
440 		addr_ptrs.addr6->sin6_port = htons(*service->port);
441 	} else if (IS_ENABLED(CONFIG_NET_IPV4) && service->host != NULL &&
442 		   zsock_inet_pton(AF_INET, service->host, &addr_ptrs.addr4->sin_addr) == 1) {
443 		/* if a literal IPv4 address is provided as the host, use IPv4 */
444 		af = AF_INET;
445 		len = sizeof(struct sockaddr_in);
446 
447 		addr_ptrs.addr4->sin_family = AF_INET;
448 		addr_ptrs.addr4->sin_port = htons(*service->port);
449 	} else if (IS_ENABLED(CONFIG_NET_IPV6)) {
450 		/* prefer IPv6 if both IPv6 and IPv4 are supported */
451 		af = AF_INET6;
452 		len = sizeof(struct sockaddr_in6);
453 
454 		addr_ptrs.addr6->sin6_family = AF_INET6;
455 		addr_ptrs.addr6->sin6_port = htons(*service->port);
456 	} else if (IS_ENABLED(CONFIG_NET_IPV4)) {
457 		af = AF_INET;
458 		len = sizeof(struct sockaddr_in);
459 
460 		addr_ptrs.addr4->sin_family = AF_INET;
461 		addr_ptrs.addr4->sin_port = htons(*service->port);
462 	} else {
463 		ret = -ENOTSUP;
464 		goto end;
465 	}
466 
467 #if defined(CONFIG_NET_SOCKETS_ENABLE_DTLS)
468 	if (service->sec_tag_list != NULL) {
469 		proto = IPPROTO_DTLS_1_2;
470 	}
471 #endif
472 
473 	service->data->sock_fd = zsock_socket(af, SOCK_DGRAM, proto);
474 	if (service->data->sock_fd < 0) {
475 		ret = -errno;
476 		goto end;
477 	}
478 
479 #if defined(CONFIG_NET_SOCKETS_ENABLE_DTLS)
480 	if (service->sec_tag_list != NULL) {
481 		int role = TLS_DTLS_ROLE_SERVER;
482 
483 		ret = zsock_setsockopt(service->data->sock_fd, SOL_TLS, TLS_SEC_TAG_LIST,
484 				       service->sec_tag_list, service->sec_tag_list_size);
485 		if (ret < 0) {
486 			ret = -errno;
487 			goto close;
488 		}
489 
490 		ret = zsock_setsockopt(service->data->sock_fd, SOL_TLS, TLS_DTLS_ROLE,
491 				       &role, sizeof(role));
492 		if (ret < 0) {
493 			ret = -errno;
494 			goto close;
495 		}
496 	}
497 #endif
498 
499 	ret = zsock_fcntl(service->data->sock_fd, ZVFS_F_SETFL, ZVFS_O_NONBLOCK);
500 	if (ret < 0) {
501 		ret = -errno;
502 		goto close;
503 	}
504 
505 	ret = zsock_bind(service->data->sock_fd, addr_ptrs.addr, len);
506 	if (ret < 0) {
507 		ret = -errno;
508 		goto close;
509 	}
510 
511 	if (*service->port == 0) {
512 		/* ephemeral port - read back the port number */
513 		len = sizeof(addr_storage);
514 		ret = zsock_getsockname(service->data->sock_fd, addr_ptrs.addr, &len);
515 		if (ret < 0) {
516 			goto close;
517 		}
518 
519 		if (af == AF_INET6) {
520 			*service->port = addr_ptrs.addr6->sin6_port;
521 		} else {
522 			*service->port = addr_ptrs.addr4->sin_port;
523 		}
524 	}
525 
526 end:
527 	k_mutex_unlock(&lock);
528 
529 	coap_server_update_services();
530 
531 	coap_service_raise_event(service, NET_EVENT_COAP_SERVICE_STARTED);
532 
533 	return ret;
534 
535 close:
536 	(void)zsock_close(service->data->sock_fd);
537 	service->data->sock_fd = -1;
538 
539 	k_mutex_unlock(&lock);
540 
541 	return ret;
542 }
543 
coap_service_stop(const struct coap_service * service)544 int coap_service_stop(const struct coap_service *service)
545 {
546 	int ret;
547 
548 	if (!coap_service_in_section(service)) {
549 		__ASSERT_NO_MSG(false);
550 		return -EINVAL;
551 	}
552 
553 	k_mutex_lock(&lock, K_FOREVER);
554 
555 	if (service->data->sock_fd < 0) {
556 		k_mutex_unlock(&lock);
557 		return -EALREADY;
558 	}
559 
560 	/* Closing a socket will trigger a poll event */
561 	ret = zsock_close(service->data->sock_fd);
562 	service->data->sock_fd = -1;
563 
564 	k_mutex_unlock(&lock);
565 
566 	coap_service_raise_event(service, NET_EVENT_COAP_SERVICE_STOPPED);
567 
568 	return ret;
569 }
570 
coap_service_is_running(const struct coap_service * service)571 int coap_service_is_running(const struct coap_service *service)
572 {
573 	int ret;
574 
575 	if (!coap_service_in_section(service)) {
576 		__ASSERT_NO_MSG(false);
577 		return -EINVAL;
578 	}
579 
580 	k_mutex_lock(&lock, K_FOREVER);
581 
582 	ret = (service->data->sock_fd < 0) ? 0 : 1;
583 
584 	k_mutex_unlock(&lock);
585 
586 	return ret;
587 }
588 
coap_service_send(const struct coap_service * service,const struct coap_packet * cpkt,const struct sockaddr * addr,socklen_t addr_len,const struct coap_transmission_parameters * params)589 int coap_service_send(const struct coap_service *service, const struct coap_packet *cpkt,
590 		      const struct sockaddr *addr, socklen_t addr_len,
591 		      const struct coap_transmission_parameters *params)
592 {
593 	int ret;
594 
595 	if (!coap_service_in_section(service)) {
596 		__ASSERT_NO_MSG(false);
597 		return -EINVAL;
598 	}
599 
600 	(void)k_mutex_lock(&lock, K_FOREVER);
601 
602 	if (service->data->sock_fd < 0) {
603 		(void)k_mutex_unlock(&lock);
604 		return -EBADF;
605 	}
606 
607 	/*
608 	 * Check if we should start with retransmits, if creating a pending message fails we still
609 	 * try to send.
610 	 */
611 	if (coap_header_get_type(cpkt) == COAP_TYPE_CON) {
612 		struct coap_pending *pending = coap_pending_next_unused(service->data->pending,
613 									MAX_PENDINGS);
614 
615 		if (pending == NULL) {
616 			LOG_WRN("No pending message available for %s", service->name);
617 			goto send;
618 		}
619 
620 		ret = coap_pending_init(pending, cpkt, addr, params);
621 		if (ret < 0) {
622 			LOG_WRN("Failed to init pending message for %s (%d)", service->name, ret);
623 			goto send;
624 		}
625 
626 		/* Replace tracked data with our allocated copy */
627 		pending->data = coap_server_alloc(pending->len);
628 		if (pending->data == NULL) {
629 			LOG_WRN("Failed to allocate pending message data for %s", service->name);
630 			coap_pending_clear(pending);
631 			goto send;
632 		}
633 		memcpy(pending->data, cpkt->data, pending->len);
634 
635 		coap_pending_cycle(pending);
636 
637 		/* Trigger event in receive loop to schedule retransmit */
638 		coap_server_update_services();
639 	}
640 
641 send:
642 	(void)k_mutex_unlock(&lock);
643 
644 	ret = zsock_sendto(service->data->sock_fd, cpkt->data, cpkt->offset, 0, addr, addr_len);
645 	if (ret < 0) {
646 		LOG_ERR("Failed to send CoAP message (%d)", ret);
647 		return ret;
648 	}
649 	__ASSERT_NO_MSG(ret == cpkt->offset);
650 
651 	return 0;
652 }
653 
coap_resource_send(const struct coap_resource * resource,const struct coap_packet * cpkt,const struct sockaddr * addr,socklen_t addr_len,const struct coap_transmission_parameters * params)654 int coap_resource_send(const struct coap_resource *resource, const struct coap_packet *cpkt,
655 		       const struct sockaddr *addr, socklen_t addr_len,
656 		       const struct coap_transmission_parameters *params)
657 {
658 	/* Find owning service */
659 	COAP_SERVICE_FOREACH(svc) {
660 		if (COAP_SERVICE_HAS_RESOURCE(svc, resource)) {
661 			return coap_service_send(svc, cpkt, addr, addr_len, params);
662 		}
663 	}
664 
665 	return -ENOENT;
666 }
667 
coap_resource_parse_observe(struct coap_resource * resource,const struct coap_packet * request,const struct sockaddr * addr)668 int coap_resource_parse_observe(struct coap_resource *resource, const struct coap_packet *request,
669 				const struct sockaddr *addr)
670 {
671 	const struct coap_service *service = NULL;
672 	int ret;
673 	uint8_t token[COAP_TOKEN_MAX_LEN];
674 	uint8_t tkl;
675 
676 	if (!coap_packet_is_request(request)) {
677 		return -EINVAL;
678 	}
679 
680 	ret = coap_get_option_int(request, COAP_OPTION_OBSERVE);
681 	if (ret < 0) {
682 		return ret;
683 	}
684 
685 	/* Find owning service */
686 	COAP_SERVICE_FOREACH(svc) {
687 		if (COAP_SERVICE_HAS_RESOURCE(svc, resource)) {
688 			service = svc;
689 			break;
690 		}
691 	}
692 
693 	if (service == NULL) {
694 		return -ENOENT;
695 	}
696 
697 	tkl = coap_header_get_token(request, token);
698 	if (tkl == 0) {
699 		return -EINVAL;
700 	}
701 
702 	(void)k_mutex_lock(&lock, K_FOREVER);
703 
704 	if (ret == 0) {
705 		struct coap_observer *observer;
706 
707 		/* RFC7641 section 4.1 - Check if the current observer already exists */
708 		observer = coap_find_observer(service->data->observers, MAX_OBSERVERS, addr, token,
709 					      tkl);
710 		if (observer != NULL) {
711 			/* Client refresh */
712 			goto unlock;
713 		}
714 
715 		/* New client */
716 		observer = coap_observer_next_unused(service->data->observers, MAX_OBSERVERS);
717 		if (observer == NULL) {
718 			ret = -ENOMEM;
719 			goto unlock;
720 		}
721 
722 		coap_observer_init(observer, request, addr);
723 		coap_register_observer(resource, observer);
724 	} else if (ret == 1) {
725 		ret = coap_service_remove_observer(service, resource, addr, token, tkl);
726 		if (ret < 0) {
727 			LOG_WRN("Failed to remove observer (%d)", ret);
728 			goto unlock;
729 		}
730 
731 		if (ret == 0) {
732 			/* Observer not found */
733 			ret = -ENOENT;
734 		}
735 	}
736 
737 unlock:
738 	(void)k_mutex_unlock(&lock);
739 
740 	return ret;
741 }
742 
coap_resource_remove_observer(struct coap_resource * resource,const struct sockaddr * addr,const uint8_t * token,uint8_t token_len)743 static int coap_resource_remove_observer(struct coap_resource *resource,
744 					 const struct sockaddr *addr,
745 					 const uint8_t *token, uint8_t token_len)
746 {
747 	const struct coap_service *service = NULL;
748 	int ret;
749 
750 	/* Find owning service */
751 	COAP_SERVICE_FOREACH(svc) {
752 		if (COAP_SERVICE_HAS_RESOURCE(svc, resource)) {
753 			service = svc;
754 			break;
755 		}
756 	}
757 
758 	if (service == NULL) {
759 		return -ENOENT;
760 	}
761 
762 	(void)k_mutex_lock(&lock, K_FOREVER);
763 	ret = coap_service_remove_observer(service, resource, addr, token, token_len);
764 	(void)k_mutex_unlock(&lock);
765 
766 	if (ret == 1) {
767 		/* An observer was found and removed */
768 		return 0;
769 	} else if (ret == 0) {
770 		/* No matching observer found */
771 		return -ENOENT;
772 	}
773 
774 	/* An error occurred */
775 	return ret;
776 }
777 
coap_resource_remove_observer_by_addr(struct coap_resource * resource,const struct sockaddr * addr)778 int coap_resource_remove_observer_by_addr(struct coap_resource *resource,
779 					  const struct sockaddr *addr)
780 {
781 	return coap_resource_remove_observer(resource, addr, NULL, 0);
782 }
783 
coap_resource_remove_observer_by_token(struct coap_resource * resource,const uint8_t * token,uint8_t token_len)784 int coap_resource_remove_observer_by_token(struct coap_resource *resource,
785 					   const uint8_t *token, uint8_t token_len)
786 {
787 	return coap_resource_remove_observer(resource, NULL, token, token_len);
788 }
789 
coap_server_thread(void * p1,void * p2,void * p3)790 static void coap_server_thread(void *p1, void *p2, void *p3)
791 {
792 	struct zsock_pollfd sock_fds[MAX_POLL_FD];
793 	int sock_nfds;
794 	int ret;
795 
796 	ARG_UNUSED(p1);
797 	ARG_UNUSED(p2);
798 	ARG_UNUSED(p3);
799 
800 	control_sock = zvfs_eventfd(0, ZVFS_EFD_NONBLOCK);
801 	if (control_sock < 0) {
802 		LOG_ERR("Failed to create event fd (%d)", -errno);
803 		return;
804 	}
805 
806 	COAP_SERVICE_FOREACH(svc) {
807 		if (svc->flags & COAP_SERVICE_AUTOSTART) {
808 			ret = coap_service_start(svc);
809 			if (ret < 0) {
810 				LOG_ERR("Failed to autostart service %s (%d)", svc->name, ret);
811 			}
812 		}
813 	}
814 
815 	while (true) {
816 		sock_nfds = 0;
817 		COAP_SERVICE_FOREACH(svc) {
818 			if (svc->data->sock_fd < 0) {
819 				continue;
820 			}
821 			if (sock_nfds >= MAX_POLL_FD) {
822 				LOG_ERR("Maximum active CoAP services reached (%d), "
823 					"increase CONFIG_ZVFS_POLL_MAX to support more.",
824 					MAX_POLL_FD);
825 				break;
826 			}
827 
828 			sock_fds[sock_nfds].fd = svc->data->sock_fd;
829 			sock_fds[sock_nfds].events = ZSOCK_POLLIN;
830 			sock_fds[sock_nfds].revents = 0;
831 			sock_nfds++;
832 		}
833 
834 		/* Add event FD to allow wake up */
835 		if (sock_nfds < MAX_POLL_FD) {
836 			sock_fds[sock_nfds].fd = control_sock;
837 			sock_fds[sock_nfds].events = ZSOCK_POLLIN;
838 			sock_fds[sock_nfds].revents = 0;
839 			sock_nfds++;
840 		}
841 
842 		__ASSERT_NO_MSG(sock_nfds > 0);
843 
844 		ret = zsock_poll(sock_fds, sock_nfds, coap_server_poll_timeout());
845 		if (ret < 0) {
846 			LOG_ERR("Poll error (%d)", -errno);
847 			k_msleep(10);
848 		}
849 
850 		for (int i = 0; i < sock_nfds; ++i) {
851 			/* Check the wake up event */
852 			if (sock_fds[i].fd == control_sock &&
853 			    sock_fds[i].revents & ZSOCK_POLLIN) {
854 				zvfs_eventfd_t tmp;
855 
856 				zvfs_eventfd_read(sock_fds[i].fd, &tmp);
857 				continue;
858 			}
859 
860 			/* Check if socket can receive/was closed first */
861 			if (sock_fds[i].revents & ZSOCK_POLLIN) {
862 				coap_server_process(sock_fds[i].fd);
863 				continue;
864 			}
865 
866 			if (sock_fds[i].revents & ZSOCK_POLLERR) {
867 				LOG_ERR("Poll error on %d", sock_fds[i].fd);
868 			}
869 			if (sock_fds[i].revents & ZSOCK_POLLHUP) {
870 				LOG_DBG("Poll hup on %d", sock_fds[i].fd);
871 			}
872 			if (sock_fds[i].revents & ZSOCK_POLLNVAL) {
873 				LOG_ERR("Poll invalid on %d", sock_fds[i].fd);
874 			}
875 		}
876 
877 		/* Process retransmits */
878 		coap_server_retransmit();
879 	}
880 }
881 
882 K_THREAD_DEFINE(coap_server_id, CONFIG_COAP_SERVER_STACK_SIZE,
883 		coap_server_thread, NULL, NULL, NULL,
884 		THREAD_PRIORITY, 0, 0);
885