WPS: Add HTTP server module
authorJouni Malinen <j@w1.fi>
Sun, 8 Nov 2009 15:26:55 +0000 (17:26 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 8 Nov 2009 15:26:55 +0000 (17:26 +0200)
Clean up code so that UPnP implementation does not need to include all
the HTTP functionality. In addition, make it easier to share HTTP server
functionality with other components in the future.

hostapd/Makefile
src/wps/http_server.c [new file with mode: 0644]
src/wps/http_server.h [new file with mode: 0644]
src/wps/wps_upnp_i.h
src/wps/wps_upnp_web.c
wpa_supplicant/Makefile

index 6756c8f..1b6748d 100644 (file)
@@ -312,6 +312,7 @@ OBJS += ../src/wps/wps_upnp_event.o
 OBJS += ../src/wps/upnp_xml.o
 OBJS += ../src/wps/httpread.o
 OBJS += ../src/wps/http_client.o
+OBJS += ../src/wps/http_server.o
 endif
 
 endif
diff --git a/src/wps/http_server.c b/src/wps/http_server.c
new file mode 100644 (file)
index 0000000..2593dda
--- /dev/null
@@ -0,0 +1,128 @@
+/**
+ * http_server - HTTP server
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <fcntl.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "http_server.h"
+
+
+struct http_server {
+       void (*cb)(void *ctx, int fd, struct sockaddr_in *addr);
+       void *cb_ctx;
+
+       int fd;
+       int port;
+};
+
+
+static void http_server_cb(int sd, void *eloop_ctx, void *sock_ctx)
+{
+       struct sockaddr_in addr;
+       socklen_t addr_len = sizeof(addr);
+       struct http_server *srv = eloop_ctx;
+       int conn;
+
+       conn = accept(srv->fd, (struct sockaddr *) &addr, &addr_len);
+       if (conn < 0) {
+               wpa_printf(MSG_DEBUG, "HTTP: Failed to accept new connection: "
+                          "%s", strerror(errno));
+               return;
+       }
+       wpa_printf(MSG_DEBUG, "HTTP: Connection from %s:%d",
+                  inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+       srv->cb(srv->cb_ctx, conn, &addr);
+}
+
+
+struct http_server * http_server_init(struct in_addr *addr, int port,
+                                     void (*cb)(void *ctx, int fd,
+                                                struct sockaddr_in *addr),
+                                     void *cb_ctx)
+{
+       struct sockaddr_in sin;
+       struct http_server *srv;
+
+       srv = os_zalloc(sizeof(*srv));
+       if (srv == NULL)
+               return NULL;
+       srv->cb = cb;
+       srv->cb_ctx = cb_ctx;
+
+       srv->fd = socket(AF_INET, SOCK_STREAM, 0);
+       if (srv->fd < 0)
+               goto fail;
+       if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
+               goto fail;
+       if (port < 0)
+               srv->port = 49152;
+       else
+               srv->port = port;
+
+       os_memset(&sin, 0, sizeof(sin));
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = addr->s_addr;
+
+       for (;;) {
+               sin.sin_port = htons(srv->port);
+               if (bind(srv->fd, (struct sockaddr *) &sin, sizeof(sin)) == 0)
+                       break;
+               if (errno == EADDRINUSE) {
+                       /* search for unused port */
+                       if (++srv->port == 65535 || port >= 0)
+                               goto fail;
+                       continue;
+               }
+               wpa_printf(MSG_DEBUG, "HTTP: Failed to bind server port %d: "
+                          "%s", srv->port, strerror(errno));
+               goto fail;
+       }
+       if (listen(srv->fd, 10 /* max backlog */) < 0)
+               goto fail;
+       if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
+               goto fail;
+       if (eloop_register_sock(srv->fd, EVENT_TYPE_READ, http_server_cb,
+                               srv, NULL))
+               goto fail;
+
+       wpa_printf(MSG_DEBUG, "HTTP: Started server on %s:%d",
+                  inet_ntoa(*addr), srv->port);
+
+       return srv;
+
+fail:
+       http_server_deinit(srv);
+       return NULL;
+}
+
+
+void http_server_deinit(struct http_server *srv)
+{
+       if (srv == NULL)
+               return;
+       if (srv->fd >= 0) {
+               eloop_unregister_sock(srv->fd, EVENT_TYPE_READ);
+               close(srv->fd);
+       }
+
+       os_free(srv);
+}
+
+
+int http_server_get_port(struct http_server *srv)
+{
+       return srv->port;
+}
diff --git a/src/wps/http_server.h b/src/wps/http_server.h
new file mode 100644 (file)
index 0000000..1d01efc
--- /dev/null
@@ -0,0 +1,27 @@
+/**
+ * http_server - HTTP server
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef HTTP_SERVER_H
+#define HTTP_SERVER_H
+
+struct http_server;
+
+struct http_server * http_server_init(struct in_addr *addr, int port,
+                                     void (*cb)(void *ctx, int fd,
+                                                struct sockaddr_in *addr),
+                                     void *cb_ctx);
+void http_server_deinit(struct http_server *srv);
+int http_server_get_port(struct http_server *srv);
+
+#endif /* HTTP_SERVER_H */
index 00b71d7..02b807e 100644 (file)
@@ -130,8 +130,7 @@ struct upnp_wps_device_sm {
        struct advertisement_state_machine *msearch_replies;
        int n_msearch_replies; /* no. of pending M-SEARCH replies */
        int web_port; /* our port that others get xml files from */
-       int web_sd; /* socket to listen for web requests */
-       int web_sd_registered; /* nonzero if we must cancel registration */
+       struct http_server *web_srv;
        struct web_connection *web_connections; /* linked list */
        int n_web_connections; /* no. of pending web connections */
        /* Note: subscriptions are kept in expiry order */
index 2ff3af2..a841c13 100644 (file)
@@ -9,13 +9,12 @@
  */
 
 #include "includes.h"
-#include <fcntl.h>
 
 #include "common.h"
 #include "base64.h"
-#include "eloop.h"
 #include "uuid.h"
 #include "httpread.h"
+#include "http_server.h"
 #include "wps_i.h"
 #include "wps_upnp.h"
 #include "wps_upnp_i.h"
@@ -1593,9 +1592,9 @@ static void web_connection_got_file_handler(struct httpread *handle,
  * The socket descriptor sd is handed over for ownership by the WPS UPnP
  * state machine.
  */
-static void web_connection_start(struct upnp_wps_device_sm *sm,
-                                int sd, struct sockaddr_in *addr)
+static void web_connection_start(void *ctx, int sd, struct sockaddr_in *addr)
 {
+       struct upnp_wps_device_sm *sm = ctx;
        struct web_connection *c = NULL;
 
        /* if too many connections, bail */
@@ -1649,77 +1648,21 @@ fail:
 
 void web_listener_stop(struct upnp_wps_device_sm *sm)
 {
-       if (sm->web_sd_registered) {
-               sm->web_sd_registered = 0;
-               eloop_unregister_sock(sm->web_sd, EVENT_TYPE_READ);
-       }
-       if (sm->web_sd >= 0)
-               close(sm->web_sd);
-       sm->web_sd = -1;
-}
-
-
-static void web_listener_handler(int sd, void *eloop_ctx, void *sock_ctx)
-{
-       struct sockaddr_in addr;
-       socklen_t addr_len = sizeof(addr);
-       struct upnp_wps_device_sm *sm = sock_ctx;
-       int new_sd;
-
-       /* Create state for new connection */
-       /* Remember so we can cancel if need be */
-       new_sd = accept(sm->web_sd, (struct sockaddr *) &addr, &addr_len);
-       if (new_sd < 0) {
-               wpa_printf(MSG_ERROR, "WPS UPnP: web listener accept "
-                          "errno=%d (%s) web_sd=%d",
-                          errno, strerror(errno), sm->web_sd);
-               return;
-       }
-       web_connection_start(sm, new_sd, &addr);
+       http_server_deinit(sm->web_srv);
+       sm->web_srv = NULL;
 }
 
 
 int web_listener_start(struct upnp_wps_device_sm *sm)
 {
-       struct sockaddr_in addr;
-       int port;
-
-       sm->web_sd = socket(AF_INET, SOCK_STREAM, 0);
-       if (sm->web_sd < 0)
-               goto fail;
-       if (fcntl(sm->web_sd, F_SETFL, O_NONBLOCK) != 0)
-               goto fail;
-       port = 49152;  /* first non-reserved port */
-       for (;;) {
-               os_memset(&addr, 0, sizeof(addr));
-               addr.sin_family = AF_INET;
-               addr.sin_addr.s_addr = sm->ip_addr;
-               addr.sin_port = htons(port);
-               if (bind(sm->web_sd, (struct sockaddr *) &addr,
-                        sizeof(addr)) == 0)
-                       break;
-               if (errno == EADDRINUSE) {
-                       /* search for unused port */
-                       if (++port == 65535)
-                               goto fail;
-                       continue;
-               }
-               goto fail;
+       struct in_addr addr;
+       addr.s_addr = sm->ip_addr;
+       sm->web_srv = http_server_init(&addr, -1, web_connection_start, sm);
+       if (sm->web_srv == NULL) {
+               web_listener_stop(sm);
+               return -1;
        }
-       if (listen(sm->web_sd, 10 /* max backlog */) != 0)
-               goto fail;
-       if (fcntl(sm->web_sd, F_SETFL, O_NONBLOCK) != 0)
-               goto fail;
-       if (eloop_register_sock(sm->web_sd, EVENT_TYPE_READ,
-                               web_listener_handler, NULL, sm))
-               goto fail;
-       sm->web_sd_registered = 1;
-       sm->web_port = port;
+       sm->web_port = http_server_get_port(sm->web_srv);
 
        return 0;
-
-fail:
-       /* Error */
-       web_listener_stop(sm);
-       return -1;
 }
index 70e7a3a..6436f39 100644 (file)
@@ -512,6 +512,7 @@ OBJS += ../src/wps/wps_upnp_event.o
 OBJS += ../src/wps/upnp_xml.o
 OBJS += ../src/wps/httpread.o
 OBJS += ../src/wps/http_client.o
+OBJS += ../src/wps/http_server.o
 endif
 
 endif