1 /*
2  * Copyright (c) 2019 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 #define LOG_LEVEL LOG_LEVEL_DBG
9 LOG_MODULE_REGISTER(net_dumb_http_srv_mt_sample);
10 
11 #include <zephyr/kernel.h>
12 #include <errno.h>
13 #include <zephyr/net/net_ip.h>
14 #include <zephyr/net/socket.h>
15 #include <zephyr/net/tls_credentials.h>
16 
17 #include <zephyr/net/net_mgmt.h>
18 #include <zephyr/net/net_event.h>
19 #include <zephyr/net/conn_mgr_monitor.h>
20 
21 #define MY_PORT 8080
22 
23 /* If accept returns an error, then we are probably running
24  * out of resource. Sleep a small amount of time in order the
25  * system to cool down.
26  */
27 #define ACCEPT_ERROR_WAIT 100 /* in ms */
28 
29 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
30 #define STACK_SIZE 4096
31 
32 #define SERVER_CERTIFICATE_TAG 1
33 
34 static const unsigned char server_certificate[] = {
35 #include "mt-http-server-cert.der.inc"
36 };
37 
38 /* This is the private key in pkcs#8 format. */
39 static const unsigned char private_key[] = {
40 #include "mt-http-server-key.der.inc"
41 };
42 #else
43 #define STACK_SIZE 1024
44 #endif
45 #if defined(CONFIG_NET_TC_THREAD_COOPERATIVE)
46 #define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1)
47 #else
48 #define THREAD_PRIORITY K_PRIO_PREEMPT(8)
49 #endif
50 
51 static const char content[] = {
52 #if defined(CONFIG_NET_SAMPLE_SERVE_LARGE_FILE)
53     #include "response_100k.html.bin.inc"
54 #else
55     #include "response_big.html.bin.inc"
56 #endif
57 };
58 
59 #define MAX_CLIENT_QUEUE CONFIG_NET_SAMPLE_NUM_HANDLERS
60 
61 #if defined(CONFIG_NET_IPV4)
62 K_THREAD_STACK_ARRAY_DEFINE(tcp4_handler_stack, CONFIG_NET_SAMPLE_NUM_HANDLERS,
63 			    STACK_SIZE);
64 static struct k_thread tcp4_handler_thread[CONFIG_NET_SAMPLE_NUM_HANDLERS];
65 static k_tid_t tcp4_handler_tid[CONFIG_NET_SAMPLE_NUM_HANDLERS];
66 #endif
67 
68 #if defined(CONFIG_NET_IPV6)
69 K_THREAD_STACK_ARRAY_DEFINE(tcp6_handler_stack, CONFIG_NET_SAMPLE_NUM_HANDLERS,
70 			    STACK_SIZE);
71 static struct k_thread tcp6_handler_thread[CONFIG_NET_SAMPLE_NUM_HANDLERS];
72 static k_tid_t tcp6_handler_tid[CONFIG_NET_SAMPLE_NUM_HANDLERS];
73 #endif
74 
75 static struct net_mgmt_event_callback mgmt_cb;
76 static bool connected;
77 K_SEM_DEFINE(run_app, 0, 1);
78 K_SEM_DEFINE(quit_lock, 0, 1);
79 static bool running_status;
80 static bool want_to_quit;
81 static int tcp4_listen_sock;
82 static int tcp4_accepted[CONFIG_NET_SAMPLE_NUM_HANDLERS];
83 static int tcp6_listen_sock;
84 static int tcp6_accepted[CONFIG_NET_SAMPLE_NUM_HANDLERS];
85 
86 static void process_tcp4(void);
87 static void process_tcp6(void);
88 
89 K_THREAD_DEFINE(tcp4_thread_id, STACK_SIZE,
90 		process_tcp4, NULL, NULL, NULL,
91 		THREAD_PRIORITY, 0, -1);
92 
93 K_THREAD_DEFINE(tcp6_thread_id, STACK_SIZE,
94 		process_tcp6, NULL, NULL, NULL,
95 		THREAD_PRIORITY, 0, -1);
96 
97 #define EVENT_MASK (NET_EVENT_L4_CONNECTED | \
98 		    NET_EVENT_L4_DISCONNECTED)
99 
event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)100 static void event_handler(struct net_mgmt_event_callback *cb,
101 			  uint32_t mgmt_event, struct net_if *iface)
102 {
103 	if ((mgmt_event & EVENT_MASK) != mgmt_event) {
104 		return;
105 	}
106 
107 	if (want_to_quit) {
108 		k_sem_give(&run_app);
109 		want_to_quit = false;
110 	}
111 
112 	if (mgmt_event == NET_EVENT_L4_CONNECTED) {
113 		LOG_INF("Network connected");
114 
115 		connected = true;
116 		k_sem_give(&run_app);
117 
118 		return;
119 	}
120 
121 	if (mgmt_event == NET_EVENT_L4_DISCONNECTED) {
122 		if (connected == false) {
123 			LOG_INF("Waiting network to be connected");
124 		} else {
125 			LOG_INF("Network disconnected");
126 			connected = false;
127 		}
128 
129 		k_sem_reset(&run_app);
130 
131 		return;
132 	}
133 }
134 
sendall(int sock,const void * buf,size_t len)135 static ssize_t sendall(int sock, const void *buf, size_t len)
136 {
137 	while (len) {
138 		ssize_t out_len = send(sock, buf, len, 0);
139 
140 		if (out_len < 0) {
141 			return out_len;
142 		}
143 
144 		buf = (const char *)buf + out_len;
145 		len -= out_len;
146 	}
147 
148 	return 0;
149 }
150 
setup(int * sock,struct sockaddr * bind_addr,socklen_t bind_addrlen)151 static int setup(int *sock, struct sockaddr *bind_addr,
152 		 socklen_t bind_addrlen)
153 {
154 	int ret;
155 
156 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
157 	*sock = socket(bind_addr->sa_family, SOCK_STREAM, IPPROTO_TLS_1_2);
158 #else
159 	*sock = socket(bind_addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
160 #endif
161 	if (*sock < 0) {
162 		LOG_ERR("Failed to create TCP socket: %d", errno);
163 		return -errno;
164 	}
165 
166 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
167 	sec_tag_t sec_tag_list[] = {
168 		SERVER_CERTIFICATE_TAG,
169 	};
170 
171 	ret = setsockopt(*sock, SOL_TLS, TLS_SEC_TAG_LIST,
172 			 sec_tag_list, sizeof(sec_tag_list));
173 	if (ret < 0) {
174 		LOG_ERR("Failed to set TCP secure option %d", errno);
175 		ret = -errno;
176 	}
177 #endif
178 
179 	ret = bind(*sock, bind_addr, bind_addrlen);
180 	if (ret < 0) {
181 		LOG_ERR("Failed to bind TCP socket %d", errno);
182 		return -errno;
183 	}
184 
185 	ret = listen(*sock, MAX_CLIENT_QUEUE);
186 	if (ret < 0) {
187 		LOG_ERR("Failed to listen on TCP socket %d", errno);
188 		ret = -errno;
189 	}
190 
191 	return ret;
192 }
193 
client_conn_handler(void * ptr1,void * ptr2,void * ptr3)194 static void client_conn_handler(void *ptr1, void *ptr2, void *ptr3)
195 {
196 	ARG_UNUSED(ptr1);
197 	int *sock = ptr2;
198 	k_tid_t *in_use = ptr3;
199 	int client;
200 	int received;
201 	int ret;
202 	char buf[100];
203 
204 	client = *sock;
205 
206 	/* Discard HTTP request (or otherwise client will get
207 	 * connection reset error).
208 	 */
209 	do {
210 		received = recv(client, buf, sizeof(buf), 0);
211 		if (received == 0) {
212 			/* Connection closed */
213 			LOG_DBG("[%d] Connection closed by peer", client);
214 			break;
215 		} else if (received < 0) {
216 			/* Socket error */
217 			ret = -errno;
218 			LOG_ERR("[%d] Connection error %d", client, ret);
219 			break;
220 		}
221 
222 		/* Note that something like this strstr() check should *NOT*
223 		 * be used in production code. This is done like this just
224 		 * for this sample application to keep things simple.
225 		 *
226 		 * We are assuming here that the full HTTP request is received
227 		 * in one TCP segment which in real life might not.
228 		 */
229 		if (strstr(buf, "\r\n\r\n")) {
230 			break;
231 		}
232 	} while (true);
233 
234 	/* We received status from the client */
235 	if (strstr(buf, "\r\n\r\nOK")) {
236 		running_status = true;
237 		want_to_quit = true;
238 		k_sem_give(&quit_lock);
239 	} else if (strstr(buf, "\r\n\r\nFAIL")) {
240 		running_status = false;
241 		want_to_quit = true;
242 		k_sem_give(&quit_lock);
243 	} else {
244 		(void)sendall(client, content, sizeof(content));
245 	}
246 
247 	(void)close(client);
248 
249 	*sock = -1;
250 	*in_use = NULL;
251 }
252 
get_free_slot(int * accepted)253 static int get_free_slot(int *accepted)
254 {
255 	int i;
256 
257 	for (i = 0; i < CONFIG_NET_SAMPLE_NUM_HANDLERS; i++) {
258 		if (accepted[i] < 0) {
259 			return i;
260 		}
261 	}
262 
263 	return -1;
264 }
265 
process_tcp(int * sock,int * accepted)266 static int process_tcp(int *sock, int *accepted)
267 {
268 	static int counter;
269 	int client;
270 	int slot;
271 	struct sockaddr_in6 client_addr;
272 	socklen_t client_addr_len = sizeof(client_addr);
273 
274 	client = accept(*sock, (struct sockaddr *)&client_addr,
275 			&client_addr_len);
276 	if (client < 0) {
277 		LOG_DBG("Error in accept %d, ignored", -errno);
278 		k_msleep(ACCEPT_ERROR_WAIT);
279 		return 0;
280 	}
281 
282 	slot = get_free_slot(accepted);
283 	if (slot < 0 || slot >= CONFIG_NET_SAMPLE_NUM_HANDLERS) {
284 		LOG_ERR("Cannot accept more connections");
285 		close(client);
286 		return 0;
287 	}
288 
289 	accepted[slot] = client;
290 
291 #if defined(CONFIG_NET_IPV6)
292 	if (client_addr.sin6_family == AF_INET6) {
293 		tcp6_handler_tid[slot] = k_thread_create(
294 			&tcp6_handler_thread[slot],
295 			tcp6_handler_stack[slot],
296 			K_THREAD_STACK_SIZEOF(tcp6_handler_stack[slot]),
297 			client_conn_handler,
298 			INT_TO_POINTER(slot),
299 			&accepted[slot],
300 			&tcp6_handler_tid[slot],
301 			THREAD_PRIORITY,
302 			0, K_NO_WAIT);
303 	}
304 #endif
305 
306 #if defined(CONFIG_NET_IPV4)
307 	if (client_addr.sin6_family == AF_INET) {
308 		tcp4_handler_tid[slot] = k_thread_create(
309 			&tcp4_handler_thread[slot],
310 			tcp4_handler_stack[slot],
311 			K_THREAD_STACK_SIZEOF(tcp4_handler_stack[slot]),
312 			client_conn_handler,
313 			INT_TO_POINTER(slot),
314 			&accepted[slot],
315 			&tcp4_handler_tid[slot],
316 			THREAD_PRIORITY,
317 			0, K_NO_WAIT);
318 	}
319 #endif
320 
321 	if (LOG_LEVEL >= LOG_LEVEL_DBG) {
322 		char addr_str[INET6_ADDRSTRLEN];
323 
324 		net_addr_ntop(client_addr.sin6_family,
325 			      &client_addr.sin6_addr,
326 			      addr_str, sizeof(addr_str));
327 
328 		LOG_DBG("[%d] Connection #%d from %s",
329 			client, ++counter,
330 			addr_str);
331 	}
332 
333 	return 0;
334 }
335 
process_tcp4(void)336 static void process_tcp4(void)
337 {
338 	struct sockaddr_in addr4;
339 	int ret;
340 
341 	(void)memset(&addr4, 0, sizeof(addr4));
342 	addr4.sin_family = AF_INET;
343 	addr4.sin_port = htons(MY_PORT);
344 
345 	ret = setup(&tcp4_listen_sock, (struct sockaddr *)&addr4,
346 		    sizeof(addr4));
347 	if (ret < 0) {
348 		return;
349 	}
350 
351 	LOG_DBG("Waiting for IPv4 HTTP connections on port %d, sock %d",
352 		MY_PORT, tcp4_listen_sock);
353 
354 	while (ret == 0 || !want_to_quit) {
355 		ret = process_tcp(&tcp4_listen_sock, tcp4_accepted);
356 		if (ret < 0) {
357 			return;
358 		}
359 	}
360 }
361 
process_tcp6(void)362 static void process_tcp6(void)
363 {
364 	struct sockaddr_in6 addr6;
365 	int ret;
366 
367 	(void)memset(&addr6, 0, sizeof(addr6));
368 	addr6.sin6_family = AF_INET6;
369 	addr6.sin6_port = htons(MY_PORT);
370 
371 	ret = setup(&tcp6_listen_sock, (struct sockaddr *)&addr6,
372 		    sizeof(addr6));
373 	if (ret < 0) {
374 		return;
375 	}
376 
377 	LOG_DBG("Waiting for IPv6 HTTP connections on port %d, sock %d",
378 		MY_PORT, tcp6_listen_sock);
379 
380 	while (ret == 0 || !want_to_quit) {
381 		ret = process_tcp(&tcp6_listen_sock, tcp6_accepted);
382 		if (ret != 0) {
383 			return;
384 		}
385 	}
386 }
387 
start_listener(void)388 void start_listener(void)
389 {
390 	int i;
391 
392 	for (i = 0; i < CONFIG_NET_SAMPLE_NUM_HANDLERS; i++) {
393 #if defined(CONFIG_NET_IPV4)
394 		tcp4_accepted[i] = -1;
395 		tcp4_listen_sock = -1;
396 #endif
397 #if defined(CONFIG_NET_IPV6)
398 		tcp6_accepted[i] = -1;
399 		tcp6_listen_sock = -1;
400 #endif
401 	}
402 
403 	if (IS_ENABLED(CONFIG_NET_IPV6)) {
404 		k_thread_start(tcp6_thread_id);
405 	}
406 
407 	if (IS_ENABLED(CONFIG_NET_IPV4)) {
408 		k_thread_start(tcp4_thread_id);
409 	}
410 }
411 
main(void)412 int main(void)
413 {
414 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
415 	int err = tls_credential_add(SERVER_CERTIFICATE_TAG,
416 				     TLS_CREDENTIAL_SERVER_CERTIFICATE,
417 				     server_certificate,
418 				     sizeof(server_certificate));
419 	if (err < 0) {
420 		LOG_ERR("Failed to register public certificate: %d", err);
421 	}
422 
423 	err = tls_credential_add(SERVER_CERTIFICATE_TAG,
424 				 TLS_CREDENTIAL_PRIVATE_KEY,
425 				 private_key, sizeof(private_key));
426 	if (err < 0) {
427 		LOG_ERR("Failed to register private key: %d", err);
428 	}
429 #endif
430 
431 	if (IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) {
432 		net_mgmt_init_event_callback(&mgmt_cb,
433 					     event_handler, EVENT_MASK);
434 		net_mgmt_add_event_callback(&mgmt_cb);
435 
436 		conn_mgr_mon_resend_status();
437 	}
438 
439 	if (!IS_ENABLED(CONFIG_NET_CONNECTION_MANAGER)) {
440 		/* If the config library has not been configured to start the
441 		 * app only after we have a connection, then we can start
442 		 * it right away.
443 		 */
444 		k_sem_give(&run_app);
445 	}
446 
447 	/* Wait for the connection. */
448 	k_sem_take(&run_app, K_FOREVER);
449 
450 	start_listener();
451 
452 	k_sem_take(&quit_lock, K_FOREVER);
453 
454 	if (running_status) {
455 		/* No issues, let the testing system know about this */
456 		exit(0);
457 	} else {
458 		exit(1);
459 	}
460 	return 0;
461 }
462