1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * http_server - HTTP server
3e5b75505Sopenharmony_ci * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "includes.h"
10e5b75505Sopenharmony_ci#include <fcntl.h>
11e5b75505Sopenharmony_ci
12e5b75505Sopenharmony_ci#include "common.h"
13e5b75505Sopenharmony_ci#include "eloop.h"
14e5b75505Sopenharmony_ci#include "httpread.h"
15e5b75505Sopenharmony_ci#include "http_server.h"
16e5b75505Sopenharmony_ci
17e5b75505Sopenharmony_ci#define HTTP_SERVER_TIMEOUT 30
18e5b75505Sopenharmony_ci#define HTTP_SERVER_MAX_REQ_LEN 8000
19e5b75505Sopenharmony_ci#define HTTP_SERVER_MAX_CONNECTIONS 10
20e5b75505Sopenharmony_ci
21e5b75505Sopenharmony_cistruct http_request {
22e5b75505Sopenharmony_ci	struct http_request *next;
23e5b75505Sopenharmony_ci	struct http_server *srv;
24e5b75505Sopenharmony_ci	int fd;
25e5b75505Sopenharmony_ci	struct sockaddr_in cli;
26e5b75505Sopenharmony_ci	struct httpread *hread;
27e5b75505Sopenharmony_ci};
28e5b75505Sopenharmony_ci
29e5b75505Sopenharmony_cistruct http_server {
30e5b75505Sopenharmony_ci	void (*cb)(void *ctx, struct http_request *req);
31e5b75505Sopenharmony_ci	void *cb_ctx;
32e5b75505Sopenharmony_ci
33e5b75505Sopenharmony_ci	int fd;
34e5b75505Sopenharmony_ci	int port;
35e5b75505Sopenharmony_ci
36e5b75505Sopenharmony_ci	struct http_request *requests;
37e5b75505Sopenharmony_ci	unsigned int request_count;
38e5b75505Sopenharmony_ci};
39e5b75505Sopenharmony_ci
40e5b75505Sopenharmony_ci
41e5b75505Sopenharmony_cistatic void http_request_cb(struct httpread *handle, void *cookie,
42e5b75505Sopenharmony_ci			    enum httpread_event en)
43e5b75505Sopenharmony_ci{
44e5b75505Sopenharmony_ci	struct http_request *req = cookie;
45e5b75505Sopenharmony_ci	struct http_server *srv = req->srv;
46e5b75505Sopenharmony_ci
47e5b75505Sopenharmony_ci	if (en == HTTPREAD_EVENT_FILE_READY) {
48e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d received",
49e5b75505Sopenharmony_ci			   inet_ntoa(req->cli.sin_addr),
50e5b75505Sopenharmony_ci			   ntohs(req->cli.sin_port));
51e5b75505Sopenharmony_ci		srv->cb(srv->cb_ctx, req);
52e5b75505Sopenharmony_ci		return;
53e5b75505Sopenharmony_ci	}
54e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d could not be received "
55e5b75505Sopenharmony_ci		   "completely", inet_ntoa(req->cli.sin_addr),
56e5b75505Sopenharmony_ci		   ntohs(req->cli.sin_port));
57e5b75505Sopenharmony_ci	http_request_deinit(req);
58e5b75505Sopenharmony_ci}
59e5b75505Sopenharmony_ci
60e5b75505Sopenharmony_ci
61e5b75505Sopenharmony_cistatic struct http_request * http_request_init(struct http_server *srv, int fd,
62e5b75505Sopenharmony_ci					       struct sockaddr_in *cli)
63e5b75505Sopenharmony_ci{
64e5b75505Sopenharmony_ci	struct http_request *req;
65e5b75505Sopenharmony_ci
66e5b75505Sopenharmony_ci	if (srv->request_count >= HTTP_SERVER_MAX_CONNECTIONS) {
67e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "HTTP: Too many concurrent requests");
68e5b75505Sopenharmony_ci		return NULL;
69e5b75505Sopenharmony_ci	}
70e5b75505Sopenharmony_ci
71e5b75505Sopenharmony_ci	req = os_zalloc(sizeof(*req));
72e5b75505Sopenharmony_ci	if (req == NULL)
73e5b75505Sopenharmony_ci		return NULL;
74e5b75505Sopenharmony_ci
75e5b75505Sopenharmony_ci	req->srv = srv;
76e5b75505Sopenharmony_ci	req->fd = fd;
77e5b75505Sopenharmony_ci	req->cli = *cli;
78e5b75505Sopenharmony_ci
79e5b75505Sopenharmony_ci	req->hread = httpread_create(req->fd, http_request_cb, req,
80e5b75505Sopenharmony_ci				     HTTP_SERVER_MAX_REQ_LEN,
81e5b75505Sopenharmony_ci				     HTTP_SERVER_TIMEOUT);
82e5b75505Sopenharmony_ci	if (req->hread == NULL) {
83e5b75505Sopenharmony_ci		http_request_deinit(req);
84e5b75505Sopenharmony_ci		return NULL;
85e5b75505Sopenharmony_ci	}
86e5b75505Sopenharmony_ci
87e5b75505Sopenharmony_ci	return req;
88e5b75505Sopenharmony_ci}
89e5b75505Sopenharmony_ci
90e5b75505Sopenharmony_ci
91e5b75505Sopenharmony_civoid http_request_deinit(struct http_request *req)
92e5b75505Sopenharmony_ci{
93e5b75505Sopenharmony_ci	struct http_request *r, *p;
94e5b75505Sopenharmony_ci	struct http_server *srv;
95e5b75505Sopenharmony_ci
96e5b75505Sopenharmony_ci	if (req == NULL)
97e5b75505Sopenharmony_ci		return;
98e5b75505Sopenharmony_ci
99e5b75505Sopenharmony_ci	srv = req->srv;
100e5b75505Sopenharmony_ci	p = NULL;
101e5b75505Sopenharmony_ci	r = srv->requests;
102e5b75505Sopenharmony_ci	while (r) {
103e5b75505Sopenharmony_ci		if (r == req) {
104e5b75505Sopenharmony_ci			if (p)
105e5b75505Sopenharmony_ci				p->next = r->next;
106e5b75505Sopenharmony_ci			else
107e5b75505Sopenharmony_ci				srv->requests = r->next;
108e5b75505Sopenharmony_ci			srv->request_count--;
109e5b75505Sopenharmony_ci			break;
110e5b75505Sopenharmony_ci		}
111e5b75505Sopenharmony_ci		p = r;
112e5b75505Sopenharmony_ci		r = r->next;
113e5b75505Sopenharmony_ci	}
114e5b75505Sopenharmony_ci
115e5b75505Sopenharmony_ci	httpread_destroy(req->hread);
116e5b75505Sopenharmony_ci	close(req->fd);
117e5b75505Sopenharmony_ci	os_free(req);
118e5b75505Sopenharmony_ci}
119e5b75505Sopenharmony_ci
120e5b75505Sopenharmony_ci
121e5b75505Sopenharmony_cistatic void http_request_free_all(struct http_request *req)
122e5b75505Sopenharmony_ci{
123e5b75505Sopenharmony_ci	struct http_request *prev;
124e5b75505Sopenharmony_ci	while (req) {
125e5b75505Sopenharmony_ci		prev = req;
126e5b75505Sopenharmony_ci		req = req->next;
127e5b75505Sopenharmony_ci		http_request_deinit(prev);
128e5b75505Sopenharmony_ci	}
129e5b75505Sopenharmony_ci}
130e5b75505Sopenharmony_ci
131e5b75505Sopenharmony_ci
132e5b75505Sopenharmony_civoid http_request_send(struct http_request *req, struct wpabuf *resp)
133e5b75505Sopenharmony_ci{
134e5b75505Sopenharmony_ci	int res;
135e5b75505Sopenharmony_ci
136e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "HTTP: Send %lu byte response to %s:%d",
137e5b75505Sopenharmony_ci		   (unsigned long) wpabuf_len(resp),
138e5b75505Sopenharmony_ci		   inet_ntoa(req->cli.sin_addr),
139e5b75505Sopenharmony_ci		   ntohs(req->cli.sin_port));
140e5b75505Sopenharmony_ci
141e5b75505Sopenharmony_ci	res = send(req->fd, wpabuf_head(resp), wpabuf_len(resp), 0);
142e5b75505Sopenharmony_ci	if (res < 0) {
143e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "HTTP: Send failed: %s",
144e5b75505Sopenharmony_ci			   strerror(errno));
145e5b75505Sopenharmony_ci	} else if ((size_t) res < wpabuf_len(resp)) {
146e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "HTTP: Sent only %d of %lu bytes",
147e5b75505Sopenharmony_ci			   res, (unsigned long) wpabuf_len(resp));
148e5b75505Sopenharmony_ci		/* TODO: add eloop handler for sending rest of the data */
149e5b75505Sopenharmony_ci	}
150e5b75505Sopenharmony_ci
151e5b75505Sopenharmony_ci	wpabuf_free(resp);
152e5b75505Sopenharmony_ci}
153e5b75505Sopenharmony_ci
154e5b75505Sopenharmony_ci
155e5b75505Sopenharmony_civoid http_request_send_and_deinit(struct http_request *req,
156e5b75505Sopenharmony_ci				  struct wpabuf *resp)
157e5b75505Sopenharmony_ci{
158e5b75505Sopenharmony_ci	http_request_send(req, resp);
159e5b75505Sopenharmony_ci	http_request_deinit(req);
160e5b75505Sopenharmony_ci}
161e5b75505Sopenharmony_ci
162e5b75505Sopenharmony_ci
163e5b75505Sopenharmony_cienum httpread_hdr_type http_request_get_type(struct http_request *req)
164e5b75505Sopenharmony_ci{
165e5b75505Sopenharmony_ci	return httpread_hdr_type_get(req->hread);
166e5b75505Sopenharmony_ci}
167e5b75505Sopenharmony_ci
168e5b75505Sopenharmony_ci
169e5b75505Sopenharmony_cichar * http_request_get_uri(struct http_request *req)
170e5b75505Sopenharmony_ci{
171e5b75505Sopenharmony_ci	return httpread_uri_get(req->hread);
172e5b75505Sopenharmony_ci}
173e5b75505Sopenharmony_ci
174e5b75505Sopenharmony_ci
175e5b75505Sopenharmony_cichar * http_request_get_hdr(struct http_request *req)
176e5b75505Sopenharmony_ci{
177e5b75505Sopenharmony_ci	return httpread_hdr_get(req->hread);
178e5b75505Sopenharmony_ci}
179e5b75505Sopenharmony_ci
180e5b75505Sopenharmony_ci
181e5b75505Sopenharmony_cichar * http_request_get_data(struct http_request *req)
182e5b75505Sopenharmony_ci{
183e5b75505Sopenharmony_ci	return httpread_data_get(req->hread);
184e5b75505Sopenharmony_ci}
185e5b75505Sopenharmony_ci
186e5b75505Sopenharmony_ci
187e5b75505Sopenharmony_cichar * http_request_get_hdr_line(struct http_request *req, const char *tag)
188e5b75505Sopenharmony_ci{
189e5b75505Sopenharmony_ci	return httpread_hdr_line_get(req->hread, tag);
190e5b75505Sopenharmony_ci}
191e5b75505Sopenharmony_ci
192e5b75505Sopenharmony_ci
193e5b75505Sopenharmony_cistruct sockaddr_in * http_request_get_cli_addr(struct http_request *req)
194e5b75505Sopenharmony_ci{
195e5b75505Sopenharmony_ci	return &req->cli;
196e5b75505Sopenharmony_ci}
197e5b75505Sopenharmony_ci
198e5b75505Sopenharmony_ci
199e5b75505Sopenharmony_cistatic void http_server_cb(int sd, void *eloop_ctx, void *sock_ctx)
200e5b75505Sopenharmony_ci{
201e5b75505Sopenharmony_ci	struct sockaddr_in addr;
202e5b75505Sopenharmony_ci	socklen_t addr_len = sizeof(addr);
203e5b75505Sopenharmony_ci	struct http_server *srv = eloop_ctx;
204e5b75505Sopenharmony_ci	int conn;
205e5b75505Sopenharmony_ci	struct http_request *req;
206e5b75505Sopenharmony_ci
207e5b75505Sopenharmony_ci	conn = accept(srv->fd, (struct sockaddr *) &addr, &addr_len);
208e5b75505Sopenharmony_ci	if (conn < 0) {
209e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "HTTP: Failed to accept new connection: "
210e5b75505Sopenharmony_ci			   "%s", strerror(errno));
211e5b75505Sopenharmony_ci		return;
212e5b75505Sopenharmony_ci	}
213e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "HTTP: Connection from %s:%d",
214e5b75505Sopenharmony_ci		   inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
215e5b75505Sopenharmony_ci
216e5b75505Sopenharmony_ci	req = http_request_init(srv, conn, &addr);
217e5b75505Sopenharmony_ci	if (req == NULL) {
218e5b75505Sopenharmony_ci		close(conn);
219e5b75505Sopenharmony_ci		return;
220e5b75505Sopenharmony_ci	}
221e5b75505Sopenharmony_ci
222e5b75505Sopenharmony_ci	req->next = srv->requests;
223e5b75505Sopenharmony_ci	srv->requests = req;
224e5b75505Sopenharmony_ci	srv->request_count++;
225e5b75505Sopenharmony_ci}
226e5b75505Sopenharmony_ci
227e5b75505Sopenharmony_ci
228e5b75505Sopenharmony_cistruct http_server * http_server_init(struct in_addr *addr, int port,
229e5b75505Sopenharmony_ci				      void (*cb)(void *ctx,
230e5b75505Sopenharmony_ci						 struct http_request *req),
231e5b75505Sopenharmony_ci				      void *cb_ctx)
232e5b75505Sopenharmony_ci{
233e5b75505Sopenharmony_ci	struct sockaddr_in sin;
234e5b75505Sopenharmony_ci	struct http_server *srv;
235e5b75505Sopenharmony_ci	int on = 1;
236e5b75505Sopenharmony_ci
237e5b75505Sopenharmony_ci	srv = os_zalloc(sizeof(*srv));
238e5b75505Sopenharmony_ci	if (srv == NULL)
239e5b75505Sopenharmony_ci		return NULL;
240e5b75505Sopenharmony_ci	srv->cb = cb;
241e5b75505Sopenharmony_ci	srv->cb_ctx = cb_ctx;
242e5b75505Sopenharmony_ci
243e5b75505Sopenharmony_ci	srv->fd = socket(AF_INET, SOCK_STREAM, 0);
244e5b75505Sopenharmony_ci	if (srv->fd < 0)
245e5b75505Sopenharmony_ci		goto fail;
246e5b75505Sopenharmony_ci
247e5b75505Sopenharmony_ci	if (setsockopt(srv->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
248e5b75505Sopenharmony_ci	{
249e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
250e5b75505Sopenharmony_ci			   "HTTP: setsockopt(SO_REUSEADDR) failed: %s",
251e5b75505Sopenharmony_ci			   strerror(errno));
252e5b75505Sopenharmony_ci		/* try to continue anyway */
253e5b75505Sopenharmony_ci	}
254e5b75505Sopenharmony_ci
255e5b75505Sopenharmony_ci	if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
256e5b75505Sopenharmony_ci		goto fail;
257e5b75505Sopenharmony_ci	if (port < 0)
258e5b75505Sopenharmony_ci		srv->port = 49152;
259e5b75505Sopenharmony_ci	else
260e5b75505Sopenharmony_ci		srv->port = port;
261e5b75505Sopenharmony_ci
262e5b75505Sopenharmony_ci	os_memset(&sin, 0, sizeof(sin));
263e5b75505Sopenharmony_ci	sin.sin_family = AF_INET;
264e5b75505Sopenharmony_ci	sin.sin_addr.s_addr = addr->s_addr;
265e5b75505Sopenharmony_ci
266e5b75505Sopenharmony_ci	for (;;) {
267e5b75505Sopenharmony_ci		sin.sin_port = htons(srv->port);
268e5b75505Sopenharmony_ci		if (bind(srv->fd, (struct sockaddr *) &sin, sizeof(sin)) == 0)
269e5b75505Sopenharmony_ci			break;
270e5b75505Sopenharmony_ci		if (errno == EADDRINUSE) {
271e5b75505Sopenharmony_ci			/* search for unused port */
272e5b75505Sopenharmony_ci			if (++srv->port == 65535 || port >= 0)
273e5b75505Sopenharmony_ci				goto fail;
274e5b75505Sopenharmony_ci			continue;
275e5b75505Sopenharmony_ci		}
276e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "HTTP: Failed to bind server port %d: "
277e5b75505Sopenharmony_ci			   "%s", srv->port, strerror(errno));
278e5b75505Sopenharmony_ci		goto fail;
279e5b75505Sopenharmony_ci	}
280e5b75505Sopenharmony_ci	if (listen(srv->fd, 10 /* max backlog */) < 0 ||
281e5b75505Sopenharmony_ci	    fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0 ||
282e5b75505Sopenharmony_ci	    eloop_register_sock(srv->fd, EVENT_TYPE_READ, http_server_cb,
283e5b75505Sopenharmony_ci				srv, NULL))
284e5b75505Sopenharmony_ci		goto fail;
285e5b75505Sopenharmony_ci
286e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "HTTP: Started server on %s:%d",
287e5b75505Sopenharmony_ci		   inet_ntoa(*addr), srv->port);
288e5b75505Sopenharmony_ci
289e5b75505Sopenharmony_ci	return srv;
290e5b75505Sopenharmony_ci
291e5b75505Sopenharmony_cifail:
292e5b75505Sopenharmony_ci	http_server_deinit(srv);
293e5b75505Sopenharmony_ci	return NULL;
294e5b75505Sopenharmony_ci}
295e5b75505Sopenharmony_ci
296e5b75505Sopenharmony_ci
297e5b75505Sopenharmony_civoid http_server_deinit(struct http_server *srv)
298e5b75505Sopenharmony_ci{
299e5b75505Sopenharmony_ci	if (srv == NULL)
300e5b75505Sopenharmony_ci		return;
301e5b75505Sopenharmony_ci	if (srv->fd >= 0) {
302e5b75505Sopenharmony_ci		eloop_unregister_sock(srv->fd, EVENT_TYPE_READ);
303e5b75505Sopenharmony_ci		close(srv->fd);
304e5b75505Sopenharmony_ci	}
305e5b75505Sopenharmony_ci	http_request_free_all(srv->requests);
306e5b75505Sopenharmony_ci
307e5b75505Sopenharmony_ci	os_free(srv);
308e5b75505Sopenharmony_ci}
309e5b75505Sopenharmony_ci
310e5b75505Sopenharmony_ci
311e5b75505Sopenharmony_ciint http_server_get_port(struct http_server *srv)
312e5b75505Sopenharmony_ci{
313e5b75505Sopenharmony_ci	return srv->port;
314e5b75505Sopenharmony_ci}
315