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