1 /*
2  * Copyright (c) 2017 Linaro Limited
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <errno.h>
10 
11 #if !defined(__ZEPHYR__) || defined(CONFIG_POSIX_API)
12 
13 #include <netinet/in.h>
14 #include <sys/socket.h>
15 #include <arpa/inet.h>
16 #include <unistd.h>
17 
18 #else
19 
20 #include <zephyr/net/socket.h>
21 #include <zephyr/kernel.h>
22 
23 #include <zephyr/net/net_pkt.h>
24 
25 #endif
26 
27 #define BIND_PORT 8080
28 
29 #ifndef USE_BIG_PAYLOAD
30 #define USE_BIG_PAYLOAD 1
31 #endif
32 
33 #define CHECK(r) { if (r == -1) { printf("Error: " #r "\n"); exit(1); } }
34 
35 static const char content[] = {
36 #if USE_BIG_PAYLOAD
37     #include "response_big.html.bin.inc"
38 #else
39     #include "response_small.html.bin.inc"
40 #endif
41 };
42 
43 /* If accept returns an error, then we are probably running
44  * out of resource. Sleep a small amount of time in order the
45  * system to cool down.
46  */
47 #define ACCEPT_ERROR_WAIT 100 /* in ms */
48 
sleep_after_error(unsigned int amount)49 static void sleep_after_error(unsigned int amount)
50 {
51 #if defined(__ZEPHYR__)
52 	k_msleep(amount);
53 #else
54 	usleep(amount * 1000U);
55 #endif
56 }
57 
main(void)58 int main(void)
59 {
60 	int serv;
61 	struct sockaddr_in bind_addr;
62 	static int counter;
63 	int ret;
64 
65 	serv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
66 	CHECK(serv);
67 
68 	bind_addr.sin_family = AF_INET;
69 	bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
70 	bind_addr.sin_port = htons(BIND_PORT);
71 	CHECK(bind(serv, (struct sockaddr *)&bind_addr, sizeof(bind_addr)));
72 
73 	CHECK(listen(serv, 5));
74 
75 	printf("Single-threaded dumb HTTP server waits for a connection on "
76 	       "port %d...\n", BIND_PORT);
77 
78 	while (1) {
79 		struct sockaddr_in client_addr;
80 		socklen_t client_addr_len = sizeof(client_addr);
81 		char addr_str[32];
82 		int req_state = 0;
83 		const char *data;
84 		size_t len;
85 
86 		int client = accept(serv, (struct sockaddr *)&client_addr,
87 				    &client_addr_len);
88 		if (client < 0) {
89 			printf("Error in accept: %d - continuing\n", errno);
90 			sleep_after_error(ACCEPT_ERROR_WAIT);
91 			continue;
92 		}
93 
94 		inet_ntop(client_addr.sin_family, &client_addr.sin_addr,
95 			  addr_str, sizeof(addr_str));
96 		printf("Connection #%d from %s\n", counter++, addr_str);
97 
98 		/* Discard HTTP request (or otherwise client will get
99 		 * connection reset error).
100 		 */
101 		while (1) {
102 			ssize_t r;
103 			char c;
104 
105 			r = recv(client, &c, 1, 0);
106 			if (r == 0) {
107 				goto close_client;
108 			}
109 
110 			if (r < 0) {
111 				if (errno == EAGAIN || errno == EINTR) {
112 					continue;
113 				}
114 
115 				printf("Got error %d when receiving from "
116 				       "socket\n", errno);
117 				goto close_client;
118 			}
119 			if (req_state == 0 && c == '\r') {
120 				req_state++;
121 			} else if (req_state == 1 && c == '\n') {
122 				req_state++;
123 			} else if (req_state == 2 && c == '\r') {
124 				req_state++;
125 			} else if (req_state == 3 && c == '\n') {
126 				break;
127 			} else {
128 				req_state = 0;
129 			}
130 		}
131 
132 		data = content;
133 		len = sizeof(content);
134 		while (len) {
135 			int sent_len = send(client, data, len, 0);
136 
137 			if (sent_len == -1) {
138 				printf("Error sending data to peer, errno: %d\n", errno);
139 				break;
140 			}
141 			data += sent_len;
142 			len -= sent_len;
143 		}
144 
145 close_client:
146 		ret = close(client);
147 		if (ret == 0) {
148 			printf("Connection from %s closed\n", addr_str);
149 		} else {
150 			printf("Got error %d while closing the "
151 			       "socket\n", errno);
152 		}
153 
154 #if defined(__ZEPHYR__) && defined(CONFIG_NET_BUF_POOL_USAGE)
155 		struct k_mem_slab *rx, *tx;
156 		struct net_buf_pool *rx_data, *tx_data;
157 
158 		net_pkt_get_info(&rx, &tx, &rx_data, &tx_data);
159 		printf("rx buf: %d, tx buf: %d\n",
160 		       atomic_get(&rx_data->avail_count), atomic_get(&tx_data->avail_count));
161 #endif
162 
163 	}
164 	return 0;
165 }
166