WPS: Add HTTP server module
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.
This commit is contained in:
parent
585774f28a
commit
b905c4a398
6 changed files with 170 additions and 71 deletions
|
@ -312,6 +312,7 @@ OBJS += ../src/wps/wps_upnp_event.o
|
||||||
OBJS += ../src/wps/upnp_xml.o
|
OBJS += ../src/wps/upnp_xml.o
|
||||||
OBJS += ../src/wps/httpread.o
|
OBJS += ../src/wps/httpread.o
|
||||||
OBJS += ../src/wps/http_client.o
|
OBJS += ../src/wps/http_client.o
|
||||||
|
OBJS += ../src/wps/http_server.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
128
src/wps/http_server.c
Normal file
128
src/wps/http_server.c
Normal file
|
@ -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;
|
||||||
|
}
|
27
src/wps/http_server.h
Normal file
27
src/wps/http_server.h
Normal file
|
@ -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 */
|
|
@ -130,8 +130,7 @@ struct upnp_wps_device_sm {
|
||||||
struct advertisement_state_machine *msearch_replies;
|
struct advertisement_state_machine *msearch_replies;
|
||||||
int n_msearch_replies; /* no. of pending M-SEARCH replies */
|
int n_msearch_replies; /* no. of pending M-SEARCH replies */
|
||||||
int web_port; /* our port that others get xml files from */
|
int web_port; /* our port that others get xml files from */
|
||||||
int web_sd; /* socket to listen for web requests */
|
struct http_server *web_srv;
|
||||||
int web_sd_registered; /* nonzero if we must cancel registration */
|
|
||||||
struct web_connection *web_connections; /* linked list */
|
struct web_connection *web_connections; /* linked list */
|
||||||
int n_web_connections; /* no. of pending web connections */
|
int n_web_connections; /* no. of pending web connections */
|
||||||
/* Note: subscriptions are kept in expiry order */
|
/* Note: subscriptions are kept in expiry order */
|
||||||
|
|
|
@ -9,13 +9,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
#include "eloop.h"
|
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
#include "httpread.h"
|
#include "httpread.h"
|
||||||
|
#include "http_server.h"
|
||||||
#include "wps_i.h"
|
#include "wps_i.h"
|
||||||
#include "wps_upnp.h"
|
#include "wps_upnp.h"
|
||||||
#include "wps_upnp_i.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
|
* The socket descriptor sd is handed over for ownership by the WPS UPnP
|
||||||
* state machine.
|
* state machine.
|
||||||
*/
|
*/
|
||||||
static void web_connection_start(struct upnp_wps_device_sm *sm,
|
static void web_connection_start(void *ctx, int sd, struct sockaddr_in *addr)
|
||||||
int sd, struct sockaddr_in *addr)
|
|
||||||
{
|
{
|
||||||
|
struct upnp_wps_device_sm *sm = ctx;
|
||||||
struct web_connection *c = NULL;
|
struct web_connection *c = NULL;
|
||||||
|
|
||||||
/* if too many connections, bail */
|
/* if too many connections, bail */
|
||||||
|
@ -1649,77 +1648,21 @@ fail:
|
||||||
|
|
||||||
void web_listener_stop(struct upnp_wps_device_sm *sm)
|
void web_listener_stop(struct upnp_wps_device_sm *sm)
|
||||||
{
|
{
|
||||||
if (sm->web_sd_registered) {
|
http_server_deinit(sm->web_srv);
|
||||||
sm->web_sd_registered = 0;
|
sm->web_srv = NULL;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int web_listener_start(struct upnp_wps_device_sm *sm)
|
int web_listener_start(struct upnp_wps_device_sm *sm)
|
||||||
{
|
{
|
||||||
struct sockaddr_in addr;
|
struct in_addr addr;
|
||||||
int port;
|
addr.s_addr = sm->ip_addr;
|
||||||
|
sm->web_srv = http_server_init(&addr, -1, web_connection_start, sm);
|
||||||
sm->web_sd = socket(AF_INET, SOCK_STREAM, 0);
|
if (sm->web_srv == NULL) {
|
||||||
if (sm->web_sd < 0)
|
web_listener_stop(sm);
|
||||||
goto fail;
|
return -1;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
if (listen(sm->web_sd, 10 /* max backlog */) != 0)
|
sm->web_port = http_server_get_port(sm->web_srv);
|
||||||
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;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
|
||||||
/* Error */
|
|
||||||
web_listener_stop(sm);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -512,6 +512,7 @@ OBJS += ../src/wps/wps_upnp_event.o
|
||||||
OBJS += ../src/wps/upnp_xml.o
|
OBJS += ../src/wps/upnp_xml.o
|
||||||
OBJS += ../src/wps/httpread.o
|
OBJS += ../src/wps/httpread.o
|
||||||
OBJS += ../src/wps/http_client.o
|
OBJS += ../src/wps/http_client.o
|
||||||
|
OBJS += ../src/wps/http_server.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
Loading…
Reference in a new issue