LCOV - code coverage report
Current view: top level - src/wps - http_server.c (source / functions) Hit Total Coverage
Test: wpa_supplicant hwsim test run 1388240082 Lines: 106 143 74.1 %
Date: 2013-12-28 Functions: 14 16 87.5 %
Branches: 27 52 51.9 %

           Branch data     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                 :         16 : static void http_request_cb(struct httpread *handle, void *cookie,
      42                 :            :                             enum httpread_event en)
      43                 :            : {
      44                 :         16 :         struct http_request *req = cookie;
      45                 :         16 :         struct http_server *srv = req->srv;
      46                 :            : 
      47         [ +  - ]:         16 :         if (en == HTTPREAD_EVENT_FILE_READY) {
      48                 :         16 :                 wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d received",
      49                 :            :                            inet_ntoa(req->cli.sin_addr),
      50                 :         16 :                            ntohs(req->cli.sin_port));
      51                 :         16 :                 srv->cb(srv->cb_ctx, req);
      52                 :         16 :                 return;
      53                 :            :         }
      54                 :          0 :         wpa_printf(MSG_DEBUG, "HTTP: Request from %s:%d could not be received "
      55                 :            :                    "completely", inet_ntoa(req->cli.sin_addr),
      56                 :          0 :                    ntohs(req->cli.sin_port));
      57                 :          0 :         http_request_deinit(req);
      58                 :            : }
      59                 :            : 
      60                 :            : 
      61                 :         16 : 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         [ -  + ]:         16 :         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                 :         16 :         req = os_zalloc(sizeof(*req));
      72         [ -  + ]:         16 :         if (req == NULL)
      73                 :          0 :                 return NULL;
      74                 :            : 
      75                 :         16 :         req->srv = srv;
      76                 :         16 :         req->fd = fd;
      77                 :         16 :         req->cli = *cli;
      78                 :            : 
      79                 :         16 :         req->hread = httpread_create(req->fd, http_request_cb, req,
      80                 :            :                                      HTTP_SERVER_MAX_REQ_LEN,
      81                 :            :                                      HTTP_SERVER_TIMEOUT);
      82         [ -  + ]:         16 :         if (req->hread == NULL) {
      83                 :          0 :                 http_request_deinit(req);
      84                 :          0 :                 return NULL;
      85                 :            :         }
      86                 :            : 
      87                 :         16 :         return req;
      88                 :            : }
      89                 :            : 
      90                 :            : 
      91                 :         16 : void http_request_deinit(struct http_request *req)
      92                 :            : {
      93                 :            :         struct http_request *r, *p;
      94                 :            :         struct http_server *srv;
      95                 :            : 
      96         [ -  + ]:         16 :         if (req == NULL)
      97                 :         16 :                 return;
      98                 :            : 
      99                 :         16 :         srv = req->srv;
     100                 :         16 :         p = NULL;
     101                 :         16 :         r = srv->requests;
     102         [ +  - ]:         16 :         while (r) {
     103         [ +  - ]:         16 :                 if (r == req) {
     104         [ -  + ]:         16 :                         if (p)
     105                 :          0 :                                 p->next = r->next;
     106                 :            :                         else
     107                 :         16 :                                 srv->requests = r->next;
     108                 :         16 :                         srv->request_count--;
     109                 :         16 :                         break;
     110                 :            :                 }
     111                 :          0 :                 p = r;
     112                 :          0 :                 r = r->next;
     113                 :            :         }
     114                 :            : 
     115                 :         16 :         httpread_destroy(req->hread);
     116                 :         16 :         close(req->fd);
     117                 :         16 :         os_free(req);
     118                 :            : }
     119                 :            : 
     120                 :            : 
     121                 :          1 : static void http_request_free_all(struct http_request *req)
     122                 :            : {
     123                 :            :         struct http_request *prev;
     124         [ -  + ]:          1 :         while (req) {
     125                 :          0 :                 prev = req;
     126                 :          0 :                 req = req->next;
     127                 :          0 :                 http_request_deinit(prev);
     128                 :            :         }
     129                 :          1 : }
     130                 :            : 
     131                 :            : 
     132                 :         16 : void http_request_send(struct http_request *req, struct wpabuf *resp)
     133                 :            : {
     134                 :            :         int res;
     135                 :            : 
     136                 :         16 :         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                 :         16 :                    ntohs(req->cli.sin_port));
     140                 :            : 
     141                 :         16 :         res = send(req->fd, wpabuf_head(resp), wpabuf_len(resp), 0);
     142         [ -  + ]:         16 :         if (res < 0) {
     143                 :          0 :                 wpa_printf(MSG_DEBUG, "HTTP: Send failed: %s",
     144                 :          0 :                            strerror(errno));
     145         [ -  + ]:         16 :         } 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                 :         16 :         wpabuf_free(resp);
     152                 :         16 : }
     153                 :            : 
     154                 :            : 
     155                 :         16 : void http_request_send_and_deinit(struct http_request *req,
     156                 :            :                                   struct wpabuf *resp)
     157                 :            : {
     158                 :         16 :         http_request_send(req, resp);
     159                 :         16 :         http_request_deinit(req);
     160                 :         16 : }
     161                 :            : 
     162                 :            : 
     163                 :         16 : enum httpread_hdr_type http_request_get_type(struct http_request *req)
     164                 :            : {
     165                 :         16 :         return httpread_hdr_type_get(req->hread);
     166                 :            : }
     167                 :            : 
     168                 :            : 
     169                 :         32 : char * http_request_get_uri(struct http_request *req)
     170                 :            : {
     171                 :         32 :         return httpread_uri_get(req->hread);
     172                 :            : }
     173                 :            : 
     174                 :            : 
     175                 :          0 : char * http_request_get_hdr(struct http_request *req)
     176                 :            : {
     177                 :          0 :         return httpread_hdr_get(req->hread);
     178                 :            : }
     179                 :            : 
     180                 :            : 
     181                 :         32 : char * http_request_get_data(struct http_request *req)
     182                 :            : {
     183                 :         32 :         return httpread_data_get(req->hread);
     184                 :            : }
     185                 :            : 
     186                 :            : 
     187                 :          0 : char * http_request_get_hdr_line(struct http_request *req, const char *tag)
     188                 :            : {
     189                 :          0 :         return httpread_hdr_line_get(req->hread, tag);
     190                 :            : }
     191                 :            : 
     192                 :            : 
     193                 :         16 : struct sockaddr_in * http_request_get_cli_addr(struct http_request *req)
     194                 :            : {
     195                 :         16 :         return &req->cli;
     196                 :            : }
     197                 :            : 
     198                 :            : 
     199                 :         16 : static void http_server_cb(int sd, void *eloop_ctx, void *sock_ctx)
     200                 :            : {
     201                 :            :         struct sockaddr_in addr;
     202                 :         16 :         socklen_t addr_len = sizeof(addr);
     203                 :         16 :         struct http_server *srv = eloop_ctx;
     204                 :            :         int conn;
     205                 :            :         struct http_request *req;
     206                 :            : 
     207                 :         16 :         conn = accept(srv->fd, (struct sockaddr *) &addr, &addr_len);
     208         [ -  + ]:         16 :         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                 :         16 :         wpa_printf(MSG_DEBUG, "HTTP: Connection from %s:%d",
     214                 :         16 :                    inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
     215                 :            : 
     216                 :         16 :         req = http_request_init(srv, conn, &addr);
     217         [ -  + ]:         16 :         if (req == NULL) {
     218                 :          0 :                 close(conn);
     219                 :          0 :                 return;
     220                 :            :         }
     221                 :            : 
     222                 :         16 :         req->next = srv->requests;
     223                 :         16 :         srv->requests = req;
     224                 :         16 :         srv->request_count++;
     225                 :            : }
     226                 :            : 
     227                 :            : 
     228                 :          1 : 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                 :          1 :         int on = 1;
     236                 :            : 
     237                 :          1 :         srv = os_zalloc(sizeof(*srv));
     238         [ -  + ]:          1 :         if (srv == NULL)
     239                 :          0 :                 return NULL;
     240                 :          1 :         srv->cb = cb;
     241                 :          1 :         srv->cb_ctx = cb_ctx;
     242                 :            : 
     243                 :          1 :         srv->fd = socket(AF_INET, SOCK_STREAM, 0);
     244         [ -  + ]:          1 :         if (srv->fd < 0)
     245                 :          0 :                 goto fail;
     246                 :            : 
     247                 :          1 :         setsockopt(srv->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
     248                 :            : 
     249         [ -  + ]:          1 :         if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
     250                 :          0 :                 goto fail;
     251         [ +  - ]:          1 :         if (port < 0)
     252                 :          1 :                 srv->port = 49152;
     253                 :            :         else
     254                 :          0 :                 srv->port = port;
     255                 :            : 
     256                 :          1 :         os_memset(&sin, 0, sizeof(sin));
     257                 :          1 :         sin.sin_family = AF_INET;
     258                 :          1 :         sin.sin_addr.s_addr = addr->s_addr;
     259                 :            : 
     260                 :            :         for (;;) {
     261                 :          2 :                 sin.sin_port = htons(srv->port);
     262         [ +  + ]:          2 :                 if (bind(srv->fd, (struct sockaddr *) &sin, sizeof(sin)) == 0)
     263                 :          1 :                         break;
     264         [ +  - ]:          1 :                 if (errno == EADDRINUSE) {
     265                 :            :                         /* search for unused port */
     266 [ +  - ][ +  - ]:          1 :                         if (++srv->port == 65535 || port >= 0)
     267                 :            :                                 goto fail;
     268                 :          1 :                         continue;
     269                 :            :                 }
     270                 :          0 :                 wpa_printf(MSG_DEBUG, "HTTP: Failed to bind server port %d: "
     271                 :          0 :                            "%s", srv->port, strerror(errno));
     272                 :          0 :                 goto fail;
     273                 :          1 :         }
     274         [ -  + ]:          1 :         if (listen(srv->fd, 10 /* max backlog */) < 0)
     275                 :          0 :                 goto fail;
     276         [ -  + ]:          1 :         if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
     277                 :          0 :                 goto fail;
     278         [ -  + ]:          1 :         if (eloop_register_sock(srv->fd, EVENT_TYPE_READ, http_server_cb,
     279                 :            :                                 srv, NULL))
     280                 :          0 :                 goto fail;
     281                 :            : 
     282                 :          1 :         wpa_printf(MSG_DEBUG, "HTTP: Started server on %s:%d",
     283                 :            :                    inet_ntoa(*addr), srv->port);
     284                 :            : 
     285                 :          1 :         return srv;
     286                 :            : 
     287                 :            : fail:
     288                 :          0 :         http_server_deinit(srv);
     289                 :          1 :         return NULL;
     290                 :            : }
     291                 :            : 
     292                 :            : 
     293                 :          1 : void http_server_deinit(struct http_server *srv)
     294                 :            : {
     295         [ -  + ]:          1 :         if (srv == NULL)
     296                 :          1 :                 return;
     297         [ +  - ]:          1 :         if (srv->fd >= 0) {
     298                 :          1 :                 eloop_unregister_sock(srv->fd, EVENT_TYPE_READ);
     299                 :          1 :                 close(srv->fd);
     300                 :            :         }
     301                 :          1 :         http_request_free_all(srv->requests);
     302                 :            : 
     303                 :          1 :         os_free(srv);
     304                 :            : }
     305                 :            : 
     306                 :            : 
     307                 :          1 : int http_server_get_port(struct http_server *srv)
     308                 :            : {
     309                 :          1 :         return srv->port;
     310                 :            : }

Generated by: LCOV version 1.9