Merge branch 'master' into randomize_url
This commit is contained in:
commit
11fcf5a008
2
README
2
README
|
@ -11,7 +11,7 @@ miniupnpc/ : MiniUPnP client - an UPnP IGD control point
|
||||||
miniupnpd/ : MiniUPnP daemon - an implementation of a UPnP IGD
|
miniupnpd/ : MiniUPnP daemon - an implementation of a UPnP IGD
|
||||||
+ NAT-PMP / PCP gateway
|
+ NAT-PMP / PCP gateway
|
||||||
minissdpd/ : SSDP managing daemon. Designed to work with miniupnpc,
|
minissdpd/ : SSDP managing daemon. Designed to work with miniupnpc,
|
||||||
miniupnpd, minidlna, etc.
|
miniupnpd, ReadyMedia (formerly MiniDLNA), etc.
|
||||||
miniupnpc-async/ : Proof of concept for a UPnP IGD control point using
|
miniupnpc-async/ : Proof of concept for a UPnP IGD control point using
|
||||||
asynchronous (non blocking) sockets.
|
asynchronous (non blocking) sockets.
|
||||||
miniupnpc-libevent/ : UPnP IGD control point using libevent2
|
miniupnpc-libevent/ : UPnP IGD control point using libevent2
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# $Id: testminissdpd.sh,v 1.2 2015/09/03 18:31:25 nanard Exp $
|
# $Id: testminissdpd.sh,v 1.8 2017/04/21 11:57:59 nanard Exp $
|
||||||
# (c) 2016 Thomas Bernard
|
# (c) 2017 Thomas Bernard
|
||||||
|
|
||||||
OS=`uname -s`
|
OS=`uname -s`
|
||||||
IF=lo
|
IF=lo
|
||||||
if [ "$OS" = "Darwin" ] || [ "$OS" = "SunOS" ] ; then
|
if [ "$OS" = "Darwin" ] || [ "$OS" = "OpenBSD" ] || [ "$OS" = "SunOS" ] || [ "$OS" = "FreeBSD" ] ; then
|
||||||
IF=lo0
|
IF=lo0
|
||||||
fi
|
fi
|
||||||
# if set, 1st argument is network interface
|
# if set, 1st argument is network interface
|
||||||
|
|
|
@ -5,7 +5,7 @@ Pod::Spec.new do |spec|
|
||||||
spec.authors = "The MiniUPnP Authors"
|
spec.authors = "The MiniUPnP Authors"
|
||||||
spec.license = { type: "BSD", file: "miniupnpc/LICENSE" }
|
spec.license = { type: "BSD", file: "miniupnpc/LICENSE" }
|
||||||
|
|
||||||
spec.version = "2.0.0.0"
|
spec.version = "2.0.0.2"
|
||||||
spec.source = {
|
spec.source = {
|
||||||
git: 'https://github.com/cpp-ethereum-ios/miniupnp.git',
|
git: 'https://github.com/cpp-ethereum-ios/miniupnp.git',
|
||||||
tag: "v#{spec.version}"
|
tag: "v#{spec.version}"
|
||||||
|
@ -36,12 +36,13 @@ Pod::Spec.new do |spec|
|
||||||
CC=`xcrun -sdk $PLATFORM -find cc` \
|
CC=`xcrun -sdk $PLATFORM -find cc` \
|
||||||
CFLAGS="-arch $ARCH -isysroot $SDKPATH" \
|
CFLAGS="-arch $ARCH -isysroot $SDKPATH" \
|
||||||
LIBTOOL=`xcrun -sdk $PLATFORM -find libtool` \
|
LIBTOOL=`xcrun -sdk $PLATFORM -find libtool` \
|
||||||
LDFLAGS="-arch $ARCH"
|
LDFLAGS="-arch $ARCH -headerpad_max_install_names"
|
||||||
}
|
}
|
||||||
|
|
||||||
create_universal_library() {
|
create_universal_library() {
|
||||||
lipo -create -output build-ios/libminiupnpc.dylib \
|
lipo -create -output libminiupnpc.dylib \
|
||||||
build-ios/{armv7,arm64,i386,x86_64}/usr/lib/libminiupnpc.dylib
|
build-ios/{armv7,arm64,i386,x86_64}/usr/lib/libminiupnpc.dylib
|
||||||
|
install_name_tool -id "@rpath/libminiupnpc.dylib" libminiupnpc.dylib
|
||||||
}
|
}
|
||||||
|
|
||||||
cd miniupnpc
|
cd miniupnpc
|
||||||
|
@ -49,5 +50,5 @@ Pod::Spec.new do |spec|
|
||||||
CMD
|
CMD
|
||||||
|
|
||||||
spec.source_files = "miniupnpc/build-ios/armv7/usr/include/**/*.h"
|
spec.source_files = "miniupnpc/build-ios/armv7/usr/include/**/*.h"
|
||||||
spec.ios.vendored_libraries = "miniupnpc/build-ios/libminiupnpc.dylib"
|
spec.ios.vendored_libraries = "miniupnpc/libminiupnpc.dylib"
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
# $Id: Makefile,v 1.9 2014/11/04 22:25:00 nanard Exp $
|
# $Id: Makefile,v 1.12 2017/05/26 11:01:37 nanard Exp $
|
||||||
# MiniUPnP Project
|
# MiniUPnP Project
|
||||||
# http://miniupnp.free.fr/
|
# http://miniupnp.free.fr/
|
||||||
# (c) 2005-2014 Thomas Bernard
|
# (c) 2005-2017 Thomas Bernard
|
||||||
# to install use :
|
# to install use :
|
||||||
# $ PREFIX=/tmp/dummylocation make install
|
# $ PREFIX=/tmp/dummylocation make install
|
||||||
# or
|
# or
|
||||||
# $ INSTALLPREFIX=/usr/local make install
|
# $ INSTALLPREFIX=/usr/local make install
|
||||||
# or
|
# or
|
||||||
# make install (will go to /usr/bin, /usr/lib, etc...)
|
# make install (will go to /usr/bin, /usr/lib, etc...)
|
||||||
|
OS = $(shell uname -s)
|
||||||
|
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
#AR = gar
|
#AR = gar
|
||||||
CFLAGS = -O0 -g -DDEBUG
|
CFLAGS = -O0 -g -DDEBUG
|
||||||
|
@ -16,10 +18,15 @@ CFLAGS += -fPIC
|
||||||
CFLAGS += -ansi
|
CFLAGS += -ansi
|
||||||
CFLAGS += -Wall -W
|
CFLAGS += -Wall -W
|
||||||
CFLAGS += -D_BSD_SOURCE
|
CFLAGS += -D_BSD_SOURCE
|
||||||
|
ifneq ($(OS), FreeBSD)
|
||||||
|
ifneq ($(OS), Darwin)
|
||||||
|
#CFLAGS += -D_POSIX_C_SOURCE=200112L
|
||||||
|
CFLAGS += -D_XOPEN_SOURCE=600
|
||||||
|
endif
|
||||||
|
endif
|
||||||
CFLAGS += -DUPNPC_USE_SELECT
|
CFLAGS += -DUPNPC_USE_SELECT
|
||||||
INSTALL = install
|
INSTALL = install
|
||||||
|
|
||||||
OS = $(shell uname -s)
|
|
||||||
#following libs are needed on Solaris
|
#following libs are needed on Solaris
|
||||||
ifeq ($(OS), SunOS)
|
ifeq ($(OS), SunOS)
|
||||||
LDLIBS += -lsocket -lnsl -lresolv
|
LDLIBS += -lsocket -lnsl -lresolv
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* $Id: miniupnpc-async.c,v 1.19 2014/11/07 12:05:40 nanard Exp $ */
|
/* $Id: miniupnpc-async.c,v 1.19 2014/11/07 12:05:40 nanard Exp $ */
|
||||||
/* miniupnpc-async
|
/* miniupnpc-async
|
||||||
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr>
|
* Copyright (c) 2008-2017, Thomas BERNARD <miniupnp@free.fr>
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
@ -72,8 +72,8 @@ struct upnp_args {
|
||||||
|
|
||||||
/* private functions */
|
/* private functions */
|
||||||
|
|
||||||
static int upnpc_connect(upnpc_t * p, const char * url);
|
static int upnpc_connect(upnpc_device_t * p, const char * url);
|
||||||
static int upnpc_send_request(upnpc_t * p);
|
static int upnpc_send_request(upnpc_device_t * p);
|
||||||
|
|
||||||
|
|
||||||
/* parse_msearch_reply()
|
/* parse_msearch_reply()
|
||||||
|
@ -83,8 +83,8 @@ static int upnpc_send_request(upnpc_t * p);
|
||||||
* The strings are NOT null terminated */
|
* The strings are NOT null terminated */
|
||||||
static void
|
static void
|
||||||
parse_msearch_reply(const char * reply, int size,
|
parse_msearch_reply(const char * reply, int size,
|
||||||
const char * * location, int * locationsize,
|
const char * * location, unsigned int * locationsize,
|
||||||
const char * * st, int * stsize)
|
const char * * st, unsigned int * stsize)
|
||||||
{
|
{
|
||||||
int a, b, i;
|
int a, b, i;
|
||||||
i = 0; /* current character index */
|
i = 0; /* current character index */
|
||||||
|
@ -147,26 +147,26 @@ static int upnpc_send_ssdp_msearch(upnpc_t * p, const char * device, unsigned in
|
||||||
int err = SOCKET_ERROR;
|
int err = SOCKET_ERROR;
|
||||||
if(err == EINTR || WOULDBLOCK(err)) {
|
if(err == EINTR || WOULDBLOCK(err)) {
|
||||||
debug_printf("upnpc_send_ssdp_msearch: should try again");
|
debug_printf("upnpc_send_ssdp_msearch: should try again");
|
||||||
p->state = ESendSSDP;
|
p->state = EUPnPSendSSDP;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
PRINT_SOCKET_ERROR("sendto");
|
PRINT_SOCKET_ERROR("sendto");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
p->state = EReceiveSSDP;
|
p->state = EUPnPReceiveSSDP;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int upnpc_set_root_desc_location(upnpc_t * p, const char * location, int locationsize)
|
static int upnpc_set_root_desc_location(upnpc_device_t * d, const char * location, int locationsize)
|
||||||
{
|
{
|
||||||
char * tmp;
|
char * tmp;
|
||||||
tmp = realloc(p->root_desc_location, locationsize + 1);
|
tmp = realloc(d->root_desc_location, locationsize + 1);
|
||||||
if(tmp == 0) {
|
if(tmp == 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memcpy(tmp, location, locationsize);
|
memcpy(tmp, location, locationsize);
|
||||||
tmp[locationsize] = '\0';
|
tmp[locationsize] = '\0';
|
||||||
p->root_desc_location = tmp;
|
d->root_desc_location = tmp;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,23 +181,41 @@ static int upnpc_receive_and_parse_ssdp(upnpc_t * p)
|
||||||
debug_printf("empty packet received\n");
|
debug_printf("empty packet received\n");
|
||||||
} else {
|
} else {
|
||||||
const char * location = NULL;
|
const char * location = NULL;
|
||||||
int locationsize;
|
unsigned int locationsize;
|
||||||
const char * st = NULL;
|
const char * st = NULL;
|
||||||
int stsize;
|
unsigned int stsize;
|
||||||
debug_printf("%.*s", n, bufr);
|
debug_printf("%.*s", n, bufr);
|
||||||
parse_msearch_reply(bufr, n, &location, &locationsize, &st, &stsize);
|
parse_msearch_reply(bufr, n, &location, &locationsize, &st, &stsize);
|
||||||
debug_printf("location = '%.*s'\n", locationsize, location);
|
debug_printf("location = '%.*s'\n", locationsize, location);
|
||||||
debug_printf("st = '%.*s'\n", stsize, st);
|
debug_printf("st = '%.*s'\n", stsize, st);
|
||||||
if(location != NULL) {
|
if(location != NULL) {
|
||||||
if(upnpc_set_root_desc_location(p, location, locationsize) < 0) {
|
upnpc_device_t * dev = p->device_list;
|
||||||
p->state = EError;
|
while(dev != NULL) {
|
||||||
|
if(dev->root_desc_location != NULL
|
||||||
|
&& strlen(dev->root_desc_location) == locationsize
|
||||||
|
&& memcmp(dev->root_desc_location, location, locationsize) == 0) {
|
||||||
|
debug_printf("device already in list (location='%s')\n", dev->root_desc_location);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
p->state = EGetDescConnect;
|
dev = dev->next;
|
||||||
upnpc_connect(p, p->root_desc_location);
|
}
|
||||||
|
dev = calloc(1, sizeof(upnpc_device_t));
|
||||||
|
if(dev == NULL) {
|
||||||
|
p->state = EUPnPError;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(upnpc_set_root_desc_location(dev, location, locationsize) < 0) {
|
||||||
|
free(dev);
|
||||||
|
p->state = EUPnPError;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dev->next = p->device_list;
|
||||||
|
p->device_list = dev;
|
||||||
|
dev->state = EDevGetDescConnect;
|
||||||
|
upnpc_connect(dev, dev->root_desc_location);
|
||||||
} else {
|
} else {
|
||||||
/* or do nothing ? */
|
/* or do nothing ? */
|
||||||
p->state = EError;
|
p->state = EUPnPError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -298,7 +316,7 @@ parseURL(const char * url,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int upnpc_connect(upnpc_t * p, const char * url)
|
static int upnpc_connect(upnpc_device_t * p, const char * url)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
char hostname[MAXHOSTNAMELEN+1];
|
char hostname[MAXHOSTNAMELEN+1];
|
||||||
|
@ -308,19 +326,19 @@ static int upnpc_connect(upnpc_t * p, const char * url)
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
|
|
||||||
if(p->root_desc_location == 0) {
|
/*if(p->root_desc_location == 0) {
|
||||||
p->state = EError;
|
p->state = EError;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}*/
|
||||||
if(!parseURL(url/*p->root_desc_location*/, hostname, &port,
|
if(!parseURL(url/*p->root_desc_location*/, hostname, &port,
|
||||||
&path, &scope_id)) {
|
&path, &scope_id)) {
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
p->http_socket = socket(PF_INET, SOCK_STREAM, 0);
|
p->http_socket = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
if(p->http_socket < 0) {
|
if(p->http_socket < 0) {
|
||||||
PRINT_SOCKET_ERROR("socket");
|
PRINT_SOCKET_ERROR("socket");
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(!set_non_blocking(p->http_socket)) {
|
if(!set_non_blocking(p->http_socket)) {
|
||||||
|
@ -339,44 +357,44 @@ static int upnpc_connect(upnpc_t * p, const char * url)
|
||||||
return 0;
|
return 0;
|
||||||
} else if(errno != EINTR) {
|
} else if(errno != EINTR) {
|
||||||
PRINT_SOCKET_ERROR("connect");
|
PRINT_SOCKET_ERROR("connect");
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while(r < 0 && errno == EINTR);
|
} while(r < 0 && errno == EINTR);
|
||||||
if(p->state == EGetDescConnect) {
|
if(p->state == EDevGetDescConnect) {
|
||||||
p->state = EGetDescRequest;
|
p->state = EDevGetDescRequest;
|
||||||
} else {
|
} else {
|
||||||
p->state = ESoapRequest;
|
p->state = EDevSoapRequest;
|
||||||
}
|
}
|
||||||
upnpc_send_request(p);
|
upnpc_send_request(p);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int upnpc_complete_connect(upnpc_t * p)
|
static int upnpc_complete_connect(upnpc_device_t * p)
|
||||||
{
|
{
|
||||||
socklen_t len;
|
socklen_t len;
|
||||||
int err;
|
int err;
|
||||||
len = sizeof(err);
|
len = sizeof(err);
|
||||||
if(getsockopt(p->http_socket, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
|
if(getsockopt(p->http_socket, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
|
||||||
PRINT_SOCKET_ERROR("getsockopt");
|
PRINT_SOCKET_ERROR("getsockopt");
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(err != 0) {
|
if(err != 0) {
|
||||||
debug_printf("connect failed %d\n", err);
|
debug_printf("connect failed %d\n", err);
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(p->state == EGetDescConnect)
|
if(p->state == EDevGetDescConnect)
|
||||||
p->state = EGetDescRequest;
|
p->state = EDevGetDescRequest;
|
||||||
else
|
else
|
||||||
p->state = ESoapRequest;
|
p->state = EDevSoapRequest;
|
||||||
upnpc_send_request(p);
|
upnpc_send_request(p);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int upnpc_send_request(upnpc_t * p)
|
static int upnpc_send_request(upnpc_device_t * p)
|
||||||
{
|
{
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
static const char reqfmt[] = "GET %s HTTP/1.1\r\n"
|
static const char reqfmt[] = "GET %s HTTP/1.1\r\n"
|
||||||
|
@ -384,6 +402,13 @@ static int upnpc_send_request(upnpc_t * p)
|
||||||
"Connection: Close\r\n"
|
"Connection: Close\r\n"
|
||||||
"User-Agent: MiniUPnPc-async\r\n"
|
"User-Agent: MiniUPnPc-async\r\n"
|
||||||
"\r\n";
|
"\r\n";
|
||||||
|
|
||||||
|
/* retrieve "our" IP address used to connect to the UPnP device */
|
||||||
|
p->selfaddrlen = sizeof(struct sockaddr_storage);
|
||||||
|
if(getsockname(p->http_socket, (struct sockaddr *)&p->selfaddr, &p->selfaddrlen) < 0) {
|
||||||
|
PRINT_SOCKET_ERROR("getsockname()");
|
||||||
|
}
|
||||||
|
|
||||||
if(p->http_request == NULL) {
|
if(p->http_request == NULL) {
|
||||||
char hostname[MAXHOSTNAMELEN+1];
|
char hostname[MAXHOSTNAMELEN+1];
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
|
@ -392,13 +417,13 @@ static int upnpc_send_request(upnpc_t * p)
|
||||||
int len;
|
int len;
|
||||||
if(!parseURL(p->root_desc_location, hostname, &port,
|
if(!parseURL(p->root_desc_location, hostname, &port,
|
||||||
&path, &scope_id)) {
|
&path, &scope_id)) {
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
len = snprintf(NULL, 0, reqfmt, path, hostname, port);
|
len = snprintf(NULL, 0, reqfmt, path, hostname, port);
|
||||||
p->http_request = malloc(len + 1);
|
p->http_request = malloc(len + 1);
|
||||||
if(p->http_request == NULL) {
|
if(p->http_request == NULL) {
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
p->http_request_len = snprintf(p->http_request, len + 1,
|
p->http_request_len = snprintf(p->http_request, len + 1,
|
||||||
|
@ -409,7 +434,7 @@ static int upnpc_send_request(upnpc_t * p)
|
||||||
p->http_request_len - p->http_request_sent, 0/* flags */);
|
p->http_request_len - p->http_request_sent, 0/* flags */);
|
||||||
if(n < 0) {
|
if(n < 0) {
|
||||||
PRINT_SOCKET_ERROR("send");
|
PRINT_SOCKET_ERROR("send");
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
debug_printf("sent %d bytes\n", (int)n);
|
debug_printf("sent %d bytes\n", (int)n);
|
||||||
|
@ -426,10 +451,10 @@ static int upnpc_send_request(upnpc_t * p)
|
||||||
free(p->http_request);
|
free(p->http_request);
|
||||||
p->http_request = NULL;
|
p->http_request = NULL;
|
||||||
p->http_request_len = 0;
|
p->http_request_len = 0;
|
||||||
if(p->state == EGetDescRequest)
|
if(p->state == EDevGetDescRequest)
|
||||||
p->state = EGetDescResponse;
|
p->state = EDevGetDescResponse;
|
||||||
else
|
else
|
||||||
p->state = ESoapResponse;
|
p->state = EDevSoapResponse;
|
||||||
free(p->http_response);
|
free(p->http_response);
|
||||||
p->http_response = NULL;
|
p->http_response = NULL;
|
||||||
p->http_response_received = 0;
|
p->http_response_received = 0;
|
||||||
|
@ -440,7 +465,7 @@ static int upnpc_send_request(upnpc_t * p)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int upnpc_parse_headers(upnpc_t * p)
|
static int upnpc_parse_headers(upnpc_device_t * p)
|
||||||
{
|
{
|
||||||
/* search for CR LF CR LF (end of headers)
|
/* search for CR LF CR LF (end of headers)
|
||||||
* recognize also LF LF */
|
* recognize also LF LF */
|
||||||
|
@ -547,7 +572,7 @@ static char * build_url_string(const char * urlbase, const char * root_desc_url,
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int upnpc_get_response(upnpc_t * p)
|
static int upnpc_get_response(upnpc_device_t * p)
|
||||||
{
|
{
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
ssize_t count;
|
ssize_t count;
|
||||||
|
@ -566,7 +591,7 @@ static int upnpc_get_response(upnpc_t * p)
|
||||||
if(errno == EINTR || WOULDBLOCK(errno))
|
if(errno == EINTR || WOULDBLOCK(errno))
|
||||||
return 0; /* try again later */
|
return 0; /* try again later */
|
||||||
PRINT_SOCKET_ERROR("read");
|
PRINT_SOCKET_ERROR("read");
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
return -1;
|
return -1;
|
||||||
} else if(n == 0) {
|
} else if(n == 0) {
|
||||||
/* receiving finished */
|
/* receiving finished */
|
||||||
|
@ -579,7 +604,7 @@ static int upnpc_get_response(upnpc_t * p)
|
||||||
}
|
}
|
||||||
/* TODO : decode chunked transfer-encoding */
|
/* TODO : decode chunked transfer-encoding */
|
||||||
/* parse xml */
|
/* parse xml */
|
||||||
if(p->state == EGetDescResponse) {
|
if(p->state == EDevGetDescResponse) {
|
||||||
struct IGDdatas igd;
|
struct IGDdatas igd;
|
||||||
struct xmlparser parser;
|
struct xmlparser parser;
|
||||||
memset(&igd, 0, sizeof(struct IGDdatas));
|
memset(&igd, 0, sizeof(struct IGDdatas));
|
||||||
|
@ -608,7 +633,7 @@ static int upnpc_get_response(upnpc_t * p)
|
||||||
p->http_response = NULL;
|
p->http_response = NULL;
|
||||||
p->http_response_received = 0;
|
p->http_response_received = 0;
|
||||||
p->http_response_end_of_headers = 0;
|
p->http_response_end_of_headers = 0;
|
||||||
p->state = EReady;
|
p->state = EDevReady;
|
||||||
} else {
|
} else {
|
||||||
/* receiving in progress */
|
/* receiving in progress */
|
||||||
debug_printf("received %d bytes:\n%.*s\n", (int)n, (int)n, buffer);
|
debug_printf("received %d bytes:\n%.*s\n", (int)n, (int)n, buffer);
|
||||||
|
@ -616,7 +641,7 @@ static int upnpc_get_response(upnpc_t * p)
|
||||||
p->http_response = malloc(n);
|
p->http_response = malloc(n);
|
||||||
if(p->http_response == NULL) {
|
if(p->http_response == NULL) {
|
||||||
debug_printf("failed to malloc %d bytes\n", (int)n);
|
debug_printf("failed to malloc %d bytes\n", (int)n);
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
p->http_response_received = n;
|
p->http_response_received = n;
|
||||||
|
@ -625,7 +650,7 @@ static int upnpc_get_response(upnpc_t * p)
|
||||||
char * tmp = realloc(p->http_response, p->http_response_received + n);
|
char * tmp = realloc(p->http_response, p->http_response_received + n);
|
||||||
if(tmp == NULL) {
|
if(tmp == NULL) {
|
||||||
debug_printf("failed to realloc %d bytes\n", (int)(p->http_response_received + n));
|
debug_printf("failed to realloc %d bytes\n", (int)(p->http_response_received + n));
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
p->http_response = tmp;
|
p->http_response = tmp;
|
||||||
|
@ -643,7 +668,7 @@ static int upnpc_get_response(upnpc_t * p)
|
||||||
#define SERVICEPREFIX "u"
|
#define SERVICEPREFIX "u"
|
||||||
#define SERVICEPREFIX2 'u'
|
#define SERVICEPREFIX2 'u'
|
||||||
|
|
||||||
static int upnpc_build_soap_request(upnpc_t * p, const char * url,
|
static int upnpc_build_soap_request(upnpc_device_t * p, const char * url,
|
||||||
const char * service,
|
const char * service,
|
||||||
const char * action,
|
const char * action,
|
||||||
const struct upnp_args * args, int arg_count)
|
const struct upnp_args * args, int arg_count)
|
||||||
|
@ -689,7 +714,7 @@ static int upnpc_build_soap_request(upnpc_t * p, const char * url,
|
||||||
}
|
}
|
||||||
args_xml = malloc(++l);
|
args_xml = malloc(++l);
|
||||||
if(args_xml == NULL) {
|
if(args_xml == NULL) {
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for(i = 0, n = 0; i < arg_count && n < l; i++) {
|
for(i = 0, n = 0; i < arg_count && n < l; i++) {
|
||||||
|
@ -702,7 +727,7 @@ static int upnpc_build_soap_request(upnpc_t * p, const char * url,
|
||||||
body_len = snprintf(NULL, 0, fmt_soap, action, service, args_xml?args_xml:"", action);
|
body_len = snprintf(NULL, 0, fmt_soap, action, service, args_xml?args_xml:"", action);
|
||||||
body = malloc(body_len + 1);
|
body = malloc(body_len + 1);
|
||||||
if(body == NULL) {
|
if(body == NULL) {
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
free(args_xml);
|
free(args_xml);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -712,7 +737,7 @@ static int upnpc_build_soap_request(upnpc_t * p, const char * url,
|
||||||
free(args_xml);
|
free(args_xml);
|
||||||
args_xml = NULL;
|
args_xml = NULL;
|
||||||
if(!parseURL(url, hostname, &port, &path, &scope_id)) {
|
if(!parseURL(url, hostname, &port, &path, &scope_id)) {
|
||||||
p->state = EError;
|
p->state = EDevError;
|
||||||
free(body);
|
free(body);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -741,7 +766,7 @@ int upnpc_init(upnpc_t * p, const char * multicastif)
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
if(!p)
|
if(!p)
|
||||||
return UPNPC_ERR_INVALID_ARGS;
|
return UPNPC_ERR_INVALID_ARGS;
|
||||||
p->state = EError;
|
p->state = EUPnPError;
|
||||||
memset(p, 0, sizeof(upnpc_t)); /* clean everything */
|
memset(p, 0, sizeof(upnpc_t)); /* clean everything */
|
||||||
/* open the socket for SSDP */
|
/* open the socket for SSDP */
|
||||||
p->ssdp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
p->ssdp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
@ -782,57 +807,62 @@ int upnpc_init(upnpc_t * p, const char * multicastif)
|
||||||
return UPNPC_ERR_BIND_FAILED;
|
return UPNPC_ERR_BIND_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->state = EInit;
|
p->state = EUPnPInit;
|
||||||
return UPNPC_OK;
|
return UPNPC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int upnpc_finalize(upnpc_t * p)
|
int upnpc_finalize(upnpc_t * p)
|
||||||
{
|
{
|
||||||
if(!p) return UPNPC_ERR_INVALID_ARGS;
|
if(!p) return UPNPC_ERR_INVALID_ARGS;
|
||||||
free(p->root_desc_location);
|
|
||||||
p->root_desc_location = NULL;
|
|
||||||
free(p->http_request);
|
|
||||||
p->http_request = NULL;
|
|
||||||
free(p->http_response);
|
|
||||||
p->http_response = NULL;
|
|
||||||
free(p->control_cif_url);
|
|
||||||
p->control_cif_url = NULL;
|
|
||||||
free(p->control_conn_url);
|
|
||||||
p->control_conn_url = NULL;
|
|
||||||
if(p->ssdp_socket >= 0) {
|
if(p->ssdp_socket >= 0) {
|
||||||
close(p->ssdp_socket);
|
close(p->ssdp_socket);
|
||||||
p->ssdp_socket = -1;
|
p->ssdp_socket = -1;
|
||||||
}
|
}
|
||||||
if(p->http_socket >= 0) {
|
while(p->device_list) {
|
||||||
close(p->http_socket);
|
upnpc_device_t * next = p->device_list->next;
|
||||||
p->http_socket = -1;
|
free(p->device_list->root_desc_location);
|
||||||
|
p->device_list->root_desc_location = NULL;
|
||||||
|
free(p->device_list->http_request);
|
||||||
|
p->device_list->http_request = NULL;
|
||||||
|
free(p->device_list->http_response);
|
||||||
|
p->device_list->http_response = NULL;
|
||||||
|
free(p->device_list->control_cif_url);
|
||||||
|
p->device_list->control_cif_url = NULL;
|
||||||
|
free(p->device_list->control_conn_url);
|
||||||
|
p->device_list->control_conn_url = NULL;
|
||||||
|
if(p->device_list->http_socket >= 0) {
|
||||||
|
close(p->device_list->http_socket);
|
||||||
|
p->device_list->http_socket = -1;
|
||||||
}
|
}
|
||||||
ClearNameValueList(&p->soap_response_data);
|
ClearNameValueList(&p->device_list->soap_response_data);
|
||||||
p->state = EFinalized;
|
free(p->device_list);
|
||||||
|
p->device_list = next;
|
||||||
|
}
|
||||||
|
p->state = EUPnPFinalized;
|
||||||
return UPNPC_OK;
|
return UPNPC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int upnpc_get_external_ip_address(upnpc_t * p)
|
int upnpc_get_external_ip_address(upnpc_device_t * p)
|
||||||
{
|
{
|
||||||
upnpc_build_soap_request(p, p->control_conn_url,
|
upnpc_build_soap_request(p, p->control_conn_url,
|
||||||
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||||
"GetExternalIPAddress", NULL, 0);
|
"GetExternalIPAddress", NULL, 0);
|
||||||
p->state = ESoapConnect;
|
p->state = EDevSoapConnect;
|
||||||
upnpc_connect(p, p->control_conn_url);
|
upnpc_connect(p, p->control_conn_url);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int upnpc_get_link_layer_max_rate(upnpc_t * p)
|
int upnpc_get_link_layer_max_rate(upnpc_device_t * p)
|
||||||
{
|
{
|
||||||
upnpc_build_soap_request(p, p->control_cif_url,
|
upnpc_build_soap_request(p, p->control_cif_url,
|
||||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
|
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
|
||||||
"GetCommonLinkProperties", NULL, 0);
|
"GetCommonLinkProperties", NULL, 0);
|
||||||
p->state = ESoapConnect;
|
p->state = EDevSoapConnect;
|
||||||
upnpc_connect(p, p->control_conn_url);
|
upnpc_connect(p, p->control_conn_url);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int upnpc_add_port_mapping(upnpc_t * p,
|
int upnpc_add_port_mapping(upnpc_device_t * p,
|
||||||
const char * remote_host, unsigned short ext_port,
|
const char * remote_host, unsigned short ext_port,
|
||||||
unsigned short int_port, const char * int_client,
|
unsigned short int_port, const char * int_client,
|
||||||
const char * proto, const char * description,
|
const char * proto, const char * description,
|
||||||
|
@ -868,7 +898,7 @@ int upnpc_add_port_mapping(upnpc_t * p,
|
||||||
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||||
"AddPortMapping",
|
"AddPortMapping",
|
||||||
args, 8);
|
args, 8);
|
||||||
p->state = ESoapConnect;
|
p->state = EDevSoapConnect;
|
||||||
upnpc_connect(p, p->control_conn_url);
|
upnpc_connect(p, p->control_conn_url);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -876,42 +906,69 @@ int upnpc_add_port_mapping(upnpc_t * p,
|
||||||
#ifdef UPNPC_USE_SELECT
|
#ifdef UPNPC_USE_SELECT
|
||||||
int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds)
|
int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds)
|
||||||
{
|
{
|
||||||
|
upnpc_device_t * d;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
if(!p) return UPNPC_ERR_INVALID_ARGS;
|
if(!p) return UPNPC_ERR_INVALID_ARGS;
|
||||||
|
for(d = p->device_list; d != NULL; d = d->next) {
|
||||||
|
switch(d->state) {
|
||||||
|
case EDevGetDescConnect:
|
||||||
|
case EDevGetDescRequest:
|
||||||
|
case EDevSoapConnect:
|
||||||
|
case EDevSoapRequest:
|
||||||
|
FD_SET(d->http_socket, writefds);
|
||||||
|
if(*nfds < d->http_socket)
|
||||||
|
*nfds = d->http_socket;
|
||||||
|
n++;
|
||||||
|
break;
|
||||||
|
case EDevGetDescResponse:
|
||||||
|
case EDevSoapResponse:
|
||||||
|
FD_SET(d->http_socket, readfds);
|
||||||
|
if(*nfds < d->http_socket)
|
||||||
|
*nfds = d->http_socket;
|
||||||
|
n++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch(p->state) {
|
switch(p->state) {
|
||||||
case ESendSSDP:
|
case EUPnPSendSSDP:
|
||||||
FD_SET(p->ssdp_socket, writefds);
|
FD_SET(p->ssdp_socket, writefds);
|
||||||
if(*nfds < p->ssdp_socket)
|
if(*nfds < p->ssdp_socket)
|
||||||
*nfds = p->ssdp_socket;
|
*nfds = p->ssdp_socket;
|
||||||
n++;
|
n++;
|
||||||
break;
|
break;
|
||||||
case EReceiveSSDP:
|
case EUPnPReceiveSSDP:
|
||||||
|
default:
|
||||||
|
/* still receive SSDP responses when processing Description, etc. */
|
||||||
FD_SET(p->ssdp_socket, readfds);
|
FD_SET(p->ssdp_socket, readfds);
|
||||||
if(*nfds < p->ssdp_socket)
|
if(*nfds < p->ssdp_socket)
|
||||||
*nfds = p->ssdp_socket;
|
*nfds = p->ssdp_socket;
|
||||||
n++;
|
n++;
|
||||||
break;
|
break;
|
||||||
case EGetDescConnect:
|
|
||||||
case EGetDescRequest:
|
|
||||||
case ESoapConnect:
|
|
||||||
case ESoapRequest:
|
|
||||||
FD_SET(p->http_socket, writefds);
|
|
||||||
if(*nfds < p->http_socket)
|
|
||||||
*nfds = p->http_socket;
|
|
||||||
n++;
|
|
||||||
break;
|
|
||||||
case EGetDescResponse:
|
|
||||||
case ESoapResponse:
|
|
||||||
FD_SET(p->http_socket, readfds);
|
|
||||||
if(*nfds < p->http_socket)
|
|
||||||
*nfds = p->http_socket;
|
|
||||||
n++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void upnpc_check_select_fds(upnpc_t * p, const fd_set * readfds, const fd_set * writefds)
|
||||||
|
{
|
||||||
|
upnpc_device_t * d;
|
||||||
|
|
||||||
|
p->socket_flags = 0;
|
||||||
|
if(FD_ISSET(p->ssdp_socket, readfds))
|
||||||
|
p->socket_flags = UPNPC_SSDP_READABLE;
|
||||||
|
if(FD_ISSET(p->ssdp_socket, writefds))
|
||||||
|
p->socket_flags = UPNPC_SSDP_WRITEABLE;
|
||||||
|
|
||||||
|
for(d = p->device_list; d != NULL; d = d->next) {
|
||||||
|
d->socket_flags = 0;
|
||||||
|
if(FD_ISSET(d->http_socket, readfds))
|
||||||
|
d->socket_flags = UPNPC_HTTP_READABLE;
|
||||||
|
if(FD_ISSET(d->http_socket, writefds))
|
||||||
|
d->socket_flags = UPNPC_HTTP_WRITEABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char * devices_to_search[] = {
|
static const char * devices_to_search[] = {
|
||||||
|
@ -924,6 +981,7 @@ static const char * devices_to_search[] = {
|
||||||
|
|
||||||
int upnpc_process(upnpc_t * p)
|
int upnpc_process(upnpc_t * p)
|
||||||
{
|
{
|
||||||
|
upnpc_device_t * d;
|
||||||
/*
|
/*
|
||||||
1) Envoyer les paquets de discovery SSDP
|
1) Envoyer les paquets de discovery SSDP
|
||||||
2) Recevoir et traiter les reponses
|
2) Recevoir et traiter les reponses
|
||||||
|
@ -931,31 +989,51 @@ int upnpc_process(upnpc_t * p)
|
||||||
4) tester les etats
|
4) tester les etats
|
||||||
*/
|
*/
|
||||||
if(!p) return UPNPC_ERR_INVALID_ARGS;
|
if(!p) return UPNPC_ERR_INVALID_ARGS;
|
||||||
debug_printf("state=%d\n", (int)p->state);
|
debug_printf("state=%d socket_flags=0x%04x\n", (int)p->state, p->socket_flags);
|
||||||
switch(p->state) {
|
|
||||||
case EInit:
|
for(d = p->device_list; d != NULL; d = d->next) {
|
||||||
upnpc_send_ssdp_msearch(p, devices_to_search[0], 2);
|
switch(d->state) {
|
||||||
|
case EDevGetDescConnect:
|
||||||
|
case EDevSoapConnect:
|
||||||
|
upnpc_complete_connect(d);
|
||||||
break;
|
break;
|
||||||
case ESendSSDP:
|
case EDevGetDescRequest:
|
||||||
upnpc_send_ssdp_msearch(p, devices_to_search[0], 2);
|
case EDevSoapRequest:
|
||||||
|
upnpc_send_request(d);
|
||||||
break;
|
break;
|
||||||
case EReceiveSSDP:
|
case EDevGetDescResponse:
|
||||||
|
case EDevSoapResponse:
|
||||||
|
upnpc_get_response(d);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* all devices ready => ready */
|
||||||
|
if(p->device_list != NULL) {
|
||||||
|
d = p->device_list;
|
||||||
|
while(d && d->state == EDevReady) d = d->next;
|
||||||
|
p->state = (d == NULL) ? EUPnPReady : EUPnPProcessing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(p->socket_flags & UPNPC_SSDP_READABLE) {
|
||||||
upnpc_receive_and_parse_ssdp(p);
|
upnpc_receive_and_parse_ssdp(p);
|
||||||
|
}
|
||||||
|
switch(p->state) {
|
||||||
|
case EUPnPInit:
|
||||||
|
upnpc_send_ssdp_msearch(p, devices_to_search[0], 2);
|
||||||
|
break;
|
||||||
|
case EUPnPSendSSDP:
|
||||||
|
upnpc_send_ssdp_msearch(p, devices_to_search[0], 2);
|
||||||
|
break;
|
||||||
|
case EUPnPReceiveSSDP:
|
||||||
|
/*upnpc_receive_and_parse_ssdp(p);*/
|
||||||
break;
|
break;
|
||||||
/*case EGetDesc:
|
/*case EGetDesc:
|
||||||
upnpc_connect(p);
|
upnpc_connect(p);
|
||||||
break;*/
|
break;*/
|
||||||
case EGetDescConnect:
|
case EUPnPReady:
|
||||||
case ESoapConnect:
|
case EUPnPProcessing:
|
||||||
upnpc_complete_connect(p);
|
|
||||||
break;
|
|
||||||
case EGetDescRequest:
|
|
||||||
case ESoapRequest:
|
|
||||||
upnpc_send_request(p);
|
|
||||||
break;
|
|
||||||
case EGetDescResponse:
|
|
||||||
case ESoapResponse:
|
|
||||||
upnpc_get_response(p);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return UPNPC_ERR_UNKNOWN_STATE;
|
return UPNPC_ERR_UNKNOWN_STATE;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* $Id: miniupnpc-async.h,v 1.13 2014/11/07 11:25:52 nanard Exp $ */
|
/* $Id: miniupnpc-async.h,v 1.13 2014/11/07 11:25:52 nanard Exp $ */
|
||||||
/* miniupnpc-async
|
/* miniupnpc-async
|
||||||
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr>
|
* Copyright (c) 2008-2017, Thomas BERNARD <miniupnp@free.fr>
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
@ -17,6 +17,9 @@
|
||||||
#ifndef MINIUPNPC_ASYNC_H_INCLUDED
|
#ifndef MINIUPNPC_ASYNC_H_INCLUDED
|
||||||
#define MINIUPNPC_ASYNC_H_INCLUDED
|
#define MINIUPNPC_ASYNC_H_INCLUDED
|
||||||
|
|
||||||
|
/* for struct sockaddr_storage */
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include "declspec.h"
|
#include "declspec.h"
|
||||||
#include "upnpreplyparse.h"
|
#include "upnpreplyparse.h"
|
||||||
|
|
||||||
|
@ -30,25 +33,30 @@ extern "C" {
|
||||||
#define UPNPC_ERR_BIND_FAILED (-3)
|
#define UPNPC_ERR_BIND_FAILED (-3)
|
||||||
#define UPNPC_ERR_UNKNOWN_STATE (-4)
|
#define UPNPC_ERR_UNKNOWN_STATE (-4)
|
||||||
|
|
||||||
typedef struct {
|
#define UPNPC_SSDP_READABLE 0x0001
|
||||||
|
#define UPNPC_SSDP_WRITEABLE 0x0100
|
||||||
|
#define UPNPC_HTTP_READABLE 0x0002
|
||||||
|
#define UPNPC_HTTP_WRITEABLE 0x0200
|
||||||
|
|
||||||
|
typedef struct upnpc_device {
|
||||||
|
struct upnpc_device * next;
|
||||||
enum {
|
enum {
|
||||||
EInit = 1,
|
EDevInit = 1,
|
||||||
ESendSSDP,
|
EDevGetDescConnect,
|
||||||
EReceiveSSDP,
|
EDevGetDescRequest,
|
||||||
/*EGetDesc,*/
|
EDevGetDescResponse,
|
||||||
EGetDescConnect,
|
EDevReady,
|
||||||
EGetDescRequest,
|
EDevSoapConnect,
|
||||||
EGetDescResponse,
|
EDevSoapRequest,
|
||||||
EReady,
|
EDevSoapResponse,
|
||||||
ESoapConnect,
|
EDevFinalized = 99,
|
||||||
ESoapRequest,
|
EDevError = 1000
|
||||||
ESoapResponse,
|
|
||||||
EFinalized = 99,
|
|
||||||
EError = 1000
|
|
||||||
} state;
|
} state;
|
||||||
int ssdp_socket;
|
|
||||||
char * root_desc_location;
|
char * root_desc_location;
|
||||||
|
char * control_cif_url;
|
||||||
|
char * control_conn_url;
|
||||||
int http_socket;
|
int http_socket;
|
||||||
|
int socket_flags; /* see UPNPC_*_READABLE, etc. */
|
||||||
char * http_request;
|
char * http_request;
|
||||||
int http_request_len;
|
int http_request_len;
|
||||||
int http_request_sent;
|
int http_request_sent;
|
||||||
|
@ -58,20 +66,36 @@ typedef struct {
|
||||||
int http_response_content_length;
|
int http_response_content_length;
|
||||||
int http_response_chunked;
|
int http_response_chunked;
|
||||||
int http_response_code;
|
int http_response_code;
|
||||||
char * control_cif_url;
|
|
||||||
char * control_conn_url;
|
|
||||||
struct NameValueParserData soap_response_data;
|
struct NameValueParserData soap_response_data;
|
||||||
|
struct sockaddr_storage selfaddr;
|
||||||
|
socklen_t selfaddrlen;
|
||||||
|
} upnpc_device_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum {
|
||||||
|
EUPnPInit = 1,
|
||||||
|
EUPnPSendSSDP,
|
||||||
|
EUPnPReceiveSSDP,
|
||||||
|
EUPnPGetDesc,
|
||||||
|
EUPnPReady,
|
||||||
|
EUPnPProcessing,
|
||||||
|
EUPnPFinalized = 99,
|
||||||
|
EUPnPError = 1000
|
||||||
|
} state;
|
||||||
|
int socket_flags; /* see UPNPC_*_READABLE, etc. */
|
||||||
|
int ssdp_socket;
|
||||||
|
upnpc_device_t * device_list;
|
||||||
} upnpc_t;
|
} upnpc_t;
|
||||||
|
|
||||||
int upnpc_init(upnpc_t * p, const char * multicastif);
|
int upnpc_init(upnpc_t * p, const char * multicastif);
|
||||||
|
|
||||||
int upnpc_finalize(upnpc_t * p);
|
int upnpc_finalize(upnpc_t * p);
|
||||||
|
|
||||||
int upnpc_get_external_ip_address(upnpc_t * p);
|
int upnpc_get_external_ip_address(upnpc_device_t * p);
|
||||||
|
|
||||||
int upnpc_get_link_layer_max_rate(upnpc_t * p);
|
int upnpc_get_link_layer_max_rate(upnpc_device_t * p);
|
||||||
|
|
||||||
int upnpc_add_port_mapping(upnpc_t * p,
|
int upnpc_add_port_mapping(upnpc_device_t * p,
|
||||||
const char * remote_host, unsigned short ext_port,
|
const char * remote_host, unsigned short ext_port,
|
||||||
unsigned short int_port, const char * int_client,
|
unsigned short int_port, const char * int_client,
|
||||||
const char * proto, const char * description,
|
const char * proto, const char * description,
|
||||||
|
@ -79,6 +103,7 @@ int upnpc_add_port_mapping(upnpc_t * p,
|
||||||
|
|
||||||
#ifdef UPNPC_USE_SELECT
|
#ifdef UPNPC_USE_SELECT
|
||||||
int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds);
|
int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds);
|
||||||
|
void upnpc_check_select_fds(upnpc_t * p, const fd_set * readfds, const fd_set * writefds);
|
||||||
#endif /* UPNPC_USE_SELECT */
|
#endif /* UPNPC_USE_SELECT */
|
||||||
|
|
||||||
int upnpc_process(upnpc_t * p);
|
int upnpc_process(upnpc_t * p);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* $Id: testasync.c,v 1.14 2014/11/07 12:07:38 nanard Exp $ */
|
/* $Id: testasync.c,v 1.14 2014/11/07 12:07:38 nanard Exp $ */
|
||||||
/* miniupnpc-async
|
/* miniupnpc-async
|
||||||
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr>
|
* Copyright (c) 2008-2017, Thomas BERNARD <miniupnp@free.fr>
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
@ -17,6 +17,10 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
/* for getnameinfo() : */
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
/* compile with -DUPNPC_USE_SELECT to enable upnpc_select_fds() function */
|
/* compile with -DUPNPC_USE_SELECT to enable upnpc_select_fds() function */
|
||||||
#include "miniupnpc-async.h"
|
#include "miniupnpc-async.h"
|
||||||
#include "upnpreplyparse.h"
|
#include "upnpreplyparse.h"
|
||||||
|
@ -30,8 +34,10 @@ enum methods {
|
||||||
|
|
||||||
int main(int argc, char * * argv)
|
int main(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
|
char ip_address[64];
|
||||||
int r, n;
|
int r, n;
|
||||||
upnpc_t upnp;
|
upnpc_t upnp;
|
||||||
|
upnpc_device_t * device = NULL;
|
||||||
const char * multicastif = NULL;
|
const char * multicastif = NULL;
|
||||||
enum methods next_method_to_call = EGetExternalIP;
|
enum methods next_method_to_call = EGetExternalIP;
|
||||||
enum methods last_method = ENothing;
|
enum methods last_method = ENothing;
|
||||||
|
@ -43,7 +49,7 @@ int main(int argc, char * * argv)
|
||||||
}
|
}
|
||||||
r = upnpc_process(&upnp);
|
r = upnpc_process(&upnp);
|
||||||
printf("upnpc_process returned %d\n", r);
|
printf("upnpc_process returned %d\n", r);
|
||||||
while((upnp.state != EReady) && (upnp.state != EError)) {
|
while(upnp.state != EUPnPError) {
|
||||||
int nfds;
|
int nfds;
|
||||||
fd_set readfds;
|
fd_set readfds;
|
||||||
fd_set writefds;
|
fd_set writefds;
|
||||||
|
@ -68,26 +74,31 @@ int main(int argc, char * * argv)
|
||||||
perror("select");
|
perror("select");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
upnpc_check_select_fds(&upnp, &readfds, &writefds);
|
||||||
r = upnpc_process(&upnp);
|
r = upnpc_process(&upnp);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
printf("upnpc_process returned %d\n", r);
|
printf("upnpc_process returned %d\n", r);
|
||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
if(r < 0)
|
if(r < 0)
|
||||||
break;
|
break;
|
||||||
if(upnp.state == EReady) {
|
if(upnp.state == EUPnPReady) {
|
||||||
char * p;
|
char * p;
|
||||||
printf("Process UPnP IGD Method results : HTTP %d\n", upnp.http_response_code);
|
if(device == NULL) {
|
||||||
if(upnp.http_response_code == 200) {
|
/* select one device */
|
||||||
|
device = upnp.device_list; /* pick up the first one */
|
||||||
|
}
|
||||||
|
printf("Process UPnP IGD Method results : HTTP %d\n", device->http_response_code);
|
||||||
|
if(device->http_response_code == 200) {
|
||||||
switch(last_method) {
|
switch(last_method) {
|
||||||
case EGetExternalIP:
|
case EGetExternalIP:
|
||||||
p = GetValueFromNameValueList(&upnp.soap_response_data, "NewExternalIPAddress");
|
p = GetValueFromNameValueList(&device->soap_response_data, "NewExternalIPAddress");
|
||||||
printf("ExternalIPAddress = %s\n", p);
|
printf("ExternalIPAddress = %s\n", p);
|
||||||
/* p = GetValueFromNameValueList(&pdata, "errorCode");*/
|
/* p = GetValueFromNameValueList(&pdata, "errorCode");*/
|
||||||
break;
|
break;
|
||||||
case EGetRates:
|
case EGetRates:
|
||||||
p = GetValueFromNameValueList(&upnp.soap_response_data, "NewLayer1DownstreamMaxBitRate");
|
p = GetValueFromNameValueList(&device->soap_response_data, "NewLayer1DownstreamMaxBitRate");
|
||||||
printf("DownStream MaxBitRate = %s\t", p);
|
printf("DownStream MaxBitRate = %s\t", p);
|
||||||
p = GetValueFromNameValueList(&upnp.soap_response_data, "NewLayer1UpstreamMaxBitRate");
|
p = GetValueFromNameValueList(&device->soap_response_data, "NewLayer1UpstreamMaxBitRate");
|
||||||
printf("UpStream MaxBitRate = %s\n", p);
|
printf("UpStream MaxBitRate = %s\n", p);
|
||||||
break;
|
break;
|
||||||
case EAddPortMapping:
|
case EAddPortMapping:
|
||||||
|
@ -98,10 +109,10 @@ int main(int argc, char * * argv)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("SOAP error :\n");
|
printf("SOAP error :\n");
|
||||||
printf(" faultcode='%s'\n", GetValueFromNameValueList(&upnp.soap_response_data, "faultcode"));
|
printf(" faultcode='%s'\n", GetValueFromNameValueList(&device->soap_response_data, "faultcode"));
|
||||||
printf(" faultstring='%s'\n", GetValueFromNameValueList(&upnp.soap_response_data, "faultstring"));
|
printf(" faultstring='%s'\n", GetValueFromNameValueList(&device->soap_response_data, "faultstring"));
|
||||||
printf(" errorCode=%s\n", GetValueFromNameValueList(&upnp.soap_response_data, "errorCode"));
|
printf(" errorCode=%s\n", GetValueFromNameValueList(&device->soap_response_data, "errorCode"));
|
||||||
printf(" errorDescription='%s'\n", GetValueFromNameValueList(&upnp.soap_response_data, "errorDescription"));
|
printf(" errorDescription='%s'\n", GetValueFromNameValueList(&device->soap_response_data, "errorDescription"));
|
||||||
}
|
}
|
||||||
if(next_method_to_call == ENothing)
|
if(next_method_to_call == ENothing)
|
||||||
break;
|
break;
|
||||||
|
@ -110,19 +121,24 @@ int main(int argc, char * * argv)
|
||||||
switch(next_method_to_call) {
|
switch(next_method_to_call) {
|
||||||
case EGetExternalIP:
|
case EGetExternalIP:
|
||||||
printf("GetExternalIPAddress\n");
|
printf("GetExternalIPAddress\n");
|
||||||
upnpc_get_external_ip_address(&upnp);
|
upnpc_get_external_ip_address(device);
|
||||||
next_method_to_call = EGetRates;
|
next_method_to_call = EGetRates;
|
||||||
break;
|
break;
|
||||||
case EGetRates:
|
case EGetRates:
|
||||||
printf("GetCommonLinkProperties\n");
|
printf("GetCommonLinkProperties\n");
|
||||||
upnpc_get_link_layer_max_rate(&upnp);
|
upnpc_get_link_layer_max_rate(device);
|
||||||
next_method_to_call = EAddPortMapping;
|
next_method_to_call = EAddPortMapping;
|
||||||
break;
|
break;
|
||||||
case EAddPortMapping:
|
case EAddPortMapping:
|
||||||
|
if(getnameinfo((struct sockaddr *)&device->selfaddr, device->selfaddrlen,
|
||||||
|
ip_address, sizeof(ip_address), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
|
||||||
|
fprintf(stderr, "getnameinfo() failed\n");
|
||||||
|
}
|
||||||
|
printf("our IP address is %s\n", ip_address);
|
||||||
printf("AddPortMapping\n");
|
printf("AddPortMapping\n");
|
||||||
upnpc_add_port_mapping(&upnp,
|
upnpc_add_port_mapping(device,
|
||||||
NULL /* remote_host */, 40002 /* ext_port */,
|
NULL /* remote_host */, 40002 /* ext_port */,
|
||||||
42042 /* int_port */, "192.168.1.202" /* int_client */,
|
42042 /* int_port */, ip_address /* int_client */,
|
||||||
"TCP" /* proto */, "this is a test" /* description */,
|
"TCP" /* proto */, "this is a test" /* description */,
|
||||||
0 /* lease duration */);
|
0 /* lease duration */);
|
||||||
next_method_to_call = ENothing;
|
next_method_to_call = ENothing;
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
$Id: Changelog.txt,v 1.226 2016/12/16 08:57:19 nanard Exp $
|
$Id: Changelog.txt,v 1.226 2016/12/16 08:57:19 nanard Exp $
|
||||||
miniUPnP client Changelog.
|
miniUPnP client Changelog.
|
||||||
|
|
||||||
|
2017/05/05:
|
||||||
|
Fix CVE-2017-8798 Thanks to tin/Team OSTStrom
|
||||||
|
|
||||||
2016/11/11:
|
2016/11/11:
|
||||||
check strlen before memcmp in XML parsing portlistingparse.c
|
check strlen before memcmp in XML parsing portlistingparse.c
|
||||||
fix build under SOLARIS and CYGWIN
|
fix build under SOLARIS and CYGWIN
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* Project : miniupnp
|
/* Project : miniupnp
|
||||||
* Website : http://miniupnp.free.fr/
|
* Website : http://miniupnp.free.fr/
|
||||||
* Author : Thomas Bernard
|
* Author : Thomas Bernard
|
||||||
* Copyright (c) 2005-2016 Thomas Bernard
|
* Copyright (c) 2005-2017 Thomas Bernard
|
||||||
* This software is subject to the conditions detailed in the
|
* This software is subject to the conditions detailed in the
|
||||||
* LICENCE file provided in this distribution. */
|
* LICENCE file provided in this distribution. */
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ getHTTPResponse(int s, int * size, int * status_code)
|
||||||
chunksize_buf[0] = '\0';
|
chunksize_buf[0] = '\0';
|
||||||
chunksize_buf_index = 0;
|
chunksize_buf_index = 0;
|
||||||
|
|
||||||
while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0)
|
while((n = receivedata(s, buf, sizeof(buf), 5000, NULL)) > 0)
|
||||||
{
|
{
|
||||||
if(endofheaders == 0)
|
if(endofheaders == 0)
|
||||||
{
|
{
|
||||||
|
@ -284,11 +284,12 @@ getHTTPResponse(int s, int * size, int * status_code)
|
||||||
goto end_of_stream;
|
goto end_of_stream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i);
|
/* it is guaranteed that (n >= i) */
|
||||||
|
bytestocopy = (chunksize < (unsigned int)(n - i))?chunksize:(unsigned int)(n - i);
|
||||||
if((content_buf_used + bytestocopy) > content_buf_len)
|
if((content_buf_used + bytestocopy) > content_buf_len)
|
||||||
{
|
{
|
||||||
char * tmp;
|
char * tmp;
|
||||||
if(content_length >= (int)(content_buf_used + bytestocopy)) {
|
if((content_length >= 0) && ((unsigned int)content_length >= (content_buf_used + bytestocopy))) {
|
||||||
content_buf_len = content_length;
|
content_buf_len = content_length;
|
||||||
} else {
|
} else {
|
||||||
content_buf_len = content_buf_used + bytestocopy;
|
content_buf_len = content_buf_used + bytestocopy;
|
||||||
|
@ -313,14 +314,15 @@ getHTTPResponse(int s, int * size, int * status_code)
|
||||||
{
|
{
|
||||||
/* not chunked */
|
/* not chunked */
|
||||||
if(content_length > 0
|
if(content_length > 0
|
||||||
&& (int)(content_buf_used + n) > content_length) {
|
&& (content_buf_used + n) > (unsigned int)content_length) {
|
||||||
/* skipping additional bytes */
|
/* skipping additional bytes */
|
||||||
n = content_length - content_buf_used;
|
n = content_length - content_buf_used;
|
||||||
}
|
}
|
||||||
if(content_buf_used + n > content_buf_len)
|
if(content_buf_used + n > content_buf_len)
|
||||||
{
|
{
|
||||||
char * tmp;
|
char * tmp;
|
||||||
if(content_length >= (int)(content_buf_used + n)) {
|
if(content_length >= 0
|
||||||
|
&& (unsigned int)content_length >= (content_buf_used + n)) {
|
||||||
content_buf_len = content_length;
|
content_buf_len = content_length;
|
||||||
} else {
|
} else {
|
||||||
content_buf_len = content_buf_used + n;
|
content_buf_len = content_buf_used + n;
|
||||||
|
@ -340,7 +342,7 @@ getHTTPResponse(int s, int * size, int * status_code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* use the Content-Length header value if available */
|
/* use the Content-Length header value if available */
|
||||||
if(content_length > 0 && (int)content_buf_used >= content_length)
|
if(content_length > 0 && content_buf_used >= (unsigned int)content_length)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf("End of HTTP content\n");
|
printf("End of HTTP content\n");
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: upnpc.c,v 1.114 2016/01/22 15:04:23 nanard Exp $ */
|
/* $Id: upnpc.c,v 1.117 2017/05/26 15:26:55 nanard Exp $ */
|
||||||
/* Project : miniupnp
|
/* Project : miniupnp
|
||||||
* Author : Thomas Bernard
|
* Author : Thomas Bernard
|
||||||
* Copyright (c) 2005-2016 Thomas Bernard
|
* Copyright (c) 2005-2017 Thomas Bernard
|
||||||
* This software is subject to the conditions detailed in the
|
* This software is subject to the conditions detailed in the
|
||||||
* LICENCE file provided in this distribution. */
|
* LICENCE file provided in this distribution. */
|
||||||
|
|
||||||
|
@ -578,8 +578,8 @@ int main(int argc, char ** argv)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
|
printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
|
||||||
printf(" (c) 2005-2016 Thomas Bernard.\n");
|
printf(" (c) 2005-2017 Thomas Bernard.\n");
|
||||||
printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n"
|
printf("Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/\n"
|
||||||
"for more information.\n");
|
"for more information.\n");
|
||||||
/* command line processing */
|
/* command line processing */
|
||||||
for(i=1; i<argc; i++)
|
for(i=1; i<argc; i++)
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
$Id: Changelog.txt,v 1.430 2016/12/16 09:14:40 nanard Exp $
|
$Id: Changelog.txt,v 1.432 2017/05/24 22:47:53 nanard Exp $
|
||||||
|
|
||||||
|
2017/05/24:
|
||||||
|
get SSDP packet receiving interface index and use it to check if the
|
||||||
|
packet is from a LAN
|
||||||
|
|
||||||
2017/03/13:
|
2017/03/13:
|
||||||
default to client address for AddPortMapping when <NewInternalClient>
|
default to client address for AddPortMapping when <NewInternalClient>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
MiniUPnP project.
|
MiniUPnP project.
|
||||||
(c) 2006-2016 Thomas Bernard
|
(c) 2006-2017 Thomas Bernard
|
||||||
Homepage : http://miniupnp.free.fr/
|
Homepage : http://miniupnp.free.fr/
|
||||||
Mirror: http://miniupnp.tuxfamily.org/
|
Mirror: https://miniupnp.tuxfamily.org/
|
||||||
github: https://github.com/miniupnp/miniupnp
|
github: https://github.com/miniupnp/miniupnp
|
||||||
|
|
||||||
miniupnpd is still under active developpement. This documentation is
|
miniupnpd is still under active developpement. This documentation is
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
MiniUPnPd
|
MiniUPnPd
|
||||||
Copyright (c) 2006-2016, Thomas BERNARD
|
Copyright (c) 2006-2017, Thomas BERNARD
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
MiniUPnP project
|
MiniUPnP project
|
||||||
(c) 2006-2016 Thomas Bernard
|
(c) 2006-2017 Thomas Bernard
|
||||||
webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
webpage: http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
|
||||||
github: https://github.com/miniupnp/miniupnp
|
github: https://github.com/miniupnp/miniupnp
|
||||||
freecode: http://freecode.com/projects/miniupnp
|
freecode: http://freecode.com/projects/miniupnp
|
||||||
contact: miniupnp@free.fr
|
contact: miniupnp@free.fr
|
||||||
|
@ -31,7 +31,7 @@ Read the INSTALL file for instructions to compile, install and
|
||||||
configure miniupnpd on your system.
|
configure miniupnpd on your system.
|
||||||
|
|
||||||
Report bugs to miniupnp@free.fr or on the web forum
|
Report bugs to miniupnp@free.fr or on the web forum
|
||||||
http://miniupnp.tuxfamily.org/forum/
|
https://miniupnp.tuxfamily.org/forum/
|
||||||
or using https://github.com/miniupnp/miniupnp/issues
|
or using https://github.com/miniupnp/miniupnp/issues
|
||||||
|
|
||||||
Thomas Bernard
|
Thomas Bernard
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: minissdp.c,v 1.77 2015/08/26 07:36:52 nanard Exp $ */
|
/* $Id: minissdp.c,v 1.87 2017/05/24 22:33:33 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2006-2017 Thomas Bernard
|
* (c) 2006-2017 Thomas Bernard
|
||||||
|
@ -16,6 +16,13 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
|
#ifdef IP_RECVIF
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#if defined(ENABLE_IPV6) && defined(UPNP_STRICT)
|
#if defined(ENABLE_IPV6) && defined(UPNP_STRICT)
|
||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
|
@ -153,7 +160,7 @@ OpenAndConfSSDPReceiveSocket(int ipv6)
|
||||||
struct sockaddr_storage sockname;
|
struct sockaddr_storage sockname;
|
||||||
socklen_t sockname_len;
|
socklen_t sockname_len;
|
||||||
struct lan_addr_s * lan_addr;
|
struct lan_addr_s * lan_addr;
|
||||||
int j = 1;
|
const int on = 1;
|
||||||
|
|
||||||
if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0)
|
if( (s = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0)) < 0)
|
||||||
{
|
{
|
||||||
|
@ -185,10 +192,36 @@ OpenAndConfSSDPReceiveSocket(int ipv6)
|
||||||
sockname_len = sizeof(struct sockaddr_in);
|
sockname_len = sizeof(struct sockaddr_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j)) < 0)
|
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
|
||||||
{
|
{
|
||||||
syslog(LOG_WARNING, "setsockopt(udp, SO_REUSEADDR): %m");
|
syslog(LOG_WARNING, "setsockopt(udp, SO_REUSEADDR): %m");
|
||||||
}
|
}
|
||||||
|
#ifdef IP_RECVIF
|
||||||
|
/* BSD */
|
||||||
|
if(!ipv6) {
|
||||||
|
if(setsockopt(s, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING, "setsockopt(udp, IP_RECVIF): %m");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* IP_RECVIF */
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
/* Linux */
|
||||||
|
if(!ipv6) {
|
||||||
|
if(setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING, "setsockopt(udp, IP_PKTINFO): %m");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* IP_PKTINFO */
|
||||||
|
#if defined(ENABLE_IPV6) && defined(IPV6_RECVPKTINFO)
|
||||||
|
if(ipv6) {
|
||||||
|
if(setsockopt(s, IPPROTO_IP, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING, "setsockopt(udp, IPV6_RECVPKTINFO): %m");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* defined(ENABLE_IPV6) && defined(IPV6_RECVPKTINFO) */
|
||||||
|
|
||||||
if(!set_non_blocking(s))
|
if(!set_non_blocking(s))
|
||||||
{
|
{
|
||||||
|
@ -814,17 +847,53 @@ ProcessSSDPRequest(int s, unsigned short http_port)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
char bufr[1500];
|
char bufr[1500];
|
||||||
socklen_t len_r;
|
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
struct sockaddr_storage sendername;
|
struct sockaddr_storage sendername;
|
||||||
len_r = sizeof(struct sockaddr_storage);
|
|
||||||
#else
|
#else
|
||||||
struct sockaddr_in sendername;
|
struct sockaddr_in sendername;
|
||||||
len_r = sizeof(struct sockaddr_in);
|
|
||||||
#endif
|
#endif
|
||||||
|
int source_ifindex = -1;
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
char cmbuf[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||||
|
struct iovec iovec = {
|
||||||
|
.iov_base = bufr,
|
||||||
|
.iov_len = sizeof(bufr)
|
||||||
|
};
|
||||||
|
struct msghdr mh = {
|
||||||
|
.msg_name = &sendername,
|
||||||
|
.msg_namelen = sizeof(sendername),
|
||||||
|
.msg_iov = &iovec,
|
||||||
|
.msg_iovlen = 1,
|
||||||
|
.msg_control = cmbuf,
|
||||||
|
.msg_controllen = sizeof(cmbuf)
|
||||||
|
};
|
||||||
|
struct cmsghdr *cmptr;
|
||||||
|
#endif /* IP_PKTINFO */
|
||||||
|
#ifdef IP_RECVIF
|
||||||
|
char cmbuf[CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
||||||
|
struct iovec iovec = {
|
||||||
|
.iov_base = bufr,
|
||||||
|
.iov_len = sizeof(bufr)
|
||||||
|
};
|
||||||
|
struct msghdr mh = {
|
||||||
|
.msg_name = &sendername,
|
||||||
|
.msg_namelen = sizeof(sendername),
|
||||||
|
.msg_iov = &iovec,
|
||||||
|
.msg_iovlen = 1,
|
||||||
|
.msg_control = cmbuf,
|
||||||
|
.msg_controllen = sizeof(cmbuf)
|
||||||
|
};
|
||||||
|
struct cmsghdr *cmptr;
|
||||||
|
#endif /* IP_RECVIF */
|
||||||
|
|
||||||
|
#if defined(IP_RECVIF) || defined(IP_PKTINFO)
|
||||||
|
n = recvmsg(s, &mh, 0);
|
||||||
|
#else
|
||||||
|
socklen_t len_r;
|
||||||
|
len_r = sizeof(sendername);
|
||||||
n = recvfrom(s, bufr, sizeof(bufr), 0,
|
n = recvfrom(s, bufr, sizeof(bufr), 0,
|
||||||
(struct sockaddr *)&sendername, &len_r);
|
(struct sockaddr *)&sendername, &len_r);
|
||||||
|
#endif /* defined(IP_RECVIF) || defined(IP_PKTINFO) */
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
{
|
{
|
||||||
/* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time)
|
/* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time)
|
||||||
|
@ -837,11 +906,45 @@ ProcessSSDPRequest(int s, unsigned short http_port)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(IP_RECVIF) || defined(IP_PKTINFO)
|
||||||
|
for(cmptr = CMSG_FIRSTHDR(&mh); cmptr != NULL; cmptr = CMSG_NXTHDR(&mh, cmptr))
|
||||||
|
{
|
||||||
|
syslog(LOG_DEBUG, "level=%d type=%d", cmptr->cmsg_level, cmptr->cmsg_type);
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
if(cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
|
{
|
||||||
|
struct in_pktinfo * pi; /* fields : ifindex, spec_dst, addr */
|
||||||
|
pi = (struct in_pktinfo *)CMSG_DATA(cmptr);
|
||||||
|
syslog(LOG_DEBUG, "ifindex = %u %s", pi->ipi_ifindex, inet_ntoa(pi->ipi_spec_dst));
|
||||||
|
source_ifindex = pi->ipi_ifindex;
|
||||||
|
}
|
||||||
|
#endif /* IP_PKTINFO */
|
||||||
|
#if defined(ENABLE_IPV6) && defined(IPV6_RECVPKTINFO)
|
||||||
|
if(cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == IPV6_RECVPKTINFO)
|
||||||
|
{
|
||||||
|
struct in6_pktinfo * pi6; /* fields : ifindex, addr */
|
||||||
|
pi6 = (struct in6_pktinfo *)CMSG_DATA(cmptr);
|
||||||
|
syslog(LOG_DEBUG, "ifindex = %u", pi6->ipi6_ifindex);
|
||||||
|
source_ifindex = pi6->ipi6_ifindex;
|
||||||
|
}
|
||||||
|
#endif /* defined(ENABLE_IPV6) && defined(IPV6_RECVPKTINFO) */
|
||||||
|
#ifdef IP_RECVIF
|
||||||
|
if(cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||||
|
{
|
||||||
|
struct sockaddr_dl *sdl; /* fields : len, family, index, type, nlen, alen, slen, data */
|
||||||
|
sdl = (struct sockaddr_dl *)CMSG_DATA(cmptr);
|
||||||
|
syslog(LOG_DEBUG, "sdl_index = %d %s", sdl->sdl_index, link_ntoa(sdl));
|
||||||
|
source_ifindex = sdl->sdl_index;
|
||||||
|
}
|
||||||
|
#endif /* IP_RECVIF */
|
||||||
|
}
|
||||||
|
#endif /* defined(IP_RECVIF) || defined(IP_PKTINFO) */
|
||||||
#ifdef ENABLE_HTTPS
|
#ifdef ENABLE_HTTPS
|
||||||
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername,
|
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, source_ifindex,
|
||||||
http_port, https_port);
|
http_port, https_port);
|
||||||
#else
|
#else
|
||||||
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername,
|
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, source_ifindex,
|
||||||
http_port);
|
http_port);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -850,12 +953,12 @@ ProcessSSDPRequest(int s, unsigned short http_port)
|
||||||
#ifdef ENABLE_HTTPS
|
#ifdef ENABLE_HTTPS
|
||||||
void
|
void
|
||||||
ProcessSSDPData(int s, const char *bufr, int n,
|
ProcessSSDPData(int s, const char *bufr, int n,
|
||||||
const struct sockaddr * sender,
|
const struct sockaddr * sender, int source_if,
|
||||||
unsigned short http_port, unsigned short https_port)
|
unsigned short http_port, unsigned short https_port)
|
||||||
#else
|
#else
|
||||||
void
|
void
|
||||||
ProcessSSDPData(int s, const char *bufr, int n,
|
ProcessSSDPData(int s, const char *bufr, int n,
|
||||||
const struct sockaddr * sender,
|
const struct sockaddr * sender, int source_if,
|
||||||
unsigned short http_port)
|
unsigned short http_port)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -889,10 +992,31 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
||||||
/* get the string representation of the sender address */
|
/* get the string representation of the sender address */
|
||||||
sockaddr_to_string(sender, sender_str, sizeof(sender_str));
|
sockaddr_to_string(sender, sender_str, sizeof(sender_str));
|
||||||
lan_addr = get_lan_for_peer(sender);
|
lan_addr = get_lan_for_peer(sender);
|
||||||
|
if(source_if >= 0)
|
||||||
|
{
|
||||||
|
if(lan_addr != NULL)
|
||||||
|
{
|
||||||
|
if(lan_addr->index != (unsigned)source_if)
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING, "interface index not matching %u != %d", lan_addr->index, source_if);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* use the interface index */
|
||||||
|
for(lan_addr = lan_addrs.lh_first;
|
||||||
|
lan_addr != NULL;
|
||||||
|
lan_addr = lan_addr->list.le_next)
|
||||||
|
{
|
||||||
|
if(lan_addr->index == (unsigned)source_if)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if(lan_addr == NULL)
|
if(lan_addr == NULL)
|
||||||
{
|
{
|
||||||
syslog(LOG_WARNING, "SSDP packet sender %s not from a LAN, ignoring",
|
syslog(LOG_WARNING, "SSDP packet sender %s (if_index=%d) not from a LAN, ignoring",
|
||||||
sender_str);
|
sender_str, source_if);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: minissdp.h,v 1.12 2014/04/09 07:20:59 nanard Exp $ */
|
/* $Id: minissdp.h,v 1.12 2014/04/09 07:20:59 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2006-2014 Thomas Bernard
|
* (c) 2006-2017 Thomas Bernard
|
||||||
* This software is subject to the conditions detailed
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
#ifndef MINISSDP_H_INCLUDED
|
#ifndef MINISSDP_H_INCLUDED
|
||||||
|
@ -39,12 +39,12 @@ ProcessSSDPRequest(int s, unsigned short http_port);
|
||||||
#ifdef ENABLE_HTTPS
|
#ifdef ENABLE_HTTPS
|
||||||
void
|
void
|
||||||
ProcessSSDPData(int s, const char *bufr, int n,
|
ProcessSSDPData(int s, const char *bufr, int n,
|
||||||
const struct sockaddr * sendername,
|
const struct sockaddr * sendername, int source_if,
|
||||||
unsigned short http_port, unsigned short https_port);
|
unsigned short http_port, unsigned short https_port);
|
||||||
#else
|
#else
|
||||||
void
|
void
|
||||||
ProcessSSDPData(int s, const char *bufr, int n,
|
ProcessSSDPData(int s, const char *bufr, int n,
|
||||||
const struct sockaddr * sendername,
|
const struct sockaddr * sendername, int source_if,
|
||||||
unsigned short http_port);
|
unsigned short http_port);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -631,7 +631,7 @@ static int nfqueue_cb(
|
||||||
|
|
||||||
/* printf("pkt found %s\n",dd);*/
|
/* printf("pkt found %s\n",dd);*/
|
||||||
ProcessSSDPData (sudp, dd, size - x,
|
ProcessSSDPData (sudp, dd, size - x,
|
||||||
&sendername, (unsigned short) 5555);
|
&sendername, -1, (unsigned short) 5555);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -984,7 +984,6 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_IPV6
|
|
||||||
if(lan_addr->ifname[0] != '\0')
|
if(lan_addr->ifname[0] != '\0')
|
||||||
{
|
{
|
||||||
lan_addr->index = if_nametoindex(lan_addr->ifname);
|
lan_addr->index = if_nametoindex(lan_addr->ifname);
|
||||||
|
@ -992,6 +991,7 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str)
|
||||||
fprintf(stderr, "Cannot get index for network interface %s",
|
fprintf(stderr, "Cannot get index for network interface %s",
|
||||||
lan_addr->ifname);
|
lan_addr->ifname);
|
||||||
}
|
}
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
|
|
@ -16,9 +16,7 @@
|
||||||
* with ascii representation and mask */
|
* with ascii representation and mask */
|
||||||
struct lan_addr_s {
|
struct lan_addr_s {
|
||||||
char ifname[IFNAMSIZ]; /* example: eth0 */
|
char ifname[IFNAMSIZ]; /* example: eth0 */
|
||||||
#ifdef ENABLE_IPV6
|
|
||||||
unsigned int index; /* use if_nametoindex() */
|
unsigned int index; /* use if_nametoindex() */
|
||||||
#endif
|
|
||||||
char str[16]; /* example: 192.168.0.1 */
|
char str[16]; /* example: 192.168.0.1 */
|
||||||
struct in_addr addr, mask; /* ip/mask */
|
struct in_addr addr, mask; /* ip/mask */
|
||||||
#ifdef MULTIPLE_EXTERNAL_IP
|
#ifdef MULTIPLE_EXTERNAL_IP
|
||||||
|
|
Loading…
Reference in New Issue