LCOV - code coverage report
Current view: top level - src/wps - http_server.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1422976643 Lines: 118 145 81.4 %
Date: 2015-02-03 Functions: 16 16 100.0 %

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

Generated by: LCOV version 1.10