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