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