diff --git a/hostapd/Makefile b/hostapd/Makefile index 6756c8fd4..1b6748d05 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -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 index 000000000..2593dda8e --- /dev/null +++ b/src/wps/http_server.c @@ -0,0 +1,128 @@ +/** + * http_server - HTTP server + * Copyright (c) 2009, Jouni Malinen + * + * 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 + +#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 index 000000000..1d01efca2 --- /dev/null +++ b/src/wps/http_server.h @@ -0,0 +1,27 @@ +/** + * http_server - HTTP server + * Copyright (c) 2009, Jouni Malinen + * + * 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 */ diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h index 00b71d702..02b807e57 100644 --- a/src/wps/wps_upnp_i.h +++ b/src/wps/wps_upnp_i.h @@ -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 */ diff --git a/src/wps/wps_upnp_web.c b/src/wps/wps_upnp_web.c index 2ff3af269..a841c13cd 100644 --- a/src/wps/wps_upnp_web.c +++ b/src/wps/wps_upnp_web.c @@ -9,13 +9,12 @@ */ #include "includes.h" -#include #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; } diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 70e7a3a6b..6436f3986 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -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