Merge branch 'master' into search_all
Conflicts: miniupnpc/.gitignore miniupnpc/Makefile miniupnpc/miniupnpc.c
This commit is contained in:
commit
9325bacbfc
3
README
3
README
|
@ -46,4 +46,5 @@ Thanks to :
|
|||
* Peter Tatrai
|
||||
* Leo Moll
|
||||
* Daniel Becker
|
||||
* Yonetani Tomokazu
|
||||
* Yonetani Tomokazu
|
||||
* Markus Stenberg
|
||||
|
|
|
@ -1,4 +1,15 @@
|
|||
$Id: Changelog.txt,v 1.33 2014/02/03 15:45:07 nanard Exp $
|
||||
$Id: Changelog.txt,v 1.36 2014/11/06 10:13:36 nanard Exp $
|
||||
|
||||
2014/11/06:
|
||||
listen on only 1 IPv4 if only 1 interface is specified
|
||||
also when ENABLE_IPV6 is not defined
|
||||
|
||||
2014/09/06:
|
||||
freebsd-glue for Debian/kFreeBSD
|
||||
use LDFLAGS when linking binary
|
||||
|
||||
2014/05/01:
|
||||
listen on only 1 IPv4 if only 1 interface is specified
|
||||
|
||||
2014/02/03:
|
||||
silently ignore EAGAIN, EWOULDBLOCK, EINTR of recv calls
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $Id: Makefile,v 1.18 2014/02/03 14:32:14 nanard Exp $
|
||||
# $Id: Makefile,v 1.19 2014/06/10 10:00:18 nanard Exp $
|
||||
# MiniUPnP project
|
||||
# author: Thomas Bernard
|
||||
# website: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
|
@ -53,7 +53,11 @@ ifneq ($(OS), Darwin)
|
|||
endif
|
||||
|
||||
minissdpd: $(MINISSDPDOBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(MINISSDPDOBJS)
|
||||
if [ "$(DEB_BUILD_ARCH_OS)" = "kfreebsd" ] ; then \
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -lfreebsd-glue -o $@ $(MINISSDPDOBJS) ; \
|
||||
else \
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(MINISSDPDOBJS) ; \
|
||||
fi
|
||||
|
||||
testminissdpd: $(TESTMINISSDPDOBJS)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: minissdpd.c,v 1.37 2014/02/28 18:39:11 nanard Exp $ */
|
||||
/* $Id: minissdpd.c,v 1.39 2014/11/06 10:13:06 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* (c) 2007-2014 Thomas Bernard
|
||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
|
@ -261,6 +261,7 @@ processMSEARCH(int s, const char * st, int st_len,
|
|||
ntohs(((const struct sockaddr_in *)addr)->sin_port),
|
||||
st_len, st);
|
||||
#endif
|
||||
/* TODO : ignore packet if not coming from a LAN */
|
||||
if(st_len==8 && (0==memcmp(st, "ssdp:all", 8))) {
|
||||
/* send a response for all services */
|
||||
for(serv = servicelisthead.lh_first;
|
||||
|
@ -875,7 +876,9 @@ int main(int argc, char * * argv)
|
|||
const char * sockpath = "/var/run/minissdpd.sock";
|
||||
const char * pidfilename = "/var/run/minissdpd.pid";
|
||||
int debug_flag = 0;
|
||||
#ifdef ENABLE_IPV6
|
||||
int ipv6 = 0;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
int deltadev = 0;
|
||||
struct sockaddr_in sendername;
|
||||
socklen_t sendername_len;
|
||||
|
@ -909,8 +912,12 @@ int main(int argc, char * * argv)
|
|||
if(n_if_addr < 1)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s [-d] [-6] [-s socket] [-p pidfile] "
|
||||
"-i <interface> [-i <interface2>] ...\n",
|
||||
"Usage: %s [-d] "
|
||||
#ifdef ENABLE_IPV6
|
||||
"[-6] "
|
||||
#endif
|
||||
"[-s socket] [-p pidfile] "
|
||||
"-i <interface> [-i <interface2>] ...\n",
|
||||
argv[0]);
|
||||
fprintf(stderr,
|
||||
"\n <interface> is either an IPv4 address such as 192.168.1.42, or an\ninterface name such as eth0.\n");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $Id: openssdpsocket.c,v 1.12 2012/05/21 17:13:11 nanard Exp $ */
|
||||
/* $Id: openssdpsocket.c,v 1.14 2014/11/06 10:13:36 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2012 Thomas Bernard
|
||||
* (c) 2006-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
|
@ -81,7 +81,9 @@ AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
|||
#ifdef ENABLE_IPV6
|
||||
struct ipv6_mreq mr;
|
||||
unsigned int ifindex;
|
||||
#endif
|
||||
#else /* ENABLE_IPV6 */
|
||||
(void)ipv6;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
if(s <= 0)
|
||||
return -1; /* nothing to do */
|
||||
|
@ -115,10 +117,10 @@ AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
|||
else
|
||||
{
|
||||
#endif
|
||||
/* setting up imr structure */
|
||||
imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
||||
/*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/
|
||||
/*imr.imr_interface.s_addr = inet_addr(ifaddr);*/
|
||||
/* setting up imr structure */
|
||||
imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
||||
/*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/
|
||||
/*imr.imr_interface.s_addr = inet_addr(ifaddr);*/
|
||||
imr.imr_interface.s_addr = GetIfAddrIPv4(ifaddr);
|
||||
if(imr.imr_interface.s_addr == INADDR_NONE)
|
||||
{
|
||||
|
@ -130,11 +132,11 @@ AddDropMulticastMembership(int s, const char * ifaddr, int ipv6, int drop)
|
|||
if (setsockopt(s, IPPROTO_IP, drop ? IP_DROP_MEMBERSHIP : IP_ADD_MEMBERSHIP,
|
||||
(void *)&imr, sizeof(struct ip_mreq)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "setsockopt(udp, %s)(%s): %m",
|
||||
syslog(LOG_ERR, "setsockopt(udp, %s)(%s): %m",
|
||||
drop ? "IP_DROP_MEMBERSHIP" : "IP_ADD_MEMBERSHIP",
|
||||
ifaddr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_IPV6
|
||||
}
|
||||
#endif
|
||||
|
@ -182,27 +184,48 @@ OpenAndConfSSDPReceiveSocket(int n_listen_addr,
|
|||
}
|
||||
#endif
|
||||
struct sockaddr_in6 * sa = (struct sockaddr_in6 *)&sockname;
|
||||
sa->sin6_family = AF_INET6;
|
||||
sa->sin6_port = htons(SSDP_PORT);
|
||||
sa->sin6_family = AF_INET6;
|
||||
sa->sin6_port = htons(SSDP_PORT);
|
||||
sa->sin6_addr = in6addr_any;
|
||||
sockname_len = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct sockaddr_in * sa = (struct sockaddr_in *)&sockname;
|
||||
sa->sin_family = AF_INET;
|
||||
sa->sin_port = htons(SSDP_PORT);
|
||||
sa->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
sa->sin_family = AF_INET;
|
||||
sa->sin_port = htons(SSDP_PORT);
|
||||
if(n_listen_addr == 1)
|
||||
{
|
||||
sa->sin_addr.s_addr = GetIfAddrIPv4(listen_addr[0]);
|
||||
if(sa->sin_addr.s_addr == INADDR_NONE)
|
||||
{
|
||||
syslog(LOG_ERR, "no IPv4 address for interface %s",
|
||||
listen_addr[0]);
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
sa->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
sockname_len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
#else
|
||||
memset(&sockname, 0, sizeof(struct sockaddr_in));
|
||||
sockname.sin_family = AF_INET;
|
||||
sockname.sin_port = htons(SSDP_PORT);
|
||||
/* NOTE : it seems it doesnt work when binding on the specific address */
|
||||
/*sockname.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/
|
||||
sockname.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
/*sockname.sin_addr.s_addr = inet_addr(ifaddr);*/
|
||||
if(n_listen_addr == 1)
|
||||
{
|
||||
sockname.sin_addr.s_addr = GetIfAddrIPv4(listen_addr[0]);
|
||||
if(sockname.sin_addr.s_addr == INADDR_NONE)
|
||||
{
|
||||
syslog(LOG_ERR, "no IPv4 address for interface %s",
|
||||
listen_addr[0]);
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
sockname.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
sockname_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
*.a
|
||||
*.o
|
||||
testasync
|
|
@ -0,0 +1,4 @@
|
|||
$Id: Changelog.txt,v 1.1 2009/11/12 14:04:33 nanard Exp $
|
||||
|
||||
initial version...
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
# $Id: Makefile,v 1.9 2014/11/04 22:25:00 nanard Exp $
|
||||
# MiniUPnP Project
|
||||
# http://miniupnp.free.fr/
|
||||
# (c) 2005-2014 Thomas Bernard
|
||||
# to install use :
|
||||
# $ PREFIX=/tmp/dummylocation make install
|
||||
# or
|
||||
# $ INSTALLPREFIX=/usr/local make install
|
||||
# or
|
||||
# make install (will go to /usr/bin, /usr/lib, etc...)
|
||||
CC = gcc
|
||||
#AR = gar
|
||||
CFLAGS = -O0 -g -DDEBUG
|
||||
#CFLAGS = -O
|
||||
CFLAGS += -fPIC
|
||||
CFLAGS += -ansi
|
||||
CFLAGS += -Wall -W
|
||||
CFLAGS += -D_BSD_SOURCE
|
||||
CFLAGS += -DUPNPC_USE_SELECT
|
||||
INSTALL = install
|
||||
#following libs are needed on Solaris
|
||||
#LDLIBS=-lsocket -lnsl -lresolv
|
||||
|
||||
# APIVERSION is used to build SONAME
|
||||
APIVERSION = 0
|
||||
|
||||
SRCS = miniupnpc-async.c parsessdpreply.c \
|
||||
upnputils.c igd_desc_parse.c minixml.c \
|
||||
upnpreplyparse.c \
|
||||
testasync.c
|
||||
|
||||
LIBOBJS = miniupnpc-async.o parsessdpreply.o \
|
||||
upnputils.o igd_desc_parse.o minixml.o \
|
||||
upnpreplyparse.o
|
||||
|
||||
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||
|
||||
# HEADERS to install
|
||||
HEADERS = miniupnpc-async.h
|
||||
LIBRARY = libminiupnpc-async.a
|
||||
SHAREDLIBRARY = libminiupnpc-async.so
|
||||
SONAME = $(SHAREDLIBRARY).$(APIVERSION)
|
||||
EXECUTABLES = testasync
|
||||
|
||||
INSTALLPREFIX ?= $(PREFIX)/usr
|
||||
INSTALLDIRINC = $(INSTALLPREFIX)/include/miniupnpc
|
||||
INSTALLDIRLIB = $(INSTALLPREFIX)/lib
|
||||
INSTALLDIRBIN = $(INSTALLPREFIX)/bin
|
||||
|
||||
.PHONY: install clean depend all installpythonmodule
|
||||
|
||||
all: $(LIBRARY) $(EXECUTABLES)
|
||||
|
||||
pythonmodule: $(LIBRARY) miniupnpcmodule.c setup.py
|
||||
python setup.py build
|
||||
touch $@
|
||||
|
||||
installpythonmodule: pythonmodule
|
||||
python setup.py install
|
||||
|
||||
clean:
|
||||
$(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS)
|
||||
# clean python stuff
|
||||
$(RM) pythonmodule
|
||||
$(RM) -r build/ dist/
|
||||
#python setup.py clean
|
||||
|
||||
install: $(LIBRARY) $(SHAREDLIBRARY)
|
||||
$(INSTALL) -d $(INSTALLDIRINC)
|
||||
$(INSTALL) -m 644 $(HEADERS) $(INSTALLDIRINC)
|
||||
$(INSTALL) -d $(INSTALLDIRLIB)
|
||||
$(INSTALL) -m 644 $(LIBRARY) $(INSTALLDIRLIB)
|
||||
$(INSTALL) -m 644 $(SHAREDLIBRARY) $(INSTALLDIRLIB)/$(SONAME)
|
||||
$(INSTALL) -m 755 upnpc-shared $(INSTALLDIRBIN)/upnpc
|
||||
ln -fs $(SONAME) $(INSTALLDIRLIB)/$(SHAREDLIBRARY)
|
||||
|
||||
cleaninstall:
|
||||
$(RM) -r $(INSTALLDIRINC)
|
||||
$(RM) $(INSTALLDIRLIB)/$(LIBRARY)
|
||||
$(RM) $(INSTALLDIRLIB)/$(SHAREDLIBRARY)
|
||||
|
||||
depend:
|
||||
makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null
|
||||
|
||||
$(LIBRARY): $(LIBOBJS)
|
||||
$(AR) crs $@ $?
|
||||
|
||||
$(SHAREDLIBRARY): $(LIBOBJS)
|
||||
$(CC) -shared -Wl,-soname,$(SONAME) -o $@ $^
|
||||
|
||||
upnpc-static: upnpc.o $(LIBRARY)
|
||||
$(CC) -o $@ $^
|
||||
|
||||
upnpc-shared: upnpc.o $(SHAREDLIBRARY)
|
||||
$(CC) -o $@ $^
|
||||
|
||||
#testasync: testasync.o libminiupnpc-async.a
|
||||
testasync: testasync.o -lminiupnpc-async
|
||||
|
||||
# DO NOT DELETE THIS LINE -- make depend depends on it.
|
||||
|
||||
miniupnpc-async.o: miniupnpc-async.h declspec.h parsessdpreply.h upnputils.h
|
||||
parsessdpreply.o: parsessdpreply.h
|
||||
testasync.o: miniupnpc-async.h declspec.h
|
|
@ -0,0 +1,10 @@
|
|||
(c) 2014 Thomas BERNARD
|
||||
http://miniupnp.free.fr/
|
||||
https://github.com/miniupnp/miniupnp
|
||||
|
||||
miniupnpc-async :
|
||||
proof of concept of a UPnP IGD client using asynchronous socket calls
|
||||
(ie non blocking sockets)
|
||||
|
||||
To be reimplemented using libevent2 (http://libevent.org/)
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
/* $Id: config.h,v 1.1 2012/05/20 14:58:50 nanard Exp $ */
|
||||
#ifndef __CONFIG_H__
|
||||
#define __CONFIG_H__
|
||||
|
||||
#endif
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef __DECLSPEC_H__
|
||||
#define __DECLSPEC_H__
|
||||
|
||||
#if defined(WIN32) && !defined(STATICLIB)
|
||||
#ifdef MINIUPNP_EXPORTS
|
||||
#define LIBSPEC __declspec(dllexport)
|
||||
#else
|
||||
#define LIBSPEC __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define LIBSPEC
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/* $Id: igd_desc_parse.c,v 1.15 2014/07/01 13:01:17 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include "igd_desc_parse.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Start element handler :
|
||||
* update nesting level counter and copy element name */
|
||||
void IGDstartelt(void * d, const char * name, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
memcpy( datas->cureltname, name, l);
|
||||
datas->cureltname[l] = '\0';
|
||||
datas->level++;
|
||||
if( (l==7) && !memcmp(name, "service", l) ) {
|
||||
datas->tmp.controlurl[0] = '\0';
|
||||
datas->tmp.eventsuburl[0] = '\0';
|
||||
datas->tmp.scpdurl[0] = '\0';
|
||||
datas->tmp.servicetype[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
|
||||
|
||||
/* End element handler :
|
||||
* update nesting level counter and update parser state if
|
||||
* service element is parsed */
|
||||
void IGDendelt(void * d, const char * name, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
datas->level--;
|
||||
/*printf("endelt %2d %.*s\n", datas->level, l, name);*/
|
||||
if( (l==7) && !memcmp(name, "service", l) )
|
||||
{
|
||||
if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) {
|
||||
memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) {
|
||||
memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:")
|
||||
|| COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:") ) {
|
||||
if(datas->first.servicetype[0] == '\0') {
|
||||
memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else {
|
||||
memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Data handler :
|
||||
* copy data depending on the current element name and state */
|
||||
void IGDdata(void * d, const char * data, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
char * dstmember = 0;
|
||||
/*printf("%2d %s : %.*s\n",
|
||||
datas->level, datas->cureltname, l, data); */
|
||||
if( !strcmp(datas->cureltname, "URLBase") )
|
||||
dstmember = datas->urlbase;
|
||||
else if( !strcmp(datas->cureltname, "presentationURL") )
|
||||
dstmember = datas->presentationurl;
|
||||
else if( !strcmp(datas->cureltname, "serviceType") )
|
||||
dstmember = datas->tmp.servicetype;
|
||||
else if( !strcmp(datas->cureltname, "controlURL") )
|
||||
dstmember = datas->tmp.controlurl;
|
||||
else if( !strcmp(datas->cureltname, "eventSubURL") )
|
||||
dstmember = datas->tmp.eventsuburl;
|
||||
else if( !strcmp(datas->cureltname, "SCPDURL") )
|
||||
dstmember = datas->tmp.scpdurl;
|
||||
/* else if( !strcmp(datas->cureltname, "deviceType") )
|
||||
dstmember = datas->devicetype_tmp;*/
|
||||
if(dstmember)
|
||||
{
|
||||
if(l>=MINIUPNPC_URL_MAXSIZE)
|
||||
l = MINIUPNPC_URL_MAXSIZE-1;
|
||||
memcpy(dstmember, data, l);
|
||||
dstmember[l] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void printIGD(struct IGDdatas * d)
|
||||
{
|
||||
printf("urlbase = '%s'\n", d->urlbase);
|
||||
printf("WAN Device (Common interface config) :\n");
|
||||
/*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/
|
||||
printf(" serviceType = '%s'\n", d->CIF.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->CIF.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->CIF.scpdurl);
|
||||
printf("primary WAN Connection Device (IP or PPP Connection):\n");
|
||||
/*printf(" deviceType = '%s'\n", d->first.devicetype);*/
|
||||
printf(" servicetype = '%s'\n", d->first.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->first.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->first.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->first.scpdurl);
|
||||
printf("secondary WAN Connection Device (IP or PPP Connection):\n");
|
||||
/*printf(" deviceType = '%s'\n", d->second.devicetype);*/
|
||||
printf(" servicetype = '%s'\n", d->second.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->second.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->second.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->second.scpdurl);
|
||||
printf("WAN IPv6 Firewall Control :\n");
|
||||
/*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/
|
||||
printf(" servicetype = '%s'\n", d->IPv6FC.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->IPv6FC.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/* $Id: igd_desc_parse.h,v 1.11 2012/10/16 16:49:02 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2010 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef IGD_DESC_PARSE_H_INCLUDED
|
||||
#define IGD_DESC_PARSE_H_INCLUDED
|
||||
|
||||
/* Structure to store the result of the parsing of UPnP
|
||||
* descriptions of Internet Gateway Devices */
|
||||
#define MINIUPNPC_URL_MAXSIZE (128)
|
||||
struct IGDdatas_service {
|
||||
char controlurl[MINIUPNPC_URL_MAXSIZE];
|
||||
char eventsuburl[MINIUPNPC_URL_MAXSIZE];
|
||||
char scpdurl[MINIUPNPC_URL_MAXSIZE];
|
||||
char servicetype[MINIUPNPC_URL_MAXSIZE];
|
||||
/*char devicetype[MINIUPNPC_URL_MAXSIZE];*/
|
||||
};
|
||||
|
||||
struct IGDdatas {
|
||||
char cureltname[MINIUPNPC_URL_MAXSIZE];
|
||||
char urlbase[MINIUPNPC_URL_MAXSIZE];
|
||||
char presentationurl[MINIUPNPC_URL_MAXSIZE];
|
||||
int level;
|
||||
/*int state;*/
|
||||
/* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
|
||||
struct IGDdatas_service CIF;
|
||||
/* "urn:schemas-upnp-org:service:WANIPConnection:1"
|
||||
* "urn:schemas-upnp-org:service:WANPPPConnection:1" */
|
||||
struct IGDdatas_service first;
|
||||
/* if both WANIPConnection and WANPPPConnection are present */
|
||||
struct IGDdatas_service second;
|
||||
/* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */
|
||||
struct IGDdatas_service IPv6FC;
|
||||
/* tmp */
|
||||
struct IGDdatas_service tmp;
|
||||
};
|
||||
|
||||
void IGDstartelt(void *, const char *, int);
|
||||
void IGDendelt(void *, const char *, int);
|
||||
void IGDdata(void *, const char *, int);
|
||||
void printIGD(struct IGDdatas *);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,963 @@
|
|||
/* $Id: miniupnpc-async.c,v 1.19 2014/11/07 12:05:40 nanard Exp $ */
|
||||
/* miniupnpc-async
|
||||
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr>
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#define PRINT_SOCKET_ERROR printf
|
||||
#define SOCKET_ERROR GetWSALastError()
|
||||
#define WOULDBLOCK(err) (err == WSAEWOULDBLOCK)
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#define closesocket close
|
||||
#define PRINT_SOCKET_ERROR perror
|
||||
#define SOCKET_ERROR errno
|
||||
#define WOULDBLOCK(err) (err == EAGAIN || err == EWOULDBLOCK)
|
||||
#endif
|
||||
#include "miniupnpc-async.h"
|
||||
#include "parsessdpreply.h"
|
||||
#include "upnputils.h"
|
||||
#include "minixml.h"
|
||||
#include "igd_desc_parse.h"
|
||||
#include "upnpreplyparse.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||
#endif /* MIN */
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif /* MAXHOSTNAMELEN */
|
||||
|
||||
#define SSDP_PORT 1900
|
||||
#define SSDP_MCAST_ADDR "239.255.255.250"
|
||||
#define XSTR(s) STR(s)
|
||||
#define STR(s) #s
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug_printf(...) fprintf(stderr, __VA_ARGS__)
|
||||
#else
|
||||
#define debug_printf(...)
|
||||
#endif
|
||||
|
||||
/* stuctures */
|
||||
|
||||
struct upnp_args {
|
||||
const char * elt;
|
||||
const char * val;
|
||||
};
|
||||
|
||||
/* private functions */
|
||||
|
||||
static int upnpc_connect(upnpc_t * p, const char * url);
|
||||
static int upnpc_send_request(upnpc_t * p);
|
||||
|
||||
|
||||
/* parse_msearch_reply()
|
||||
* the last 4 arguments are filled during the parsing :
|
||||
* - location/locationsize : "location:" field of the SSDP reply packet
|
||||
* - st/stsize : "st:" field of the SSDP reply packet.
|
||||
* The strings are NOT null terminated */
|
||||
static void
|
||||
parse_msearch_reply(const char * reply, int size,
|
||||
const char * * location, int * locationsize,
|
||||
const char * * st, int * stsize)
|
||||
{
|
||||
int a, b, i;
|
||||
i = 0; /* current character index */
|
||||
a = i; /* start of the line */
|
||||
b = 0; /* end of the "header" (position of the colon) */
|
||||
while(i<size) {
|
||||
switch(reply[i]) {
|
||||
case ':':
|
||||
if(b==0) {
|
||||
b = i; /* end of the "header" */
|
||||
}
|
||||
break;
|
||||
case '\x0a':
|
||||
case '\x0d':
|
||||
if(b!=0) {
|
||||
/* skip the colon and white spaces */
|
||||
do { b++; } while(reply[b]==' ' && b<size);
|
||||
if(0==strncasecmp(reply+a, "location", 8)) {
|
||||
*location = reply+b;
|
||||
*locationsize = i-b;
|
||||
} else if(0==strncasecmp(reply+a, "st", 2)) {
|
||||
*st = reply+b;
|
||||
*stsize = i-b;
|
||||
}
|
||||
b = 0;
|
||||
}
|
||||
a = i+1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
static int upnpc_send_ssdp_msearch(upnpc_t * p, const char * device, unsigned int mx)
|
||||
{
|
||||
/* envoyer les packets de M-SEARCH discovery sur le socket ssdp */
|
||||
int n;
|
||||
char bufr[1024];
|
||||
struct sockaddr_in addr;
|
||||
static const char MSearchMsgFmt[] =
|
||||
"M-SEARCH * HTTP/1.1\r\n"
|
||||
"HOST: " SSDP_MCAST_ADDR ":" XSTR(SSDP_PORT) "\r\n"
|
||||
"ST: %s\r\n"
|
||||
"MAN: \"ssdp:discover\"\r\n"
|
||||
"MX: %u\r\n"
|
||||
"\r\n";
|
||||
|
||||
memset(&addr, 0, sizeof(struct sockaddr_in));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(SSDP_PORT);
|
||||
addr.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
||||
n = snprintf(bufr, sizeof(bufr),
|
||||
MSearchMsgFmt, device, mx);
|
||||
debug_printf("upnpc_send_ssdp_msearch: %s", bufr);
|
||||
n = sendto(p->ssdp_socket, bufr, n, 0,
|
||||
(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
|
||||
if (n < 0) {
|
||||
int err = SOCKET_ERROR;
|
||||
if(err == EINTR || WOULDBLOCK(err)) {
|
||||
debug_printf("upnpc_send_ssdp_msearch: should try again");
|
||||
p->state = ESendSSDP;
|
||||
return 0;
|
||||
}
|
||||
PRINT_SOCKET_ERROR("sendto");
|
||||
return -1;
|
||||
}
|
||||
p->state = EReceiveSSDP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int upnpc_set_root_desc_location(upnpc_t * p, const char * location, int locationsize)
|
||||
{
|
||||
char * tmp;
|
||||
tmp = realloc(p->root_desc_location, locationsize + 1);
|
||||
if(tmp == 0) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(tmp, location, locationsize);
|
||||
tmp[locationsize] = '\0';
|
||||
p->root_desc_location = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int upnpc_receive_and_parse_ssdp(upnpc_t * p)
|
||||
{
|
||||
int n;
|
||||
char bufr[1024];
|
||||
n = recv(p->ssdp_socket, bufr, sizeof(bufr), 0);
|
||||
if (n<0) {
|
||||
PRINT_SOCKET_ERROR("recv");
|
||||
} else if (n==0) {
|
||||
debug_printf("empty packet received\n");
|
||||
} else {
|
||||
const char * location = NULL;
|
||||
int locationsize;
|
||||
const char * st = NULL;
|
||||
int stsize;
|
||||
debug_printf("%.*s", n, bufr);
|
||||
parse_msearch_reply(bufr, n, &location, &locationsize, &st, &stsize);
|
||||
debug_printf("location = '%.*s'\n", locationsize, location);
|
||||
debug_printf("st = '%.*s'\n", stsize, st);
|
||||
if(location != NULL) {
|
||||
if(upnpc_set_root_desc_location(p, location, locationsize) < 0) {
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
p->state = EGetDescConnect;
|
||||
upnpc_connect(p, p->root_desc_location);
|
||||
} else {
|
||||
/* or do nothing ? */
|
||||
p->state = EError;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parseURL(const char * url,
|
||||
char * hostname, unsigned short * port,
|
||||
char * * path, unsigned int * scope_id)
|
||||
{
|
||||
char * p1, *p2, *p3;
|
||||
if(!url)
|
||||
return 0;
|
||||
p1 = strstr(url, "://");
|
||||
if(!p1)
|
||||
return 0;
|
||||
p1 += 3;
|
||||
if( (url[0]!='h') || (url[1]!='t')
|
||||
||(url[2]!='t') || (url[3]!='p'))
|
||||
return 0;
|
||||
memset(hostname, 0, MAXHOSTNAMELEN + 1);
|
||||
if(*p1 == '[') {
|
||||
/* IP v6 : http://[2a00:1450:8002::6a]/path/abc */
|
||||
char * scope;
|
||||
scope = strchr(p1, '%');
|
||||
p2 = strchr(p1, ']');
|
||||
if(p2 && scope && scope < p2 && scope_id) {
|
||||
/* parse scope */
|
||||
#ifdef IF_NAMESIZE
|
||||
char tmp[IF_NAMESIZE];
|
||||
int l;
|
||||
scope++;
|
||||
/* "%25" is just '%' in URL encoding */
|
||||
if(scope[0] == '2' && scope[1] == '5')
|
||||
scope += 2; /* skip "25" */
|
||||
l = p2 - scope;
|
||||
if(l >= IF_NAMESIZE)
|
||||
l = IF_NAMESIZE - 1;
|
||||
memcpy(tmp, scope, l);
|
||||
tmp[l] = '\0';
|
||||
*scope_id = if_nametoindex(tmp);
|
||||
if(*scope_id == 0) {
|
||||
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
|
||||
}
|
||||
#else
|
||||
/* under windows, scope is numerical */
|
||||
char tmp[8];
|
||||
int l;
|
||||
scope++;
|
||||
/* "%25" is just '%' in URL encoding */
|
||||
if(scope[0] == '2' && scope[1] == '5')
|
||||
scope += 2; /* skip "25" */
|
||||
l = p2 - scope;
|
||||
if(l >= (int)sizeof(tmp))
|
||||
l = sizeof(tmp) - 1;
|
||||
memcpy(tmp, scope, l);
|
||||
tmp[l] = '\0';
|
||||
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
|
||||
#endif
|
||||
}
|
||||
p3 = strchr(p1, '/');
|
||||
if(p2 && p3) {
|
||||
p2++;
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
|
||||
if(*p2 == ':') {
|
||||
*port = 0;
|
||||
p2++;
|
||||
while( (*p2 >= '0') && (*p2 <= '9')) {
|
||||
*port *= 10;
|
||||
*port += (unsigned short)(*p2 - '0');
|
||||
p2++;
|
||||
}
|
||||
} else {
|
||||
*port = 80;
|
||||
}
|
||||
*path = p3;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
p2 = strchr(p1, ':');
|
||||
p3 = strchr(p1, '/');
|
||||
if(!p3)
|
||||
return 0;
|
||||
if(!p2 || (p2>p3)) {
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1)));
|
||||
*port = 80;
|
||||
} else {
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
|
||||
*port = 0;
|
||||
p2++;
|
||||
while( (*p2 >= '0') && (*p2 <= '9')) {
|
||||
*port *= 10;
|
||||
*port += (unsigned short)(*p2 - '0');
|
||||
p2++;
|
||||
}
|
||||
}
|
||||
*path = p3;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int upnpc_connect(upnpc_t * p, const char * url)
|
||||
{
|
||||
int r;
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
unsigned short port;
|
||||
char * path;
|
||||
unsigned int scope_id;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
if(p->root_desc_location == 0) {
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
if(!parseURL(url/*p->root_desc_location*/, hostname, &port,
|
||||
&path, &scope_id)) {
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
p->http_socket = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if(p->http_socket < 0) {
|
||||
PRINT_SOCKET_ERROR("socket");
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
if(!set_non_blocking(p->http_socket)) {
|
||||
/* TODO : ERROR */
|
||||
}
|
||||
memset(&addr, 0, sizeof(struct sockaddr_in));
|
||||
addr.sin_family = AF_INET;
|
||||
inet_pton(AF_INET, hostname, &(addr.sin_addr));
|
||||
addr.sin_port = htons(port);
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
do {
|
||||
r = connect(p->http_socket, (struct sockaddr *)&addr, addrlen);
|
||||
if(r < 0) {
|
||||
if(errno == EINPROGRESS) {
|
||||
/*p->state = EGetDescConnect;*/
|
||||
return 0;
|
||||
} else if(errno != EINTR) {
|
||||
PRINT_SOCKET_ERROR("connect");
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} while(r < 0 && errno == EINTR);
|
||||
if(p->state == EGetDescConnect) {
|
||||
p->state = EGetDescRequest;
|
||||
} else {
|
||||
p->state = ESoapRequest;
|
||||
}
|
||||
upnpc_send_request(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int upnpc_complete_connect(upnpc_t * p)
|
||||
{
|
||||
socklen_t len;
|
||||
int err;
|
||||
len = sizeof(err);
|
||||
if(getsockopt(p->http_socket, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
|
||||
PRINT_SOCKET_ERROR("getsockopt");
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
if(err != 0) {
|
||||
debug_printf("connect failed %d\n", err);
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
if(p->state == EGetDescConnect)
|
||||
p->state = EGetDescRequest;
|
||||
else
|
||||
p->state = ESoapRequest;
|
||||
upnpc_send_request(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int upnpc_send_request(upnpc_t * p)
|
||||
{
|
||||
ssize_t n;
|
||||
static const char reqfmt[] = "GET %s HTTP/1.1\r\n"
|
||||
"Host: %s:%hu\r\n"
|
||||
"Connection: Close\r\n"
|
||||
"User-Agent: MiniUPnPc-async\r\n"
|
||||
"\r\n";
|
||||
if(p->http_request == NULL) {
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
unsigned short port;
|
||||
char * path;
|
||||
unsigned int scope_id;
|
||||
int len;
|
||||
if(!parseURL(p->root_desc_location, hostname, &port,
|
||||
&path, &scope_id)) {
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
len = snprintf(NULL, 0, reqfmt, path, hostname, port);
|
||||
p->http_request = malloc(len + 1);
|
||||
if(p->http_request == NULL) {
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
p->http_request_len = snprintf(p->http_request, len + 1,
|
||||
reqfmt, path, hostname, port);
|
||||
p->http_request_sent = 0;
|
||||
}
|
||||
n = send(p->http_socket, p->http_request + p->http_request_sent,
|
||||
p->http_request_len - p->http_request_sent, 0/* flags */);
|
||||
if(n < 0) {
|
||||
PRINT_SOCKET_ERROR("send");
|
||||
p->state = EError;
|
||||
return -1;
|
||||
} else {
|
||||
debug_printf("sent %d bytes\n", (int)n);
|
||||
/*if(n == 0) {
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}*/
|
||||
p->http_request_sent += n;
|
||||
if(p->http_request_sent >= p->http_request_len) {
|
||||
/* all bytes sent */
|
||||
#if 0
|
||||
shutdown(p->http_socket, SHUT_WR); /* some routers don't like that */
|
||||
#endif
|
||||
free(p->http_request);
|
||||
p->http_request = NULL;
|
||||
p->http_request_len = 0;
|
||||
if(p->state == EGetDescRequest)
|
||||
p->state = EGetDescResponse;
|
||||
else
|
||||
p->state = ESoapResponse;
|
||||
free(p->http_response);
|
||||
p->http_response = NULL;
|
||||
p->http_response_received = 0;
|
||||
p->http_response_end_of_headers = 0;
|
||||
/* get response */
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int upnpc_parse_headers(upnpc_t * p)
|
||||
{
|
||||
/* search for CR LF CR LF (end of headers)
|
||||
* recognize also LF LF */
|
||||
int i = 0;
|
||||
while(i < (p->http_response_received-1) &&
|
||||
p->http_response_end_of_headers == 0) {
|
||||
if(p->http_response[i] == '\r') {
|
||||
i++;
|
||||
if(p->http_response[i] == '\n') {
|
||||
i++;
|
||||
if(i < p->http_response_received && p->http_response[i] == '\r') {
|
||||
i++;
|
||||
if(i < p->http_response_received && p->http_response[i] == '\n') {
|
||||
p->http_response_end_of_headers = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(p->http_response[i] == '\n') {
|
||||
i++;
|
||||
if(p->http_response[i] == '\n') {
|
||||
p->http_response_end_of_headers = i + 1;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(p->http_response_end_of_headers != 0) {
|
||||
int colon = 0;
|
||||
int linestart = 0;
|
||||
int valuestart = 0;
|
||||
p->http_response_code = -1;
|
||||
for(i = 0; i < p->http_response_end_of_headers - 1; i++) {
|
||||
if(linestart == 0) {
|
||||
/* reading HTTP response code on the 1st line */
|
||||
if(p->http_response[i] == ' ' && p->http_response_code < 0)
|
||||
p->http_response_code = 0;
|
||||
else if(p->http_response[i] >= '0' && p->http_response[i] <= '9') {
|
||||
p->http_response_code = p->http_response_code * 10 + (p->http_response[i] - '0');
|
||||
} else if(p->http_response[i] == ' ')
|
||||
linestart = 1;
|
||||
}
|
||||
if(colon <= linestart && p->http_response[i] == ':') {
|
||||
colon = i;
|
||||
while(i < p->http_response_end_of_headers - 1 &&
|
||||
(p->http_response[i+1] == ' ' || p->http_response[i+1] == '\t'))
|
||||
i++;
|
||||
valuestart = i + 1;
|
||||
} else if(p->http_response[i + 1] == '\r' ||
|
||||
p->http_response[i + 1] == '\n') {
|
||||
if(colon > linestart && valuestart > colon) {
|
||||
debug_printf("header='%.*s', value='%.*s'\n",
|
||||
colon-linestart, p->http_response+linestart,
|
||||
i+1-valuestart, p->http_response+valuestart);
|
||||
if(0==strncasecmp(p->http_response+linestart, "content-length", colon-linestart)) {
|
||||
p->http_response_content_length = atoi(p->http_response + valuestart);
|
||||
debug_printf("Content-Length: %d\n", p->http_response_content_length);
|
||||
if(p->http_response_content_length < 0) {
|
||||
debug_printf("Content-Length overflow ? setting to 0\n");
|
||||
p->http_response_content_length = 0;
|
||||
}
|
||||
} else if(0==strncasecmp(p->http_response+linestart, "transfer-encoding", colon-linestart)
|
||||
&& 0==strncasecmp(p->http_response+valuestart, "chunked", 7)) {
|
||||
debug_printf("Chunked transfer-encoding !\n");
|
||||
p->http_response_chunked = 1;
|
||||
}
|
||||
}
|
||||
/* find next line */
|
||||
while((i < p->http_response_received) &&
|
||||
(p->http_response[i]=='\r' || p->http_response[i] == '\n'))
|
||||
i++;
|
||||
linestart = i;
|
||||
colon = linestart;
|
||||
valuestart = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char * build_url_string(const char * urlbase, const char * root_desc_url, const char * controlurl)
|
||||
{
|
||||
int l, n;
|
||||
char * s;
|
||||
const char * base;
|
||||
char * p;
|
||||
/* if controlurl is an absolute url, return it */
|
||||
if(0 == memcmp("http://", controlurl, 7))
|
||||
return strdup(controlurl);
|
||||
base = (urlbase[0] == '\0') ? root_desc_url : urlbase;
|
||||
n = strlen(base);
|
||||
if(n > 7) {
|
||||
p = strchr(base + 7, '/');
|
||||
if(p)
|
||||
n = p - base;
|
||||
}
|
||||
l = n + strlen(controlurl) + 1;
|
||||
if(controlurl[0] != '/')
|
||||
l++;
|
||||
s = malloc(l);
|
||||
if(s == NULL) return NULL;
|
||||
memcpy(s, base, n);
|
||||
if(controlurl[0] != '/')
|
||||
s[n++] = '/';
|
||||
memcpy(s + n, controlurl, l - n);
|
||||
return s;
|
||||
}
|
||||
|
||||
static int upnpc_get_response(upnpc_t * p)
|
||||
{
|
||||
ssize_t n;
|
||||
ssize_t count;
|
||||
char buffer[2048];
|
||||
if(p->http_response_content_length > 0) {
|
||||
count = p->http_response_content_length
|
||||
+ p->http_response_end_of_headers
|
||||
- p->http_response_received;
|
||||
if(count > (ssize_t)sizeof(buffer)) count = sizeof(buffer);
|
||||
} else {
|
||||
count = sizeof(buffer);
|
||||
}
|
||||
debug_printf("recv(..., %d)\n", (int)count);
|
||||
n = recv(p->http_socket, buffer, count, 0/* flags */);
|
||||
if(n < 0) {
|
||||
if(errno == EINTR || WOULDBLOCK(errno))
|
||||
return 0; /* try again later */
|
||||
PRINT_SOCKET_ERROR("read");
|
||||
p->state = EError;
|
||||
return -1;
|
||||
} else if(n == 0) {
|
||||
/* receiving finished */
|
||||
debug_printf("%.*s\n", p->http_response_received, p->http_response);
|
||||
close(p->http_socket);
|
||||
p->http_socket = -1;
|
||||
/* parse */
|
||||
if(p->http_response_end_of_headers == 0) {
|
||||
upnpc_parse_headers(p);
|
||||
}
|
||||
/* TODO : decode chunked transfer-encoding */
|
||||
/* parse xml */
|
||||
if(p->state == EGetDescResponse) {
|
||||
struct IGDdatas igd;
|
||||
struct xmlparser parser;
|
||||
memset(&igd, 0, sizeof(struct IGDdatas));
|
||||
memset(&parser, 0, sizeof(struct xmlparser));
|
||||
parser.xmlstart = p->http_response + p->http_response_end_of_headers;
|
||||
parser.xmlsize = p->http_response_received - p->http_response_end_of_headers;
|
||||
parser.data = &igd;
|
||||
parser.starteltfunc = IGDstartelt;
|
||||
parser.endeltfunc = IGDendelt;
|
||||
parser.datafunc = IGDdata;
|
||||
parsexml(&parser);
|
||||
#ifdef DEBUG
|
||||
printIGD(&igd);
|
||||
#endif /* DEBUG */
|
||||
p->control_conn_url = build_url_string(igd.urlbase, p->root_desc_location, igd.first.controlurl);
|
||||
p->control_cif_url = build_url_string(igd.urlbase, p->root_desc_location, igd.CIF.controlurl);
|
||||
debug_printf("control_conn_url='%s'\n", p->control_conn_url);
|
||||
debug_printf("control_cif_url='%s'\n", p->control_cif_url);
|
||||
} else {
|
||||
ClearNameValueList(&p->soap_response_data);
|
||||
ParseNameValue(p->http_response + p->http_response_end_of_headers,
|
||||
p->http_response_received - p->http_response_end_of_headers,
|
||||
&p->soap_response_data);
|
||||
}
|
||||
free(p->http_response);
|
||||
p->http_response = NULL;
|
||||
p->http_response_received = 0;
|
||||
p->http_response_end_of_headers = 0;
|
||||
p->state = EReady;
|
||||
} else {
|
||||
/* receiving in progress */
|
||||
debug_printf("received %d bytes:\n%.*s\n", (int)n, (int)n, buffer);
|
||||
if(p->http_response == NULL) {
|
||||
p->http_response = malloc(n);
|
||||
if(p->http_response == NULL) {
|
||||
debug_printf("failed to malloc %d bytes\n", (int)n);
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
p->http_response_received = n;
|
||||
memcpy(p->http_response, buffer, n);
|
||||
} else {
|
||||
char * tmp = realloc(p->http_response, p->http_response_received + n);
|
||||
if(tmp == NULL) {
|
||||
debug_printf("failed to realloc %d bytes\n", (int)(p->http_response_received + n));
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
p->http_response = tmp;
|
||||
memcpy(p->http_response + p->http_response_received, buffer, n);
|
||||
p->http_response_received += n;
|
||||
}
|
||||
if(p->http_response_end_of_headers == 0) {
|
||||
upnpc_parse_headers(p);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SOAPPREFIX "s"
|
||||
#define SERVICEPREFIX "u"
|
||||
#define SERVICEPREFIX2 'u'
|
||||
|
||||
static int upnpc_build_soap_request(upnpc_t * p, const char * url,
|
||||
const char * service,
|
||||
const char * action,
|
||||
const struct upnp_args * args, int arg_count)
|
||||
{
|
||||
char * body;
|
||||
const char fmt_soap[] =
|
||||
"<?xml version=\"1.0\"?>\r\n"
|
||||
"<" SOAPPREFIX ":Envelope "
|
||||
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
||||
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||
"<" SOAPPREFIX ":Body>"
|
||||
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
|
||||
"%s"
|
||||
"</" SERVICEPREFIX ":%s>"
|
||||
"</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
|
||||
"\r\n";
|
||||
int body_len;
|
||||
const char fmt_http[] =
|
||||
"POST %s HTTP/1.1\r\n"
|
||||
"Host: %s%s\r\n"
|
||||
"User-Agent: MiniUPnPc-async\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"Content-Type: text/xml\r\n"
|
||||
"SOAPAction: \"%s#%s\"\r\n"
|
||||
"Connection: Close\r\n"
|
||||
"Cache-Control: no-cache\r\n" /* ??? */
|
||||
"Pragma: no-cache\r\n"
|
||||
"\r\n"
|
||||
"%s";
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
unsigned short port;
|
||||
char * path;
|
||||
unsigned int scope_id;
|
||||
char portstr[8];
|
||||
char * args_xml = NULL;
|
||||
|
||||
if(arg_count > 0) {
|
||||
int i;
|
||||
size_t l, n;
|
||||
for(i = 0, l = 0; i < arg_count; i++) {
|
||||
/* <ELT>VAL</ELT> */
|
||||
l += strlen(args[i].elt) * 2 + strlen(args[i].val) + 5;
|
||||
}
|
||||
args_xml = malloc(++l);
|
||||
if(args_xml == NULL) {
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
for(i = 0, n = 0; i < arg_count && n < l; i++) {
|
||||
/* <ELT>VAL</ELT> */
|
||||
n += snprintf(args_xml + n, l - n, "<%s>%s</%s>",
|
||||
args[i].elt, args[i].val, args[i].elt);
|
||||
}
|
||||
}
|
||||
|
||||
body_len = snprintf(NULL, 0, fmt_soap, action, service, args_xml?args_xml:"", action);
|
||||
body = malloc(body_len + 1);
|
||||
if(body == NULL) {
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
if(snprintf(body, body_len + 1, fmt_soap, action, service, args_xml?args_xml:"", action) != body_len) {
|
||||
debug_printf("snprintf() returned strange value...\n");
|
||||
}
|
||||
free(args_xml);
|
||||
args_xml = NULL;
|
||||
if(!parseURL(url, hostname, &port, &path, &scope_id)) {
|
||||
p->state = EError;
|
||||
return -1;
|
||||
}
|
||||
if(port != 80)
|
||||
snprintf(portstr, sizeof(portstr), ":%hu", port);
|
||||
else
|
||||
portstr[0] = '\0';
|
||||
p->http_request_len = snprintf(NULL, 0, fmt_http,
|
||||
path/*url*/, hostname, portstr, body_len, service, action, body);
|
||||
free(p->http_request);
|
||||
p->http_request = malloc(p->http_request_len + 1);
|
||||
if(snprintf(p->http_request, p->http_request_len + 1, fmt_http,
|
||||
path/*url*/, hostname, portstr, body_len, service, action, body) != p->http_request_len) {
|
||||
debug_printf("snprintf() returned strange value...\n");
|
||||
}
|
||||
free(body);
|
||||
debug_printf("%s", p->http_request);
|
||||
p->http_request_sent = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* public functions */
|
||||
int upnpc_init(upnpc_t * p, const char * multicastif)
|
||||
{
|
||||
int opt = 1;
|
||||
struct sockaddr_in addr;
|
||||
if(!p)
|
||||
return UPNPC_ERR_INVALID_ARGS;
|
||||
p->state = EError;
|
||||
memset(p, 0, sizeof(upnpc_t)); /* clean everything */
|
||||
/* open the socket for SSDP */
|
||||
p->ssdp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if(p->ssdp_socket < 0) {
|
||||
return UPNPC_ERR_SOCKET_FAILED;
|
||||
}
|
||||
/* set REUSEADDR */
|
||||
#ifdef WIN32
|
||||
if(setsockopt(p->ssdp_socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)) < 0) {
|
||||
#else
|
||||
if(setsockopt(p->ssdp_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
|
||||
#endif
|
||||
/* non fatal error ! */
|
||||
}
|
||||
if(!set_non_blocking(p->ssdp_socket)) {
|
||||
/* TODO log error */
|
||||
}
|
||||
|
||||
/* receive address */
|
||||
memset(&addr, 0, sizeof(struct sockaddr_in));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
/*addr.sin_port = htons(SSDP_PORT);*/
|
||||
|
||||
if(multicastif) {
|
||||
struct in_addr mc_if;
|
||||
mc_if.s_addr = inet_addr(multicastif);
|
||||
addr.sin_addr.s_addr = mc_if.s_addr;
|
||||
if(setsockopt(p->ssdp_socket, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
|
||||
PRINT_SOCKET_ERROR("setsockopt");
|
||||
/* non fatal error ! */
|
||||
}
|
||||
}
|
||||
|
||||
/* bind the socket to the ssdp address in order to receive responses */
|
||||
if(bind(p->ssdp_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0) {
|
||||
close(p->ssdp_socket);
|
||||
return UPNPC_ERR_BIND_FAILED;
|
||||
}
|
||||
|
||||
p->state = EInit;
|
||||
return UPNPC_OK;
|
||||
}
|
||||
|
||||
int upnpc_finalize(upnpc_t * p)
|
||||
{
|
||||
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) {
|
||||
close(p->ssdp_socket);
|
||||
p->ssdp_socket = -1;
|
||||
}
|
||||
if(p->http_socket >= 0) {
|
||||
close(p->http_socket);
|
||||
p->http_socket = -1;
|
||||
}
|
||||
ClearNameValueList(&p->soap_response_data);
|
||||
p->state = EFinalized;
|
||||
return UPNPC_OK;
|
||||
}
|
||||
|
||||
int upnpc_get_external_ip_address(upnpc_t * p)
|
||||
{
|
||||
upnpc_build_soap_request(p, p->control_conn_url,
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||
"GetExternalIPAddress", NULL, 0);
|
||||
p->state = ESoapConnect;
|
||||
upnpc_connect(p, p->control_conn_url);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int upnpc_get_link_layer_max_rate(upnpc_t * p)
|
||||
{
|
||||
upnpc_build_soap_request(p, p->control_cif_url,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
|
||||
"GetCommonLinkProperties", NULL, 0);
|
||||
p->state = ESoapConnect;
|
||||
upnpc_connect(p, p->control_conn_url);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int upnpc_add_port_mapping(upnpc_t * p,
|
||||
const char * remote_host, unsigned short ext_port,
|
||||
unsigned short int_port, const char * int_client,
|
||||
const char * proto, const char * description,
|
||||
unsigned int lease_duration)
|
||||
{
|
||||
struct upnp_args args[8];
|
||||
char lease_duration_str[16];
|
||||
char int_port_str[8];
|
||||
char ext_port_str[8];
|
||||
|
||||
if(int_client == NULL || int_port == 0 || ext_port == 0 || proto == NULL)
|
||||
return UPNPC_ERR_INVALID_ARGS;
|
||||
snprintf(lease_duration_str, sizeof(lease_duration_str), "%u", lease_duration);
|
||||
snprintf(int_port_str, sizeof(int_port_str), "%hu", int_port);
|
||||
snprintf(ext_port_str, sizeof(ext_port_str), "%hu", ext_port);
|
||||
args[0].elt = "NewRemoteHost";
|
||||
args[0].val = remote_host?remote_host:"";
|
||||
args[1].elt = "NewExternalPort";
|
||||
args[1].val = ext_port_str;
|
||||
args[2].elt = "NewProtocol";
|
||||
args[2].val = proto;
|
||||
args[3].elt = "NewInternalPort";
|
||||
args[3].val = int_port_str;
|
||||
args[4].elt = "NewInternalClient";
|
||||
args[4].val = int_client;
|
||||
args[5].elt = "NewEnabled";
|
||||
args[5].val = "1";
|
||||
args[6].elt = "NewPortMappingDescription";
|
||||
args[6].val = description?description:"miniupnpc-async";
|
||||
args[7].elt = "NewLeaseDuration";
|
||||
args[7].val = lease_duration_str;
|
||||
upnpc_build_soap_request(p, p->control_conn_url,
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||
"AddPortMapping",
|
||||
args, 8);
|
||||
p->state = ESoapConnect;
|
||||
upnpc_connect(p, p->control_conn_url);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef UPNPC_USE_SELECT
|
||||
int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds)
|
||||
{
|
||||
int n = 0;
|
||||
if(!p) return UPNPC_ERR_INVALID_ARGS;
|
||||
switch(p->state) {
|
||||
case ESendSSDP:
|
||||
FD_SET(p->ssdp_socket, writefds);
|
||||
if(*nfds < p->ssdp_socket)
|
||||
*nfds = p->ssdp_socket;
|
||||
n++;
|
||||
break;
|
||||
case EReceiveSSDP:
|
||||
FD_SET(p->ssdp_socket, readfds);
|
||||
if(*nfds < p->ssdp_socket)
|
||||
*nfds = p->ssdp_socket;
|
||||
n++;
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char * devices_to_search[] = {
|
||||
"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:1",
|
||||
"upnp:rootdevice",
|
||||
0
|
||||
};
|
||||
|
||||
int upnpc_process(upnpc_t * p)
|
||||
{
|
||||
/*
|
||||
1) Envoyer les paquets de discovery SSDP
|
||||
2) Recevoir et traiter les reponses
|
||||
3) recup les descriptions
|
||||
4) tester les etats
|
||||
*/
|
||||
if(!p) return UPNPC_ERR_INVALID_ARGS;
|
||||
debug_printf("state=%d\n", (int)p->state);
|
||||
switch(p->state) {
|
||||
case EInit:
|
||||
upnpc_send_ssdp_msearch(p, devices_to_search[0], 2);
|
||||
break;
|
||||
case ESendSSDP:
|
||||
upnpc_send_ssdp_msearch(p, devices_to_search[0], 2);
|
||||
break;
|
||||
case EReceiveSSDP:
|
||||
upnpc_receive_and_parse_ssdp(p);
|
||||
break;
|
||||
/*case EGetDesc:
|
||||
upnpc_connect(p);
|
||||
break;*/
|
||||
case EGetDescConnect:
|
||||
case ESoapConnect:
|
||||
upnpc_complete_connect(p);
|
||||
break;
|
||||
case EGetDescRequest:
|
||||
case ESoapRequest:
|
||||
upnpc_send_request(p);
|
||||
break;
|
||||
case EGetDescResponse:
|
||||
case ESoapResponse:
|
||||
upnpc_get_response(p);
|
||||
break;
|
||||
default:
|
||||
return UPNPC_ERR_UNKNOWN_STATE;
|
||||
}
|
||||
return UPNPC_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/* $Id: miniupnpc-async.h,v 1.13 2014/11/07 11:25:52 nanard Exp $ */
|
||||
/* miniupnpc-async
|
||||
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr>
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
#ifndef MINIUPNPC_ASYNC_H_INCLUDED
|
||||
#define MINIUPNPC_ASYNC_H_INCLUDED
|
||||
|
||||
#include "declspec.h"
|
||||
#include "upnpreplyparse.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define UPNPC_OK 0
|
||||
#define UPNPC_ERR_INVALID_ARGS (-1)
|
||||
#define UPNPC_ERR_SOCKET_FAILED (-2)
|
||||
#define UPNPC_ERR_BIND_FAILED (-3)
|
||||
#define UPNPC_ERR_UNKNOWN_STATE (-4)
|
||||
|
||||
typedef struct {
|
||||
enum {
|
||||
EInit = 1,
|
||||
ESendSSDP,
|
||||
EReceiveSSDP,
|
||||
/*EGetDesc,*/
|
||||
EGetDescConnect,
|
||||
EGetDescRequest,
|
||||
EGetDescResponse,
|
||||
EReady,
|
||||
ESoapConnect,
|
||||
ESoapRequest,
|
||||
ESoapResponse,
|
||||
EFinalized = 99,
|
||||
EError = 1000
|
||||
} state;
|
||||
int ssdp_socket;
|
||||
char * root_desc_location;
|
||||
int http_socket;
|
||||
char * http_request;
|
||||
int http_request_len;
|
||||
int http_request_sent;
|
||||
char * http_response;
|
||||
int http_response_received;
|
||||
int http_response_end_of_headers;
|
||||
int http_response_content_length;
|
||||
int http_response_chunked;
|
||||
int http_response_code;
|
||||
char * control_cif_url;
|
||||
char * control_conn_url;
|
||||
struct NameValueParserData soap_response_data;
|
||||
} upnpc_t;
|
||||
|
||||
int upnpc_init(upnpc_t * p, const char * multicastif);
|
||||
|
||||
int upnpc_finalize(upnpc_t * p);
|
||||
|
||||
int upnpc_get_external_ip_address(upnpc_t * p);
|
||||
|
||||
int upnpc_get_link_layer_max_rate(upnpc_t * p);
|
||||
|
||||
int upnpc_add_port_mapping(upnpc_t * p,
|
||||
const char * remote_host, unsigned short ext_port,
|
||||
unsigned short int_port, const char * int_client,
|
||||
const char * proto, const char * description,
|
||||
unsigned int lease_duration);
|
||||
|
||||
#ifdef UPNPC_USE_SELECT
|
||||
int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds);
|
||||
#endif /* UPNPC_USE_SELECT */
|
||||
|
||||
int upnpc_process(upnpc_t * p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MINIUPNPC_ASYNC_H_INCLUDED */
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
/* $Id: minixml.c,v 1.11 2014/02/03 15:54:12 nanard Exp $ */
|
||||
/* minixml.c : the minimum size a xml parser can be ! */
|
||||
/* Project : miniupnp
|
||||
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
|
||||
Copyright (c) 2005-2014, Thomas BERNARD
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "minixml.h"
|
||||
|
||||
/* parseatt : used to parse the argument list
|
||||
* return 0 (false) in case of success and -1 (true) if the end
|
||||
* of the xmlbuffer is reached. */
|
||||
static int parseatt(struct xmlparser * p)
|
||||
{
|
||||
const char * attname;
|
||||
int attnamelen;
|
||||
const char * attvalue;
|
||||
int attvaluelen;
|
||||
while(p->xml < p->xmlend)
|
||||
{
|
||||
if(*p->xml=='/' || *p->xml=='>')
|
||||
return 0;
|
||||
if( !IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
char sep;
|
||||
attname = p->xml;
|
||||
attnamelen = 0;
|
||||
while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
attnamelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
while(*(p->xml++) != '=')
|
||||
{
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
while(IS_WHITE_SPACE(*p->xml))
|
||||
{
|
||||
p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
sep = *p->xml;
|
||||
if(sep=='\'' || sep=='\"')
|
||||
{
|
||||
p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
attvalue = p->xml;
|
||||
attvaluelen = 0;
|
||||
while(*p->xml != sep)
|
||||
{
|
||||
attvaluelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attvalue = p->xml;
|
||||
attvaluelen = 0;
|
||||
while( !IS_WHITE_SPACE(*p->xml)
|
||||
&& *p->xml != '>' && *p->xml != '/')
|
||||
{
|
||||
attvaluelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*printf("%.*s='%.*s'\n",
|
||||
attnamelen, attname, attvaluelen, attvalue);*/
|
||||
if(p->attfunc)
|
||||
p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen);
|
||||
}
|
||||
p->xml++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* parseelt parse the xml stream and
|
||||
* call the callback functions when needed... */
|
||||
static void parseelt(struct xmlparser * p)
|
||||
{
|
||||
int i;
|
||||
const char * elementname;
|
||||
while(p->xml < (p->xmlend - 1))
|
||||
{
|
||||
if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "<!--", 4)))
|
||||
{
|
||||
p->xml += 3;
|
||||
/* ignore comments */
|
||||
do
|
||||
{
|
||||
p->xml++;
|
||||
if ((p->xml + 3) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
while(memcmp(p->xml, "-->", 3) != 0);
|
||||
p->xml += 3;
|
||||
}
|
||||
else if((p->xml)[0]=='<' && (p->xml)[1]!='?')
|
||||
{
|
||||
i = 0; elementname = ++p->xml;
|
||||
while( !IS_WHITE_SPACE(*p->xml)
|
||||
&& (*p->xml!='>') && (*p->xml!='/')
|
||||
)
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
/* to ignore namespace : */
|
||||
if(*p->xml==':')
|
||||
{
|
||||
i = 0;
|
||||
elementname = ++p->xml;
|
||||
}
|
||||
}
|
||||
if(i>0)
|
||||
{
|
||||
if(p->starteltfunc)
|
||||
p->starteltfunc(p->data, elementname, i);
|
||||
if(parseatt(p))
|
||||
return;
|
||||
if(*p->xml!='/')
|
||||
{
|
||||
const char * data;
|
||||
i = 0; data = ++p->xml;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
while( IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(memcmp(p->xml, "<![CDATA[", 9) == 0)
|
||||
{
|
||||
/* CDATA handling */
|
||||
p->xml += 9;
|
||||
data = p->xml;
|
||||
i = 0;
|
||||
while(memcmp(p->xml, "]]>", 3) != 0)
|
||||
{
|
||||
i++; p->xml++;
|
||||
if ((p->xml + 3) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(i>0 && p->datafunc)
|
||||
p->datafunc(p->data, data, i);
|
||||
while(*p->xml!='<')
|
||||
{
|
||||
p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while(*p->xml!='<')
|
||||
{
|
||||
i++; p->xml++;
|
||||
if ((p->xml + 1) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(i>0 && p->datafunc && *(p->xml + 1) == '/')
|
||||
p->datafunc(p->data, data, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(*p->xml == '/')
|
||||
{
|
||||
i = 0; elementname = ++p->xml;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
while((*p->xml != '>'))
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(p->endeltfunc)
|
||||
p->endeltfunc(p->data, elementname, i);
|
||||
p->xml++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p->xml++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* the parser must be initialized before calling this function */
|
||||
void parsexml(struct xmlparser * parser)
|
||||
{
|
||||
parser->xml = parser->xmlstart;
|
||||
parser->xmlend = parser->xmlstart + parser->xmlsize;
|
||||
parseelt(parser);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */
|
||||
/* minimal xml parser
|
||||
*
|
||||
* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef MINIXML_H_INCLUDED
|
||||
#define MINIXML_H_INCLUDED
|
||||
#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n'))
|
||||
|
||||
/* if a callback function pointer is set to NULL,
|
||||
* the function is not called */
|
||||
struct xmlparser {
|
||||
const char *xmlstart;
|
||||
const char *xmlend;
|
||||
const char *xml; /* pointer to current character */
|
||||
int xmlsize;
|
||||
void * data;
|
||||
void (*starteltfunc) (void *, const char *, int);
|
||||
void (*endeltfunc) (void *, const char *, int);
|
||||
void (*datafunc) (void *, const char *, int);
|
||||
void (*attfunc) (void *, const char *, int, const char *, int);
|
||||
};
|
||||
|
||||
/* parsexml()
|
||||
* the xmlparser structure must be initialized before the call
|
||||
* the following structure members have to be initialized :
|
||||
* xmlstart, xmlsize, data, *func
|
||||
* xml is for internal usage, xmlend is computed automatically */
|
||||
void parsexml(struct xmlparser *);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/* $Id: parsessdpreply.c,v 1.2 2009/11/14 10:37:55 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
* copyright (c) 2005-2009 Thomas Bernard
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
#include <strings.h>
|
||||
#include "parsessdpreply.h"
|
||||
|
||||
/* parseMSEARCHReply()
|
||||
* the last 4 arguments are filled during the parsing :
|
||||
* - location/locationsize : "location:" field of the SSDP reply packet
|
||||
* - st/stsize : "st:" field of the SSDP reply packet.
|
||||
* The strings are NOT null terminated */
|
||||
void
|
||||
parseMSEARCHReply(const char * reply, int size,
|
||||
const char * * location, int * locationsize,
|
||||
const char * * st, int * stsize)
|
||||
{
|
||||
int a, b, i;
|
||||
i = 0;
|
||||
a = i; /* start of the line */
|
||||
b = 0;
|
||||
while(i<size)
|
||||
{
|
||||
switch(reply[i])
|
||||
{
|
||||
case ':':
|
||||
if(b==0)
|
||||
{
|
||||
b = i; /* end of the "header" */
|
||||
/*for(j=a; j<b; j++)
|
||||
{
|
||||
putchar(reply[j]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case '\x0a':
|
||||
case '\x0d':
|
||||
if(b!=0)
|
||||
{
|
||||
/*for(j=b+1; j<i; j++)
|
||||
{
|
||||
putchar(reply[j]);
|
||||
}
|
||||
putchar('\n');*/
|
||||
do { b++; } while(reply[b]==' ');
|
||||
if(0==strncasecmp(reply+a, "location", 8))
|
||||
{
|
||||
*location = reply+b;
|
||||
*locationsize = i-b;
|
||||
}
|
||||
else if(0==strncasecmp(reply+a, "st", 2))
|
||||
{
|
||||
*st = reply+b;
|
||||
*stsize = i-b;
|
||||
}
|
||||
b = 0;
|
||||
}
|
||||
a = i+1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/* $Id: parsessdpreply.h,v 1.1 2009/11/14 10:37:55 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
* copyright (c) 2005-2009 Thomas Bernard
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
#ifndef __PARSESSDPREPLY_H__
|
||||
#define __PARSESSDPREPLY_H__
|
||||
|
||||
/* parseMSEARCHReply()
|
||||
* the last 4 arguments are filled during the parsing :
|
||||
* - location/locationsize : "location:" field of the SSDP reply packet
|
||||
* - st/stsize : "st:" field of the SSDP reply packet.
|
||||
* The strings are NOT null terminated */
|
||||
void
|
||||
parseMSEARCHReply(const char * reply, int size,
|
||||
const char * * location, int * locationsize,
|
||||
const char * * st, int * stsize);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
/* $Id: testasync.c,v 1.14 2014/11/07 12:07:38 nanard Exp $ */
|
||||
/* miniupnpc-async
|
||||
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr>
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
/* compile with -DUPNPC_USE_SELECT to enable upnpc_select_fds() function */
|
||||
#include "miniupnpc-async.h"
|
||||
#include "upnpreplyparse.h"
|
||||
|
||||
enum methods {
|
||||
EGetExternalIP,
|
||||
EGetRates,
|
||||
EAddPortMapping,
|
||||
ENothing
|
||||
};
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
int r, n;
|
||||
upnpc_t upnp;
|
||||
const char * multicastif = NULL;
|
||||
enum methods next_method_to_call = EGetExternalIP;
|
||||
enum methods last_method = ENothing;
|
||||
if(argc>1)
|
||||
multicastif = argv[1];
|
||||
if((r = upnpc_init(&upnp, multicastif)) < 0) {
|
||||
fprintf(stderr, "upnpc_init failed : %d", r);
|
||||
return 1;
|
||||
}
|
||||
r = upnpc_process(&upnp);
|
||||
printf("upnpc_process returned %d\n", r);
|
||||
while((upnp.state != EReady) && (upnp.state != EError)) {
|
||||
int nfds;
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
/*struct timeval timeout;*/
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
nfds = 0;
|
||||
n = upnpc_select_fds(&upnp, &nfds, &readfds, &writefds);
|
||||
if(n <= 0) {
|
||||
printf("nothing to select()...\n");
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
#endif
|
||||
#if DEBUG
|
||||
printf("select(%d, ...);\n", nfds+1);
|
||||
#endif /* DEBUG */
|
||||
if(select(nfds+1, &readfds, &writefds, NULL, NULL/*&timeout*/) < 0) {
|
||||
perror("select");
|
||||
return 1;
|
||||
}
|
||||
r = upnpc_process(&upnp);
|
||||
#if DEBUG
|
||||
printf("upnpc_process returned %d\n", r);
|
||||
#endif /* DEBUG */
|
||||
if(r < 0)
|
||||
break;
|
||||
if(upnp.state == EReady) {
|
||||
char * p;
|
||||
printf("Process UPnP IGD Method results : HTTP %d\n", upnp.http_response_code);
|
||||
if(upnp.http_response_code == 200) {
|
||||
switch(last_method) {
|
||||
case EGetExternalIP:
|
||||
p = GetValueFromNameValueList(&upnp.soap_response_data, "NewExternalIPAddress");
|
||||
printf("ExternalIPAddress = %s\n", p);
|
||||
/* p = GetValueFromNameValueList(&pdata, "errorCode");*/
|
||||
break;
|
||||
case EGetRates:
|
||||
p = GetValueFromNameValueList(&upnp.soap_response_data, "NewLayer1DownstreamMaxBitRate");
|
||||
printf("DownStream MaxBitRate = %s\t", p);
|
||||
p = GetValueFromNameValueList(&upnp.soap_response_data, "NewLayer1UpstreamMaxBitRate");
|
||||
printf("UpStream MaxBitRate = %s\n", p);
|
||||
break;
|
||||
case EAddPortMapping:
|
||||
printf("OK\n");
|
||||
break;
|
||||
case ENothing:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
printf("SOAP error :\n");
|
||||
printf(" faultcode='%s'\n", GetValueFromNameValueList(&upnp.soap_response_data, "faultcode"));
|
||||
printf(" faultstring='%s'\n", GetValueFromNameValueList(&upnp.soap_response_data, "faultstring"));
|
||||
printf(" errorCode=%s\n", GetValueFromNameValueList(&upnp.soap_response_data, "errorCode"));
|
||||
printf(" errorDescription='%s'\n", GetValueFromNameValueList(&upnp.soap_response_data, "errorDescription"));
|
||||
}
|
||||
if(next_method_to_call == ENothing)
|
||||
break;
|
||||
printf("Ready to call UPnP IGD methods\n");
|
||||
last_method = next_method_to_call;
|
||||
switch(next_method_to_call) {
|
||||
case EGetExternalIP:
|
||||
printf("GetExternalIPAddress\n");
|
||||
upnpc_get_external_ip_address(&upnp);
|
||||
next_method_to_call = EGetRates;
|
||||
break;
|
||||
case EGetRates:
|
||||
printf("GetCommonLinkProperties\n");
|
||||
upnpc_get_link_layer_max_rate(&upnp);
|
||||
next_method_to_call = EAddPortMapping;
|
||||
break;
|
||||
case EAddPortMapping:
|
||||
printf("AddPortMapping\n");
|
||||
upnpc_add_port_mapping(&upnp,
|
||||
NULL /* remote_host */, 40002 /* ext_port */,
|
||||
42042 /* int_port */, "192.168.1.202" /* int_client */,
|
||||
"TCP" /* proto */, "this is a test" /* description */,
|
||||
0 /* lease duration */);
|
||||
next_method_to_call = ENothing;
|
||||
case ENothing:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
upnpc_finalize(&upnp);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
/* $Id: upnpreplyparse.c,v 1.18 2014/11/05 05:36:08 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "upnpreplyparse.h"
|
||||
#include "minixml.h"
|
||||
|
||||
static void
|
||||
NameValueParserStartElt(void * d, const char * name, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
data->topelt = 1;
|
||||
if(l>63)
|
||||
l = 63;
|
||||
memcpy(data->curelt, name, l);
|
||||
data->curelt[l] = '\0';
|
||||
data->cdata = NULL;
|
||||
data->cdatalen = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
NameValueParserEndElt(void * d, const char * name, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
struct NameValue * nv;
|
||||
(void)name;
|
||||
(void)l;
|
||||
if(!data->topelt)
|
||||
return;
|
||||
if(strcmp(data->curelt, "NewPortListing") != 0)
|
||||
{
|
||||
int l;
|
||||
/* standard case. Limited to n chars strings */
|
||||
l = data->cdatalen;
|
||||
nv = malloc(sizeof(struct NameValue));
|
||||
if(l>=(int)sizeof(nv->value))
|
||||
l = sizeof(nv->value) - 1;
|
||||
strncpy(nv->name, data->curelt, 64);
|
||||
nv->name[63] = '\0';
|
||||
if(data->cdata != NULL)
|
||||
{
|
||||
memcpy(nv->value, data->cdata, l);
|
||||
nv->value[l] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
nv->value[0] = '\0';
|
||||
}
|
||||
nv->l_next = data->l_head; /* insert in list */
|
||||
data->l_head = nv;
|
||||
}
|
||||
data->cdata = NULL;
|
||||
data->cdatalen = 0;
|
||||
data->topelt = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
NameValueParserGetData(void * d, const char * datas, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
if(strcmp(data->curelt, "NewPortListing") == 0)
|
||||
{
|
||||
/* specific case for NewPortListing which is a XML Document */
|
||||
data->portListing = malloc(l + 1);
|
||||
if(!data->portListing)
|
||||
{
|
||||
/* malloc error */
|
||||
return;
|
||||
}
|
||||
memcpy(data->portListing, datas, l);
|
||||
data->portListing[l] = '\0';
|
||||
data->portListingLength = l;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* standard case. */
|
||||
data->cdata = datas;
|
||||
data->cdatalen = l;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParseNameValue(const char * buffer, int bufsize,
|
||||
struct NameValueParserData * data)
|
||||
{
|
||||
struct xmlparser parser;
|
||||
data->l_head = NULL;
|
||||
data->portListing = NULL;
|
||||
data->portListingLength = 0;
|
||||
/* init xmlparser object */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = data;
|
||||
parser.starteltfunc = NameValueParserStartElt;
|
||||
parser.endeltfunc = NameValueParserEndElt;
|
||||
parser.datafunc = NameValueParserGetData;
|
||||
parser.attfunc = 0;
|
||||
parsexml(&parser);
|
||||
}
|
||||
|
||||
void
|
||||
ClearNameValueList(struct NameValueParserData * pdata)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
if(pdata->portListing)
|
||||
{
|
||||
free(pdata->portListing);
|
||||
pdata->portListing = NULL;
|
||||
pdata->portListingLength = 0;
|
||||
}
|
||||
while((nv = pdata->l_head) != NULL)
|
||||
{
|
||||
pdata->l_head = nv->l_next;
|
||||
free(nv);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||
const char * Name)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
char * p = NULL;
|
||||
for(nv = pdata->l_head;
|
||||
(nv != NULL) && (p == NULL);
|
||||
nv = nv->l_next)
|
||||
{
|
||||
if(strcmp(nv->name, Name) == 0)
|
||||
p = nv->value;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* useless now that minixml ignores namespaces by itself */
|
||||
char *
|
||||
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
|
||||
const char * Name)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
char * p = NULL;
|
||||
char * pname;
|
||||
for(nv = pdata->head.lh_first;
|
||||
(nv != NULL) && (p == NULL);
|
||||
nv = nv->entries.le_next)
|
||||
{
|
||||
pname = strrchr(nv->name, ':');
|
||||
if(pname)
|
||||
pname++;
|
||||
else
|
||||
pname = nv->name;
|
||||
if(strcmp(pname, Name)==0)
|
||||
p = nv->value;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* debug all-in-one function
|
||||
* do parsing then display to stdout */
|
||||
#ifdef DEBUG
|
||||
void
|
||||
DisplayNameValueList(char * buffer, int bufsize)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
struct NameValue * nv;
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
for(nv = pdata.l_head;
|
||||
nv != NULL;
|
||||
nv = nv->l_next)
|
||||
{
|
||||
printf("%s = %s\n", nv->name, nv->value);
|
||||
}
|
||||
ClearNameValueList(&pdata);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2013 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#ifndef UPNPREPLYPARSE_H_INCLUDED
|
||||
#define UPNPREPLYPARSE_H_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct NameValue {
|
||||
struct NameValue * l_next;
|
||||
char name[64];
|
||||
char value[128];
|
||||
};
|
||||
|
||||
struct NameValueParserData {
|
||||
struct NameValue * l_head;
|
||||
char curelt[64];
|
||||
char * portListing;
|
||||
int portListingLength;
|
||||
int topelt;
|
||||
const char * cdata;
|
||||
int cdatalen;
|
||||
};
|
||||
|
||||
/* ParseNameValue() */
|
||||
void
|
||||
ParseNameValue(const char * buffer, int bufsize,
|
||||
struct NameValueParserData * data);
|
||||
|
||||
/* ClearNameValueList() */
|
||||
void
|
||||
ClearNameValueList(struct NameValueParserData * pdata);
|
||||
|
||||
/* GetValueFromNameValueList() */
|
||||
char *
|
||||
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||
const char * Name);
|
||||
|
||||
#if 0
|
||||
/* GetValueFromNameValueListIgnoreNS() */
|
||||
char *
|
||||
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
|
||||
const char * Name);
|
||||
#endif
|
||||
|
||||
/* DisplayNameValueList() */
|
||||
#ifdef DEBUG
|
||||
void
|
||||
DisplayNameValueList(char * buffer, int bufsize);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/* $Id: upnputils.c,v 1.1 2013/09/07 06:45:39 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2013 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#ifdef AF_LINK
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
|
||||
#include "upnputils.h"
|
||||
|
||||
int
|
||||
sockaddr_to_string(const struct sockaddr * addr, char * str, size_t size)
|
||||
{
|
||||
char buffer[64];
|
||||
unsigned short port = 0;
|
||||
int n = -1;
|
||||
|
||||
switch(addr->sa_family)
|
||||
{
|
||||
case AF_INET6:
|
||||
inet_ntop(addr->sa_family,
|
||||
&((struct sockaddr_in6 *)addr)->sin6_addr,
|
||||
buffer, sizeof(buffer));
|
||||
port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
|
||||
n = snprintf(str, size, "[%s]:%hu", buffer, port);
|
||||
break;
|
||||
case AF_INET:
|
||||
inet_ntop(addr->sa_family,
|
||||
&((struct sockaddr_in *)addr)->sin_addr,
|
||||
buffer, sizeof(buffer));
|
||||
port = ntohs(((struct sockaddr_in *)addr)->sin_port);
|
||||
n = snprintf(str, size, "%s:%hu", buffer, port);
|
||||
break;
|
||||
#ifdef AF_LINK
|
||||
#if defined(__sun)
|
||||
/* solaris does not seem to have link_ntoa */
|
||||
/* #define link_ntoa _link_ntoa */
|
||||
#define link_ntoa(x) "dummy-link_ntoa"
|
||||
#endif
|
||||
case AF_LINK:
|
||||
{
|
||||
struct sockaddr_dl * sdl = (struct sockaddr_dl *)addr;
|
||||
n = snprintf(str, size, "index=%hu type=%d %s",
|
||||
sdl->sdl_index, sdl->sdl_type,
|
||||
link_ntoa(sdl));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
n = snprintf(str, size, "unknown address family %d", addr->sa_family);
|
||||
#if 0
|
||||
n = snprintf(str, size, "unknown address family %d "
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
addr->sa_family,
|
||||
addr->sa_data[0], addr->sa_data[1], (unsigned)addr->sa_data[2], addr->sa_data[3],
|
||||
addr->sa_data[4], addr->sa_data[5], (unsigned)addr->sa_data[6], addr->sa_data[7]);
|
||||
#endif
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
set_non_blocking(int fd)
|
||||
{
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
if(flags < 0)
|
||||
return 0;
|
||||
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/* $Id: upnputils.h,v 1.1 2013/09/07 06:45:39 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2011-2013 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#ifndef UPNPUTILS_H_INCLUDED
|
||||
#define UPNPUTILS_H_INCLUDED
|
||||
|
||||
/**
|
||||
* convert a struct sockaddr to a human readable string.
|
||||
* [ipv6]:port or ipv4:port
|
||||
* return the number of characters used (as snprintf)
|
||||
*/
|
||||
int
|
||||
sockaddr_to_string(const struct sockaddr * addr, char * str, size_t size);
|
||||
|
||||
/**
|
||||
* set the file description as non blocking
|
||||
* return 0 in case of failure, 1 in case of success
|
||||
*/
|
||||
int
|
||||
set_non_blocking(int fd);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
*.o
|
||||
*.a
|
||||
upnpc-libevent
|
|
@ -0,0 +1,50 @@
|
|||
# $Id: Makefile,v 1.2 2014/11/08 17:12:15 nanard Exp $
|
||||
|
||||
CFLAGS = -O0 -g -DDEBUG
|
||||
# libevent debug
|
||||
CFLAGS += -DUSE_DEBUG
|
||||
|
||||
CFLAGS += -fPIC
|
||||
CFLAGS += -ansi
|
||||
CFLAGS += -Wall -W
|
||||
CFLAGS += -D_BSD_SOURCE
|
||||
CFLAGS += -D_POSIX_C_SOURCE=1
|
||||
|
||||
LDFLAGS = -levent
|
||||
|
||||
LIB = libminiupnpc-ev.a
|
||||
|
||||
LIB_SRCS = miniupnpc-libevent.c minixml.c igd_desc_parse.c upnpreplyparse.c
|
||||
|
||||
SRCS = $(LIB_SRCS) upnpc-libevent.c
|
||||
|
||||
LIB_OBJS = $(patsubst %.c,%.o,$(LIB_SRCS))
|
||||
|
||||
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||
|
||||
EXECUTABLE = upnpc-libevent
|
||||
|
||||
.PHONY: all clean depend
|
||||
|
||||
all: $(EXECUTABLE)
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJS)
|
||||
$(RM) $(EXECUTABLE)
|
||||
|
||||
upnpc-libevent: upnpc-libevent.o $(LIB)
|
||||
|
||||
$(LIB): $(LIB_OBJS)
|
||||
$(AR) crs $@ $?
|
||||
|
||||
depend:
|
||||
makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null
|
||||
|
||||
# DO NOT DELETE THIS LINE -- make depend depends on it.
|
||||
|
||||
miniupnpc-libevent.o: miniupnpc-libevent.h declspec.h upnpreplyparse.h
|
||||
miniupnpc-libevent.o: parsessdpreply.h minixml.h igd_desc_parse.h
|
||||
minixml.o: minixml.h
|
||||
igd_desc_parse.o: igd_desc_parse.h
|
||||
upnpreplyparse.o: upnpreplyparse.h minixml.h
|
||||
upnpc-libevent.o: miniupnpc-libevent.h declspec.h upnpreplyparse.h
|
|
@ -0,0 +1,7 @@
|
|||
miniupnpc-libevent :
|
||||
|
||||
UPnP IGD control point (ie client) using libevent
|
||||
|
||||
http://libevent.org
|
||||
https://github.com/libevent/libevent
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef DECLSPEC_H_DEFINED
|
||||
#define DECLSPEC_H_DEFINED
|
||||
|
||||
#if defined(WIN32) && !defined(STATICLIB)
|
||||
#ifdef MINIUPNP_EXPORTS
|
||||
#define LIBSPEC __declspec(dllexport)
|
||||
#else
|
||||
#define LIBSPEC __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define LIBSPEC
|
||||
#endif
|
||||
|
||||
#endif /* DECLSPEC_H_DEFINED */
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/* $Id: igd_desc_parse.c,v 1.15 2014/07/01 13:01:17 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
#include "igd_desc_parse.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Start element handler :
|
||||
* update nesting level counter and copy element name */
|
||||
void IGDstartelt(void * d, const char * name, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
memcpy( datas->cureltname, name, l);
|
||||
datas->cureltname[l] = '\0';
|
||||
datas->level++;
|
||||
if( (l==7) && !memcmp(name, "service", l) ) {
|
||||
datas->tmp.controlurl[0] = '\0';
|
||||
datas->tmp.eventsuburl[0] = '\0';
|
||||
datas->tmp.scpdurl[0] = '\0';
|
||||
datas->tmp.servicetype[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
|
||||
|
||||
/* End element handler :
|
||||
* update nesting level counter and update parser state if
|
||||
* service element is parsed */
|
||||
void IGDendelt(void * d, const char * name, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
datas->level--;
|
||||
/*printf("endelt %2d %.*s\n", datas->level, l, name);*/
|
||||
if( (l==7) && !memcmp(name, "service", l) )
|
||||
{
|
||||
if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) {
|
||||
memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) {
|
||||
memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:")
|
||||
|| COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:") ) {
|
||||
if(datas->first.servicetype[0] == '\0') {
|
||||
memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else {
|
||||
memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Data handler :
|
||||
* copy data depending on the current element name and state */
|
||||
void IGDdata(void * d, const char * data, int l)
|
||||
{
|
||||
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||
char * dstmember = 0;
|
||||
/*printf("%2d %s : %.*s\n",
|
||||
datas->level, datas->cureltname, l, data); */
|
||||
if( !strcmp(datas->cureltname, "URLBase") )
|
||||
dstmember = datas->urlbase;
|
||||
else if( !strcmp(datas->cureltname, "presentationURL") )
|
||||
dstmember = datas->presentationurl;
|
||||
else if( !strcmp(datas->cureltname, "serviceType") )
|
||||
dstmember = datas->tmp.servicetype;
|
||||
else if( !strcmp(datas->cureltname, "controlURL") )
|
||||
dstmember = datas->tmp.controlurl;
|
||||
else if( !strcmp(datas->cureltname, "eventSubURL") )
|
||||
dstmember = datas->tmp.eventsuburl;
|
||||
else if( !strcmp(datas->cureltname, "SCPDURL") )
|
||||
dstmember = datas->tmp.scpdurl;
|
||||
/* else if( !strcmp(datas->cureltname, "deviceType") )
|
||||
dstmember = datas->devicetype_tmp;*/
|
||||
if(dstmember)
|
||||
{
|
||||
if(l>=MINIUPNPC_URL_MAXSIZE)
|
||||
l = MINIUPNPC_URL_MAXSIZE-1;
|
||||
memcpy(dstmember, data, l);
|
||||
dstmember[l] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void printIGD(struct IGDdatas * d)
|
||||
{
|
||||
printf("urlbase = '%s'\n", d->urlbase);
|
||||
printf("WAN Device (Common interface config) :\n");
|
||||
/*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/
|
||||
printf(" serviceType = '%s'\n", d->CIF.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->CIF.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->CIF.scpdurl);
|
||||
printf("primary WAN Connection Device (IP or PPP Connection):\n");
|
||||
/*printf(" deviceType = '%s'\n", d->first.devicetype);*/
|
||||
printf(" servicetype = '%s'\n", d->first.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->first.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->first.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->first.scpdurl);
|
||||
printf("secondary WAN Connection Device (IP or PPP Connection):\n");
|
||||
/*printf(" deviceType = '%s'\n", d->second.devicetype);*/
|
||||
printf(" servicetype = '%s'\n", d->second.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->second.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->second.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->second.scpdurl);
|
||||
printf("WAN IPv6 Firewall Control :\n");
|
||||
/*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/
|
||||
printf(" servicetype = '%s'\n", d->IPv6FC.servicetype);
|
||||
printf(" controlURL = '%s'\n", d->IPv6FC.controlurl);
|
||||
printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl);
|
||||
printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/* $Id: igd_desc_parse.h,v 1.11 2012/10/16 16:49:02 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2010 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef IGD_DESC_PARSE_H_INCLUDED
|
||||
#define IGD_DESC_PARSE_H_INCLUDED
|
||||
|
||||
/* Structure to store the result of the parsing of UPnP
|
||||
* descriptions of Internet Gateway Devices */
|
||||
#define MINIUPNPC_URL_MAXSIZE (128)
|
||||
struct IGDdatas_service {
|
||||
char controlurl[MINIUPNPC_URL_MAXSIZE];
|
||||
char eventsuburl[MINIUPNPC_URL_MAXSIZE];
|
||||
char scpdurl[MINIUPNPC_URL_MAXSIZE];
|
||||
char servicetype[MINIUPNPC_URL_MAXSIZE];
|
||||
/*char devicetype[MINIUPNPC_URL_MAXSIZE];*/
|
||||
};
|
||||
|
||||
struct IGDdatas {
|
||||
char cureltname[MINIUPNPC_URL_MAXSIZE];
|
||||
char urlbase[MINIUPNPC_URL_MAXSIZE];
|
||||
char presentationurl[MINIUPNPC_URL_MAXSIZE];
|
||||
int level;
|
||||
/*int state;*/
|
||||
/* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
|
||||
struct IGDdatas_service CIF;
|
||||
/* "urn:schemas-upnp-org:service:WANIPConnection:1"
|
||||
* "urn:schemas-upnp-org:service:WANPPPConnection:1" */
|
||||
struct IGDdatas_service first;
|
||||
/* if both WANIPConnection and WANPPPConnection are present */
|
||||
struct IGDdatas_service second;
|
||||
/* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */
|
||||
struct IGDdatas_service IPv6FC;
|
||||
/* tmp */
|
||||
struct IGDdatas_service tmp;
|
||||
};
|
||||
|
||||
void IGDstartelt(void *, const char *, int);
|
||||
void IGDendelt(void *, const char *, int);
|
||||
void IGDdata(void *, const char *, int);
|
||||
void printIGD(struct IGDdatas *);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,672 @@
|
|||
/* $Id: miniupnpc-libevent.c,v 1.8 2014/11/13 09:15:23 nanard Exp $ */
|
||||
/* miniupnpc-libevent
|
||||
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr>
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
#include <event2/event.h>
|
||||
#include <event2/buffer.h>
|
||||
/*#include <event2/bufferevent.h>*/
|
||||
#include <event2/http.h>
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#define PRINT_SOCKET_ERROR printf
|
||||
#define SOCKET_ERROR GetWSALastError()
|
||||
#define WOULDBLOCK(err) (err == WSAEWOULDBLOCK)
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#define closesocket close
|
||||
#define PRINT_SOCKET_ERROR perror
|
||||
#define SOCKET_ERROR errno
|
||||
#define WOULDBLOCK(err) (err == EAGAIN || err == EWOULDBLOCK)
|
||||
#endif
|
||||
#include "miniupnpc-libevent.h"
|
||||
#include "parsessdpreply.h"
|
||||
#include "minixml.h"
|
||||
#include "igd_desc_parse.h"
|
||||
#include "upnpreplyparse.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||
#endif /* MIN */
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif /* MAXHOSTNAMELEN */
|
||||
|
||||
#define SSDP_PORT 1900
|
||||
#define SSDP_MCAST_ADDR "239.255.255.250"
|
||||
#define XSTR(s) STR(s)
|
||||
#define STR(s) #s
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug_printf(...) fprintf(stderr, __VA_ARGS__)
|
||||
#else
|
||||
#define debug_printf(...)
|
||||
#endif
|
||||
|
||||
/* stuctures */
|
||||
|
||||
struct upnp_args {
|
||||
const char * elt;
|
||||
const char * val;
|
||||
};
|
||||
|
||||
/* private functions */
|
||||
|
||||
static int upnpc_get_desc(upnpc_t * p, const char * url);
|
||||
static char * build_url_string(const char * urlbase, const char * root_desc_url, const char * controlurl);
|
||||
|
||||
/* data */
|
||||
static const char * devices_to_search[] = {
|
||||
"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:1",
|
||||
"upnp:rootdevice",
|
||||
0
|
||||
};
|
||||
|
||||
static void upnpc_conn_close_cb(struct evhttp_connection * conn, void * data)
|
||||
{
|
||||
upnpc_t * p = (upnpc_t *)data;
|
||||
debug_printf("upnpc_get_desc_conn_close_cb %p %p\n", conn, p);
|
||||
}
|
||||
|
||||
/* parse_msearch_reply()
|
||||
* the last 4 arguments are filled during the parsing :
|
||||
* - location/locationsize : "location:" field of the SSDP reply packet
|
||||
* - st/stsize : "st:" field of the SSDP reply packet.
|
||||
* The strings are NOT null terminated */
|
||||
static void
|
||||
parse_msearch_reply(const char * reply, int size,
|
||||
const char * * location, int * locationsize,
|
||||
const char * * st, int * stsize)
|
||||
{
|
||||
int a, b, i;
|
||||
i = 0; /* current character index */
|
||||
a = i; /* start of the line */
|
||||
b = 0; /* end of the "header" (position of the colon) */
|
||||
while(i<size) {
|
||||
switch(reply[i]) {
|
||||
case ':':
|
||||
if(b==0) {
|
||||
b = i; /* end of the "header" */
|
||||
}
|
||||
break;
|
||||
case '\x0a':
|
||||
case '\x0d':
|
||||
if(b!=0) {
|
||||
/* skip the colon and white spaces */
|
||||
do { b++; } while(reply[b]==' ' && b<size);
|
||||
if(0==strncasecmp(reply+a, "location", 8)) {
|
||||
*location = reply+b;
|
||||
*locationsize = i-b;
|
||||
} else if(0==strncasecmp(reply+a, "st", 2)) {
|
||||
*st = reply+b;
|
||||
*stsize = i-b;
|
||||
}
|
||||
b = 0;
|
||||
}
|
||||
a = i+1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
static void upnpc_send_ssdp_msearch(evutil_socket_t s, short events, upnpc_t * p)
|
||||
{
|
||||
/* envoyer les packets de M-SEARCH discovery sur le socket ssdp */
|
||||
int n;
|
||||
char bufr[1024];
|
||||
struct sockaddr_in addr;
|
||||
unsigned int mx = 2;
|
||||
static const char MSearchMsgFmt[] =
|
||||
"M-SEARCH * HTTP/1.1\r\n"
|
||||
"HOST: " SSDP_MCAST_ADDR ":" XSTR(SSDP_PORT) "\r\n"
|
||||
"ST: %s\r\n"
|
||||
"MAN: \"ssdp:discover\"\r\n"
|
||||
"MX: %u\r\n"
|
||||
"\r\n";
|
||||
(void)p;
|
||||
(void)events;
|
||||
|
||||
memset(&addr, 0, sizeof(struct sockaddr_in));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(SSDP_PORT);
|
||||
addr.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
||||
n = snprintf(bufr, sizeof(bufr),
|
||||
MSearchMsgFmt, devices_to_search[0], mx);
|
||||
debug_printf("upnpc_send_ssdp_msearch: %s", bufr);
|
||||
n = sendto(s, bufr, n, 0,
|
||||
(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
|
||||
if (n < 0) {
|
||||
PRINT_SOCKET_ERROR("sendto");
|
||||
}
|
||||
}
|
||||
|
||||
static int upnpc_set_root_desc_location(upnpc_t * p, const char * location, int locationsize)
|
||||
{
|
||||
char * tmp;
|
||||
tmp = realloc(p->root_desc_location, locationsize + 1);
|
||||
if(tmp == 0) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(tmp, location, locationsize);
|
||||
tmp[locationsize] = '\0';
|
||||
p->root_desc_location = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void upnpc_receive_and_parse_ssdp(evutil_socket_t s, short events, upnpc_t * p)
|
||||
{
|
||||
char bufr[2048];
|
||||
ssize_t len;
|
||||
|
||||
if(events == EV_TIMEOUT) {
|
||||
/* nothing received ... */
|
||||
debug_printf("upnpc_receive_and_parse_ssdp() TIMEOUT\n");
|
||||
return;
|
||||
}
|
||||
len = recv(s, bufr, sizeof(bufr), 0);
|
||||
debug_printf("input %d bytes\n", (int)len);
|
||||
if(len < 0) {
|
||||
PRINT_SOCKET_ERROR("recv");
|
||||
} else if(len == 0) {
|
||||
debug_printf("SSDP socket closed ?\n");
|
||||
} else {
|
||||
const char * location = NULL;
|
||||
int locationsize;
|
||||
const char * st = NULL;
|
||||
int stsize;
|
||||
debug_printf("%.*s", (int)len, bufr);
|
||||
parse_msearch_reply(bufr, len, &location, &locationsize, &st, &stsize);
|
||||
debug_printf("location = '%.*s'\n", locationsize, location);
|
||||
debug_printf("st = '%.*s'\n", stsize, st);
|
||||
if(location != NULL) {
|
||||
if(upnpc_set_root_desc_location(p, location, locationsize) < 0) {
|
||||
return;
|
||||
}
|
||||
upnpc_get_desc(p, p->root_desc_location);
|
||||
} else {
|
||||
/* or do nothing ? */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
parseURL(const char * url,
|
||||
char * hostname, unsigned short * port,
|
||||
char * * path, unsigned int * scope_id)
|
||||
{
|
||||
char * p1, *p2, *p3;
|
||||
if(!url)
|
||||
return 0;
|
||||
p1 = strstr(url, "://");
|
||||
if(!p1)
|
||||
return 0;
|
||||
p1 += 3;
|
||||
if( (url[0]!='h') || (url[1]!='t')
|
||||
||(url[2]!='t') || (url[3]!='p'))
|
||||
return 0;
|
||||
memset(hostname, 0, MAXHOSTNAMELEN + 1);
|
||||
if(*p1 == '[') {
|
||||
/* IP v6 : http://[2a00:1450:8002::6a]/path/abc */
|
||||
char * scope;
|
||||
scope = strchr(p1, '%');
|
||||
p2 = strchr(p1, ']');
|
||||
if(p2 && scope && scope < p2 && scope_id) {
|
||||
/* parse scope */
|
||||
#ifdef IF_NAMESIZE
|
||||
char tmp[IF_NAMESIZE];
|
||||
int l;
|
||||
scope++;
|
||||
/* "%25" is just '%' in URL encoding */
|
||||
if(scope[0] == '2' && scope[1] == '5')
|
||||
scope += 2; /* skip "25" */
|
||||
l = p2 - scope;
|
||||
if(l >= IF_NAMESIZE)
|
||||
l = IF_NAMESIZE - 1;
|
||||
memcpy(tmp, scope, l);
|
||||
tmp[l] = '\0';
|
||||
*scope_id = if_nametoindex(tmp);
|
||||
if(*scope_id == 0) {
|
||||
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
|
||||
}
|
||||
#else /* IF_NAMESIZE */
|
||||
/* under windows, scope is numerical */
|
||||
char tmp[8];
|
||||
int l;
|
||||
scope++;
|
||||
/* "%25" is just '%' in URL encoding */
|
||||
if(scope[0] == '2' && scope[1] == '5')
|
||||
scope += 2; /* skip "25" */
|
||||
l = p2 - scope;
|
||||
if(l >= (int)sizeof(tmp))
|
||||
l = sizeof(tmp) - 1;
|
||||
memcpy(tmp, scope, l);
|
||||
tmp[l] = '\0';
|
||||
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
|
||||
#endif /* IF_NAMESIZE */
|
||||
}
|
||||
p3 = strchr(p1, '/');
|
||||
if(p2 && p3) {
|
||||
p2++;
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
|
||||
if(*p2 == ':') {
|
||||
*port = 0;
|
||||
p2++;
|
||||
while( (*p2 >= '0') && (*p2 <= '9')) {
|
||||
*port *= 10;
|
||||
*port += (unsigned short)(*p2 - '0');
|
||||
p2++;
|
||||
}
|
||||
} else {
|
||||
*port = 80;
|
||||
}
|
||||
*path = p3;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
p2 = strchr(p1, ':');
|
||||
p3 = strchr(p1, '/');
|
||||
if(!p3)
|
||||
return 0;
|
||||
if(!p2 || (p2>p3)) {
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1)));
|
||||
*port = 80;
|
||||
} else {
|
||||
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
|
||||
*port = 0;
|
||||
p2++;
|
||||
while( (*p2 >= '0') && (*p2 <= '9')) {
|
||||
*port *= 10;
|
||||
*port += (unsigned short)(*p2 - '0');
|
||||
p2++;
|
||||
}
|
||||
}
|
||||
*path = p3;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void upnpc_desc_received(struct evhttp_request * req, void * pvoid)
|
||||
{
|
||||
size_t len;
|
||||
unsigned char * data;
|
||||
struct evbuffer * input_buffer;
|
||||
struct IGDdatas igd;
|
||||
struct xmlparser parser;
|
||||
upnpc_t * p = (upnpc_t *)pvoid;
|
||||
|
||||
input_buffer = evhttp_request_get_input_buffer(req);
|
||||
len = evbuffer_get_length(input_buffer);
|
||||
data = evbuffer_pullup(input_buffer, len);
|
||||
debug_printf("upnpc_desc_received %d (%d bytes)\n", evhttp_request_get_response_code(req), (int)len);
|
||||
debug_printf("%.*s\n", (int)len, (char *)data);
|
||||
if(data == NULL)
|
||||
return;
|
||||
|
||||
memset(&igd, 0, sizeof(struct IGDdatas));
|
||||
memset(&parser, 0, sizeof(struct xmlparser));
|
||||
parser.xmlstart = (char *)data;
|
||||
parser.xmlsize = len;
|
||||
parser.data = &igd;
|
||||
parser.starteltfunc = IGDstartelt;
|
||||
parser.endeltfunc = IGDendelt;
|
||||
parser.datafunc = IGDdata;
|
||||
parsexml(&parser);
|
||||
#ifdef DEBUG
|
||||
printIGD(&igd);
|
||||
#endif /* DEBUG */
|
||||
p->control_conn_url = build_url_string(igd.urlbase, p->root_desc_location, igd.first.controlurl);
|
||||
p->control_cif_url = build_url_string(igd.urlbase, p->root_desc_location, igd.CIF.controlurl);
|
||||
debug_printf("control_conn_url='%s'\n", p->control_conn_url);
|
||||
debug_printf("control_cif_url='%s'\n", p->control_cif_url);
|
||||
p->ready_cb(evhttp_request_get_response_code(req), p->cb_data);
|
||||
}
|
||||
|
||||
static void upnpc_soap_response(struct evhttp_request * req, void * pvoid)
|
||||
{
|
||||
size_t len;
|
||||
unsigned char * data;
|
||||
struct evbuffer * input_buffer;
|
||||
upnpc_t * p = (upnpc_t *)pvoid;
|
||||
|
||||
input_buffer = evhttp_request_get_input_buffer(req);
|
||||
len = evbuffer_get_length(input_buffer);
|
||||
data = evbuffer_pullup(input_buffer, len);
|
||||
debug_printf("upnpc_soap_response %d (%d bytes)\n", evhttp_request_get_response_code(req), (int)len);
|
||||
debug_printf("%.*s\n", (int)len, (char *)data);
|
||||
if(data == NULL)
|
||||
return;
|
||||
|
||||
ClearNameValueList(&p->soap_response_data);
|
||||
ParseNameValue((char *)data, (int)len,
|
||||
&p->soap_response_data);
|
||||
p->soap_cb(evhttp_request_get_response_code(req), p->cb_data);
|
||||
}
|
||||
|
||||
static int upnpc_get_desc(upnpc_t * p, const char * url)
|
||||
{
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
unsigned short port;
|
||||
char * path;
|
||||
unsigned int scope_id;
|
||||
struct evhttp_request * req;
|
||||
struct evkeyvalq * headers;
|
||||
|
||||
if(p->root_desc_location == 0) {
|
||||
return -1;
|
||||
}
|
||||
if(!parseURL(url/*p->root_desc_location*/, hostname, &port,
|
||||
&path, &scope_id)) {
|
||||
return -1;
|
||||
}
|
||||
if(p->desc_conn == NULL) {
|
||||
p->desc_conn = evhttp_connection_base_new(p->base, NULL, hostname, port);
|
||||
}
|
||||
evhttp_connection_set_closecb(p->desc_conn, upnpc_conn_close_cb, p);
|
||||
/*evhttp_connection_set_timeout(p->desc_conn, 600);*/
|
||||
req = evhttp_request_new(upnpc_desc_received/*callback*/, p);
|
||||
headers = evhttp_request_get_output_headers(req);
|
||||
evhttp_add_header(headers, "Host", hostname);
|
||||
evhttp_add_header(headers, "Connection", "close");
|
||||
/*evhttp_add_header(headers, "User-Agent", "***");*/
|
||||
evhttp_make_request(p->desc_conn, req, EVHTTP_REQ_GET, path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char * build_url_string(const char * urlbase, const char * root_desc_url, const char * controlurl)
|
||||
{
|
||||
int l, n;
|
||||
char * s;
|
||||
const char * base;
|
||||
char * p;
|
||||
/* if controlurl is an absolute url, return it */
|
||||
if(0 == memcmp("http://", controlurl, 7))
|
||||
return strdup(controlurl);
|
||||
base = (urlbase[0] == '\0') ? root_desc_url : urlbase;
|
||||
n = strlen(base);
|
||||
if(n > 7) {
|
||||
p = strchr(base + 7, '/');
|
||||
if(p)
|
||||
n = p - base;
|
||||
}
|
||||
l = n + strlen(controlurl) + 1;
|
||||
if(controlurl[0] != '/')
|
||||
l++;
|
||||
s = malloc(l);
|
||||
if(s == NULL) return NULL;
|
||||
memcpy(s, base, n);
|
||||
if(controlurl[0] != '/')
|
||||
s[n++] = '/';
|
||||
memcpy(s + n, controlurl, l - n);
|
||||
return s;
|
||||
}
|
||||
|
||||
#define SOAPPREFIX "s"
|
||||
#define SERVICEPREFIX "u"
|
||||
#define SERVICEPREFIX2 'u'
|
||||
|
||||
static int upnpc_send_soap_request(upnpc_t * p, const char * url,
|
||||
const char * service,
|
||||
const char * method,
|
||||
const struct upnp_args * args, int arg_count)
|
||||
{
|
||||
char action[128];
|
||||
char * body;
|
||||
const char fmt_soap[] =
|
||||
"<?xml version=\"1.0\"?>\r\n"
|
||||
"<" SOAPPREFIX ":Envelope "
|
||||
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
||||
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||
"<" SOAPPREFIX ":Body>"
|
||||
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
|
||||
"%s"
|
||||
"</" SERVICEPREFIX ":%s>"
|
||||
"</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
|
||||
"\r\n";
|
||||
int body_len;
|
||||
char hostname[MAXHOSTNAMELEN+1];
|
||||
unsigned short port;
|
||||
char * path;
|
||||
unsigned int scope_id;
|
||||
char portstr[8];
|
||||
char * args_xml = NULL;
|
||||
struct evhttp_request * req;
|
||||
struct evkeyvalq * headers;
|
||||
struct evbuffer * buffer;
|
||||
|
||||
if(arg_count > 0) {
|
||||
int i;
|
||||
size_t l, n;
|
||||
for(i = 0, l = 0; i < arg_count; i++) {
|
||||
/* <ELT>VAL</ELT> */
|
||||
l += strlen(args[i].elt) * 2 + strlen(args[i].val) + 5;
|
||||
}
|
||||
args_xml = malloc(++l);
|
||||
if(args_xml == NULL) {
|
||||
return -1;
|
||||
}
|
||||
for(i = 0, n = 0; i < arg_count && n < l; i++) {
|
||||
/* <ELT>VAL</ELT> */
|
||||
n += snprintf(args_xml + n, l - n, "<%s>%s</%s>",
|
||||
args[i].elt, args[i].val, args[i].elt);
|
||||
}
|
||||
}
|
||||
|
||||
body_len = snprintf(NULL, 0, fmt_soap, method, service, args_xml?args_xml:"", method);
|
||||
body = malloc(body_len + 1);
|
||||
if(body == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if(snprintf(body, body_len + 1, fmt_soap, method, service, args_xml?args_xml:"", method) != body_len) {
|
||||
debug_printf("snprintf() returned strange value...\n");
|
||||
}
|
||||
free(args_xml);
|
||||
args_xml = NULL;
|
||||
if(!parseURL(url, hostname, &port, &path, &scope_id)) {
|
||||
return -1;
|
||||
}
|
||||
if(port != 80)
|
||||
snprintf(portstr, sizeof(portstr), ":%hu", port);
|
||||
else
|
||||
portstr[0] = '\0';
|
||||
snprintf(action, sizeof(action), "%s#%s", service, method);
|
||||
if(p->soap_conn == NULL) {
|
||||
p->soap_conn = evhttp_connection_base_new(p->base, NULL, hostname, port);
|
||||
}
|
||||
req = evhttp_request_new(upnpc_soap_response, p);
|
||||
headers = evhttp_request_get_output_headers(req);
|
||||
buffer = evhttp_request_get_output_buffer(req);
|
||||
evhttp_add_header(headers, "Host", hostname);
|
||||
evhttp_add_header(headers, "SOAPAction", action);
|
||||
evhttp_add_header(headers, "Content-Type", "text/xml");
|
||||
/*evhttp_add_header(headers, "User-Agent", "***");*/
|
||||
/*evhttp_add_header(headers, "Cache-Control", "no-cache");*/
|
||||
/*evhttp_add_header(headers, "Pragma", "no-cache");*/
|
||||
evbuffer_add(buffer, body, body_len);
|
||||
evhttp_make_request(p->soap_conn, req, EVHTTP_REQ_POST, path);
|
||||
free(body);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* public functions */
|
||||
int upnpc_init(upnpc_t * p, struct event_base * base, const char * multicastif,
|
||||
upnpc_callback_fn ready_cb, upnpc_callback_fn soap_cb, void * cb_data)
|
||||
{
|
||||
int opt = 1;
|
||||
struct sockaddr_in addr;
|
||||
struct timeval timeout;
|
||||
|
||||
if(p == NULL || base == NULL)
|
||||
return UPNPC_ERR_INVALID_ARGS;
|
||||
memset(p, 0, sizeof(upnpc_t)); /* clean everything */
|
||||
p->base = base;
|
||||
p->ready_cb = ready_cb;
|
||||
p->soap_cb = soap_cb;
|
||||
p->cb_data = cb_data;
|
||||
/* open the socket for SSDP */
|
||||
p->ssdp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if(p->ssdp_socket < 0) {
|
||||
return UPNPC_ERR_SOCKET_FAILED;
|
||||
}
|
||||
/* set REUSEADDR */
|
||||
#ifdef WIN32
|
||||
if(setsockopt(p->ssdp_socket, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)) < 0) {
|
||||
#else /* WIN32 */
|
||||
if(setsockopt(p->ssdp_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
|
||||
#endif /* WIN32 */
|
||||
/* non fatal error ! */
|
||||
}
|
||||
if(evutil_make_socket_nonblocking(p->ssdp_socket) < 0) {
|
||||
debug_printf("evutil_make_socket_nonblocking FAILED\n");
|
||||
}
|
||||
|
||||
/* receive address */
|
||||
memset(&addr, 0, sizeof(struct sockaddr_in));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
/*addr.sin_port = htons(SSDP_PORT);*/
|
||||
|
||||
if(multicastif) {
|
||||
struct in_addr mc_if;
|
||||
mc_if.s_addr = inet_addr(multicastif);
|
||||
addr.sin_addr.s_addr = mc_if.s_addr;
|
||||
if(setsockopt(p->ssdp_socket, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
|
||||
PRINT_SOCKET_ERROR("setsockopt");
|
||||
/* non fatal error ! */
|
||||
}
|
||||
}
|
||||
|
||||
/* bind the socket to the ssdp address in order to receive responses */
|
||||
if(bind(p->ssdp_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0) {
|
||||
close(p->ssdp_socket);
|
||||
return UPNPC_ERR_BIND_FAILED;
|
||||
}
|
||||
/* event on SSDP */
|
||||
p->ev_ssdp_recv = event_new(p->base, p->ssdp_socket,
|
||||
EV_READ|EV_PERSIST,
|
||||
(event_callback_fn)upnpc_receive_and_parse_ssdp, p);
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
if(event_add(p->ev_ssdp_recv, &timeout)) {
|
||||
debug_printf("event_add FAILED\n");
|
||||
}
|
||||
p->ev_ssdp_writable = event_new(p->base, p->ssdp_socket,
|
||||
EV_WRITE,
|
||||
(event_callback_fn)upnpc_send_ssdp_msearch, p);
|
||||
if(event_add(p->ev_ssdp_writable, NULL)) {
|
||||
debug_printf("event_add FAILED\n");
|
||||
}
|
||||
return UPNPC_OK;
|
||||
}
|
||||
|
||||
int upnpc_finalize(upnpc_t * p)
|
||||
{
|
||||
if(!p) return UPNPC_ERR_INVALID_ARGS;
|
||||
free(p->root_desc_location);
|
||||
p->root_desc_location = 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) {
|
||||
close(p->ssdp_socket);
|
||||
p->ssdp_socket = -1;
|
||||
}
|
||||
if(p->ev_ssdp_recv) {
|
||||
event_free(p->ev_ssdp_recv);
|
||||
p->ev_ssdp_recv = NULL;
|
||||
}
|
||||
if(p->ev_ssdp_writable) {
|
||||
event_free(p->ev_ssdp_writable);
|
||||
p->ev_ssdp_writable = NULL;
|
||||
}
|
||||
if(p->desc_conn) {
|
||||
evhttp_connection_free(p->desc_conn);
|
||||
p->desc_conn = NULL;
|
||||
}
|
||||
if(p->soap_conn) {
|
||||
evhttp_connection_free(p->soap_conn);
|
||||
p->soap_conn = NULL;
|
||||
}
|
||||
ClearNameValueList(&p->soap_response_data);
|
||||
return UPNPC_OK;
|
||||
}
|
||||
|
||||
int upnpc_get_external_ip_address(upnpc_t * p)
|
||||
{
|
||||
return upnpc_send_soap_request(p, p->control_conn_url,
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||
"GetExternalIPAddress", NULL, 0);
|
||||
}
|
||||
|
||||
int upnpc_get_link_layer_max_rate(upnpc_t * p)
|
||||
{
|
||||
return upnpc_send_soap_request(p, p->control_cif_url,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1",
|
||||
"GetCommonLinkProperties", NULL, 0);
|
||||
}
|
||||
|
||||
int upnpc_add_port_mapping(upnpc_t * p,
|
||||
const char * remote_host, unsigned short ext_port,
|
||||
unsigned short int_port, const char * int_client,
|
||||
const char * proto, const char * description,
|
||||
unsigned int lease_duration)
|
||||
{
|
||||
struct upnp_args args[8];
|
||||
char lease_duration_str[16];
|
||||
char int_port_str[8];
|
||||
char ext_port_str[8];
|
||||
|
||||
if(int_client == NULL || int_port == 0 || ext_port == 0 || proto == NULL)
|
||||
return UPNPC_ERR_INVALID_ARGS;
|
||||
snprintf(lease_duration_str, sizeof(lease_duration_str), "%u", lease_duration);
|
||||
snprintf(int_port_str, sizeof(int_port_str), "%hu", int_port);
|
||||
snprintf(ext_port_str, sizeof(ext_port_str), "%hu", ext_port);
|
||||
args[0].elt = "NewRemoteHost";
|
||||
args[0].val = remote_host?remote_host:"";
|
||||
args[1].elt = "NewExternalPort";
|
||||
args[1].val = ext_port_str;
|
||||
args[2].elt = "NewProtocol";
|
||||
args[2].val = proto;
|
||||
args[3].elt = "NewInternalPort";
|
||||
args[3].val = int_port_str;
|
||||
args[4].elt = "NewInternalClient";
|
||||
args[4].val = int_client;
|
||||
args[5].elt = "NewEnabled";
|
||||
args[5].val = "1";
|
||||
args[6].elt = "NewPortMappingDescription";
|
||||
args[6].val = description?description:"miniupnpc-libevent";
|
||||
args[7].elt = "NewLeaseDuration";
|
||||
args[7].val = lease_duration_str;
|
||||
return upnpc_send_soap_request(p, p->control_conn_url,
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:1",
|
||||
"AddPortMapping",
|
||||
args, 8);
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/* $Id: miniupnpc-libevent.h,v 1.3 2014/11/12 14:10:52 nanard Exp $ */
|
||||
/* miniupnpc-libevent
|
||||
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr>
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
#ifndef MINIUPNPC_LIBEVENT_H_INCLUDED
|
||||
#define MINIUPNPC_LIBEVENT_H_INCLUDED
|
||||
|
||||
#include <event2/event.h>
|
||||
|
||||
#include "declspec.h"
|
||||
#include "upnpreplyparse.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define UPNPC_OK 0
|
||||
#define UPNPC_ERR_INVALID_ARGS (-1)
|
||||
#define UPNPC_ERR_SOCKET_FAILED (-2)
|
||||
#define UPNPC_ERR_BIND_FAILED (-3)
|
||||
#define UPNPC_ERR_UNKNOWN_STATE (-4)
|
||||
|
||||
typedef void(* upnpc_callback_fn)(int, void *);
|
||||
|
||||
typedef struct {
|
||||
struct event_base * base;
|
||||
evutil_socket_t ssdp_socket;
|
||||
struct event * ev_ssdp_recv;
|
||||
struct event * ev_ssdp_writable;
|
||||
char * root_desc_location;
|
||||
struct evhttp_connection * desc_conn;
|
||||
char * control_cif_url;
|
||||
char * control_conn_url;
|
||||
struct evhttp_connection * soap_conn;
|
||||
struct NameValueParserData soap_response_data;
|
||||
upnpc_callback_fn ready_cb;
|
||||
upnpc_callback_fn soap_cb;
|
||||
void * cb_data;
|
||||
} upnpc_t;
|
||||
|
||||
int upnpc_init(upnpc_t * p, struct event_base * base, const char * multicastif,
|
||||
upnpc_callback_fn ready_cb, upnpc_callback_fn soap_cb, void * cb_data);
|
||||
|
||||
int upnpc_finalize(upnpc_t * p);
|
||||
|
||||
int upnpc_get_external_ip_address(upnpc_t * p);
|
||||
|
||||
int upnpc_get_link_layer_max_rate(upnpc_t * p);
|
||||
|
||||
int upnpc_add_port_mapping(upnpc_t * p,
|
||||
const char * remote_host, unsigned short ext_port,
|
||||
unsigned short int_port, const char * int_client,
|
||||
const char * proto, const char * description,
|
||||
unsigned int lease_duration);
|
||||
|
||||
#ifdef UPNPC_USE_SELECT
|
||||
int upnpc_select_fds(upnpc_t * p, int * nfds, fd_set * readfds, fd_set * writefds);
|
||||
#endif /* UPNPC_USE_SELECT */
|
||||
|
||||
int upnpc_process(upnpc_t * p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MINIUPNPC_LIBEVENT_H_INCLUDED */
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
/* $Id: minixml.c,v 1.11 2014/02/03 15:54:12 nanard Exp $ */
|
||||
/* minixml.c : the minimum size a xml parser can be ! */
|
||||
/* Project : miniupnp
|
||||
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
|
||||
Copyright (c) 2005-2014, Thomas BERNARD
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "minixml.h"
|
||||
|
||||
/* parseatt : used to parse the argument list
|
||||
* return 0 (false) in case of success and -1 (true) if the end
|
||||
* of the xmlbuffer is reached. */
|
||||
static int parseatt(struct xmlparser * p)
|
||||
{
|
||||
const char * attname;
|
||||
int attnamelen;
|
||||
const char * attvalue;
|
||||
int attvaluelen;
|
||||
while(p->xml < p->xmlend)
|
||||
{
|
||||
if(*p->xml=='/' || *p->xml=='>')
|
||||
return 0;
|
||||
if( !IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
char sep;
|
||||
attname = p->xml;
|
||||
attnamelen = 0;
|
||||
while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
attnamelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
while(*(p->xml++) != '=')
|
||||
{
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
while(IS_WHITE_SPACE(*p->xml))
|
||||
{
|
||||
p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
sep = *p->xml;
|
||||
if(sep=='\'' || sep=='\"')
|
||||
{
|
||||
p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
attvalue = p->xml;
|
||||
attvaluelen = 0;
|
||||
while(*p->xml != sep)
|
||||
{
|
||||
attvaluelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attvalue = p->xml;
|
||||
attvaluelen = 0;
|
||||
while( !IS_WHITE_SPACE(*p->xml)
|
||||
&& *p->xml != '>' && *p->xml != '/')
|
||||
{
|
||||
attvaluelen++; p->xml++;
|
||||
if(p->xml >= p->xmlend)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/*printf("%.*s='%.*s'\n",
|
||||
attnamelen, attname, attvaluelen, attvalue);*/
|
||||
if(p->attfunc)
|
||||
p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen);
|
||||
}
|
||||
p->xml++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* parseelt parse the xml stream and
|
||||
* call the callback functions when needed... */
|
||||
static void parseelt(struct xmlparser * p)
|
||||
{
|
||||
int i;
|
||||
const char * elementname;
|
||||
while(p->xml < (p->xmlend - 1))
|
||||
{
|
||||
if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "<!--", 4)))
|
||||
{
|
||||
p->xml += 3;
|
||||
/* ignore comments */
|
||||
do
|
||||
{
|
||||
p->xml++;
|
||||
if ((p->xml + 3) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
while(memcmp(p->xml, "-->", 3) != 0);
|
||||
p->xml += 3;
|
||||
}
|
||||
else if((p->xml)[0]=='<' && (p->xml)[1]!='?')
|
||||
{
|
||||
i = 0; elementname = ++p->xml;
|
||||
while( !IS_WHITE_SPACE(*p->xml)
|
||||
&& (*p->xml!='>') && (*p->xml!='/')
|
||||
)
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
/* to ignore namespace : */
|
||||
if(*p->xml==':')
|
||||
{
|
||||
i = 0;
|
||||
elementname = ++p->xml;
|
||||
}
|
||||
}
|
||||
if(i>0)
|
||||
{
|
||||
if(p->starteltfunc)
|
||||
p->starteltfunc(p->data, elementname, i);
|
||||
if(parseatt(p))
|
||||
return;
|
||||
if(*p->xml!='/')
|
||||
{
|
||||
const char * data;
|
||||
i = 0; data = ++p->xml;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
while( IS_WHITE_SPACE(*p->xml) )
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(memcmp(p->xml, "<![CDATA[", 9) == 0)
|
||||
{
|
||||
/* CDATA handling */
|
||||
p->xml += 9;
|
||||
data = p->xml;
|
||||
i = 0;
|
||||
while(memcmp(p->xml, "]]>", 3) != 0)
|
||||
{
|
||||
i++; p->xml++;
|
||||
if ((p->xml + 3) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(i>0 && p->datafunc)
|
||||
p->datafunc(p->data, data, i);
|
||||
while(*p->xml!='<')
|
||||
{
|
||||
p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while(*p->xml!='<')
|
||||
{
|
||||
i++; p->xml++;
|
||||
if ((p->xml + 1) >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(i>0 && p->datafunc && *(p->xml + 1) == '/')
|
||||
p->datafunc(p->data, data, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(*p->xml == '/')
|
||||
{
|
||||
i = 0; elementname = ++p->xml;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
while((*p->xml != '>'))
|
||||
{
|
||||
i++; p->xml++;
|
||||
if (p->xml >= p->xmlend)
|
||||
return;
|
||||
}
|
||||
if(p->endeltfunc)
|
||||
p->endeltfunc(p->data, elementname, i);
|
||||
p->xml++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p->xml++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* the parser must be initialized before calling this function */
|
||||
void parsexml(struct xmlparser * parser)
|
||||
{
|
||||
parser->xml = parser->xmlstart;
|
||||
parser->xmlend = parser->xmlstart + parser->xmlsize;
|
||||
parseelt(parser);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */
|
||||
/* minimal xml parser
|
||||
*
|
||||
* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
#ifndef MINIXML_H_INCLUDED
|
||||
#define MINIXML_H_INCLUDED
|
||||
#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n'))
|
||||
|
||||
/* if a callback function pointer is set to NULL,
|
||||
* the function is not called */
|
||||
struct xmlparser {
|
||||
const char *xmlstart;
|
||||
const char *xmlend;
|
||||
const char *xml; /* pointer to current character */
|
||||
int xmlsize;
|
||||
void * data;
|
||||
void (*starteltfunc) (void *, const char *, int);
|
||||
void (*endeltfunc) (void *, const char *, int);
|
||||
void (*datafunc) (void *, const char *, int);
|
||||
void (*attfunc) (void *, const char *, int, const char *, int);
|
||||
};
|
||||
|
||||
/* parsexml()
|
||||
* the xmlparser structure must be initialized before the call
|
||||
* the following structure members have to be initialized :
|
||||
* xmlstart, xmlsize, data, *func
|
||||
* xml is for internal usage, xmlend is computed automatically */
|
||||
void parsexml(struct xmlparser *);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/* $Id: parsessdpreply.c,v 1.2 2009/11/14 10:37:55 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
* copyright (c) 2005-2009 Thomas Bernard
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
#include <strings.h>
|
||||
#include "parsessdpreply.h"
|
||||
|
||||
/* parseMSEARCHReply()
|
||||
* the last 4 arguments are filled during the parsing :
|
||||
* - location/locationsize : "location:" field of the SSDP reply packet
|
||||
* - st/stsize : "st:" field of the SSDP reply packet.
|
||||
* The strings are NOT null terminated */
|
||||
void
|
||||
parseMSEARCHReply(const char * reply, int size,
|
||||
const char * * location, int * locationsize,
|
||||
const char * * st, int * stsize)
|
||||
{
|
||||
int a, b, i;
|
||||
i = 0;
|
||||
a = i; /* start of the line */
|
||||
b = 0;
|
||||
while(i<size)
|
||||
{
|
||||
switch(reply[i])
|
||||
{
|
||||
case ':':
|
||||
if(b==0)
|
||||
{
|
||||
b = i; /* end of the "header" */
|
||||
/*for(j=a; j<b; j++)
|
||||
{
|
||||
putchar(reply[j]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case '\x0a':
|
||||
case '\x0d':
|
||||
if(b!=0)
|
||||
{
|
||||
/*for(j=b+1; j<i; j++)
|
||||
{
|
||||
putchar(reply[j]);
|
||||
}
|
||||
putchar('\n');*/
|
||||
do { b++; } while(reply[b]==' ');
|
||||
if(0==strncasecmp(reply+a, "location", 8))
|
||||
{
|
||||
*location = reply+b;
|
||||
*locationsize = i-b;
|
||||
}
|
||||
else if(0==strncasecmp(reply+a, "st", 2))
|
||||
{
|
||||
*st = reply+b;
|
||||
*stsize = i-b;
|
||||
}
|
||||
b = 0;
|
||||
}
|
||||
a = i+1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/* $Id: parsessdpreply.h,v 1.1 2009/11/14 10:37:55 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
* copyright (c) 2005-2009 Thomas Bernard
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
#ifndef __PARSESSDPREPLY_H__
|
||||
#define __PARSESSDPREPLY_H__
|
||||
|
||||
/* parseMSEARCHReply()
|
||||
* the last 4 arguments are filled during the parsing :
|
||||
* - location/locationsize : "location:" field of the SSDP reply packet
|
||||
* - st/stsize : "st:" field of the SSDP reply packet.
|
||||
* The strings are NOT null terminated */
|
||||
void
|
||||
parseMSEARCHReply(const char * reply, int size,
|
||||
const char * * location, int * locationsize,
|
||||
const char * * st, int * stsize);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/* $Id: upnpc-libevent.c,v 1.5 2014/11/13 09:46:12 nanard Exp $ */
|
||||
/* miniupnpc-libevent
|
||||
* Copyright (c) 2008-2014, Thomas BERNARD <miniupnp@free.fr>
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "miniupnpc-libevent.h"
|
||||
|
||||
static struct event_base *base = NULL;
|
||||
|
||||
static void sighandler(int signal)
|
||||
{
|
||||
(void)signal;
|
||||
/*printf("signal %d\n", signal);*/
|
||||
event_base_loopbreak(base);
|
||||
}
|
||||
|
||||
/* ready callback */
|
||||
static void ready(int code, void * data)
|
||||
{
|
||||
upnpc_t * p = (upnpc_t *)data;
|
||||
printf("READY ! %d %p\n", code, data);
|
||||
/* 1st request */
|
||||
upnpc_get_external_ip_address(p);
|
||||
}
|
||||
|
||||
static enum { EGetExtIp = 0, EGetMaxRate, EAddPortMapping, EFinished } state = EGetExtIp;
|
||||
|
||||
/* soap callback */
|
||||
static void soap(int code, void * data)
|
||||
{
|
||||
upnpc_t * p = (upnpc_t *)data;
|
||||
printf("SOAP ! %d\n", code);
|
||||
if(code == 200) {
|
||||
switch(state) {
|
||||
case EGetExtIp:
|
||||
printf("ExternalIpAddres=%s\n", GetValueFromNameValueList(&p->soap_response_data, "NewExternalIPAddress"));
|
||||
upnpc_get_link_layer_max_rate(p);
|
||||
state = EGetMaxRate;
|
||||
break;
|
||||
case EGetMaxRate:
|
||||
printf("DownStream MaxBitRate = %s\t", GetValueFromNameValueList(&p->soap_response_data, "NewLayer1DownstreamMaxBitRate"));
|
||||
upnpc_add_port_mapping(p, NULL, 60001, 60002, "192.168.0.42", "TCP", "test port mapping", 0);
|
||||
printf("UpStream MaxBitRate = %s\n", GetValueFromNameValueList(&p->soap_response_data, "NewLayer1UpstreamMaxBitRate"));
|
||||
state = EAddPortMapping;
|
||||
break;
|
||||
case EAddPortMapping:
|
||||
printf("OK!\n");
|
||||
state = EFinished;
|
||||
default:
|
||||
event_base_loopbreak(base);
|
||||
}
|
||||
} else {
|
||||
printf("SOAP error :\n");
|
||||
printf(" faultcode='%s'\n", GetValueFromNameValueList(&p->soap_response_data, "faultcode"));
|
||||
printf(" faultstring='%s'\n", GetValueFromNameValueList(&p->soap_response_data, "faultstring"));
|
||||
printf(" errorCode=%s\n", GetValueFromNameValueList(&p->soap_response_data, "errorCode"));
|
||||
printf(" errorDescription='%s'\n", GetValueFromNameValueList(&p->soap_response_data, "errorDescription"));
|
||||
event_base_loopbreak(base);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* program entry point */
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
struct sigaction sa;
|
||||
upnpc_t upnp;
|
||||
char * multicast_if = NULL;
|
||||
|
||||
if(argc > 1) {
|
||||
multicast_if = argv[1];
|
||||
}
|
||||
|
||||
memset(&sa, 0, sizeof(struct sigaction));
|
||||
sa.sa_handler = sighandler;
|
||||
if(sigaction(SIGINT, &sa, NULL) < 0) {
|
||||
perror("sigaction");
|
||||
}
|
||||
#ifdef DEBUG
|
||||
event_enable_debug_mode();
|
||||
#if LIBEVENT_VERSION_NUMBER >= 0x02010100
|
||||
event_enable_debug_logging(EVENT_DBG_ALL); /* Libevent 2.1.1 */
|
||||
#endif /* LIBEVENT_VERSION_NUMBER >= 0x02010100 */
|
||||
#endif /* DEBUG */
|
||||
printf("Using libevent %s\n", event_get_version());
|
||||
if(LIBEVENT_VERSION_NUMBER != event_get_version_number()) {
|
||||
fprintf(stderr, "WARNING build using libevent %s", LIBEVENT_VERSION);
|
||||
}
|
||||
|
||||
base = event_base_new();
|
||||
if(base == NULL) {
|
||||
fprintf(stderr, "event_base_new() failed\n");
|
||||
return 1;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("Using Libevent with backend method %s.\n",
|
||||
event_base_get_method(base));
|
||||
#endif /* DEBUG */
|
||||
|
||||
if(upnpc_init(&upnp, base, multicast_if, ready, soap, &upnp) != UPNPC_OK) {
|
||||
fprintf(stderr, "upnpc_init() failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
event_base_dispatch(base); /* TODO : check return value */
|
||||
printf("finishing...\n");
|
||||
|
||||
upnpc_finalize(&upnp);
|
||||
event_base_free(base);
|
||||
|
||||
#if LIBEVENT_VERSION_NUMBER >= 0x02010100
|
||||
libevent_global_shutdown(); /* Libevent 2.1.1 */
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
/* $Id: upnpreplyparse.c,v 1.18 2014/11/05 05:36:08 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "upnpreplyparse.h"
|
||||
#include "minixml.h"
|
||||
|
||||
static void
|
||||
NameValueParserStartElt(void * d, const char * name, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
data->topelt = 1;
|
||||
if(l>63)
|
||||
l = 63;
|
||||
memcpy(data->curelt, name, l);
|
||||
data->curelt[l] = '\0';
|
||||
data->cdata = NULL;
|
||||
data->cdatalen = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
NameValueParserEndElt(void * d, const char * name, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
struct NameValue * nv;
|
||||
(void)name;
|
||||
(void)l;
|
||||
if(!data->topelt)
|
||||
return;
|
||||
if(strcmp(data->curelt, "NewPortListing") != 0)
|
||||
{
|
||||
int l;
|
||||
/* standard case. Limited to n chars strings */
|
||||
l = data->cdatalen;
|
||||
nv = malloc(sizeof(struct NameValue));
|
||||
if(l>=(int)sizeof(nv->value))
|
||||
l = sizeof(nv->value) - 1;
|
||||
strncpy(nv->name, data->curelt, 64);
|
||||
nv->name[63] = '\0';
|
||||
if(data->cdata != NULL)
|
||||
{
|
||||
memcpy(nv->value, data->cdata, l);
|
||||
nv->value[l] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
nv->value[0] = '\0';
|
||||
}
|
||||
nv->l_next = data->l_head; /* insert in list */
|
||||
data->l_head = nv;
|
||||
}
|
||||
data->cdata = NULL;
|
||||
data->cdatalen = 0;
|
||||
data->topelt = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
NameValueParserGetData(void * d, const char * datas, int l)
|
||||
{
|
||||
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||
if(strcmp(data->curelt, "NewPortListing") == 0)
|
||||
{
|
||||
/* specific case for NewPortListing which is a XML Document */
|
||||
data->portListing = malloc(l + 1);
|
||||
if(!data->portListing)
|
||||
{
|
||||
/* malloc error */
|
||||
return;
|
||||
}
|
||||
memcpy(data->portListing, datas, l);
|
||||
data->portListing[l] = '\0';
|
||||
data->portListingLength = l;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* standard case. */
|
||||
data->cdata = datas;
|
||||
data->cdatalen = l;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParseNameValue(const char * buffer, int bufsize,
|
||||
struct NameValueParserData * data)
|
||||
{
|
||||
struct xmlparser parser;
|
||||
data->l_head = NULL;
|
||||
data->portListing = NULL;
|
||||
data->portListingLength = 0;
|
||||
/* init xmlparser object */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = data;
|
||||
parser.starteltfunc = NameValueParserStartElt;
|
||||
parser.endeltfunc = NameValueParserEndElt;
|
||||
parser.datafunc = NameValueParserGetData;
|
||||
parser.attfunc = 0;
|
||||
parsexml(&parser);
|
||||
}
|
||||
|
||||
void
|
||||
ClearNameValueList(struct NameValueParserData * pdata)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
if(pdata->portListing)
|
||||
{
|
||||
free(pdata->portListing);
|
||||
pdata->portListing = NULL;
|
||||
pdata->portListingLength = 0;
|
||||
}
|
||||
while((nv = pdata->l_head) != NULL)
|
||||
{
|
||||
pdata->l_head = nv->l_next;
|
||||
free(nv);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||
const char * Name)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
char * p = NULL;
|
||||
for(nv = pdata->l_head;
|
||||
(nv != NULL) && (p == NULL);
|
||||
nv = nv->l_next)
|
||||
{
|
||||
if(strcmp(nv->name, Name) == 0)
|
||||
p = nv->value;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* useless now that minixml ignores namespaces by itself */
|
||||
char *
|
||||
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
|
||||
const char * Name)
|
||||
{
|
||||
struct NameValue * nv;
|
||||
char * p = NULL;
|
||||
char * pname;
|
||||
for(nv = pdata->head.lh_first;
|
||||
(nv != NULL) && (p == NULL);
|
||||
nv = nv->entries.le_next)
|
||||
{
|
||||
pname = strrchr(nv->name, ':');
|
||||
if(pname)
|
||||
pname++;
|
||||
else
|
||||
pname = nv->name;
|
||||
if(strcmp(pname, Name)==0)
|
||||
p = nv->value;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* debug all-in-one function
|
||||
* do parsing then display to stdout */
|
||||
#ifdef DEBUG
|
||||
void
|
||||
DisplayNameValueList(char * buffer, int bufsize)
|
||||
{
|
||||
struct NameValueParserData pdata;
|
||||
struct NameValue * nv;
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
for(nv = pdata.l_head;
|
||||
nv != NULL;
|
||||
nv = nv->l_next)
|
||||
{
|
||||
printf("%s = %s\n", nv->name, nv->value);
|
||||
}
|
||||
ClearNameValueList(&pdata);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2013 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#ifndef UPNPREPLYPARSE_H_INCLUDED
|
||||
#define UPNPREPLYPARSE_H_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct NameValue {
|
||||
struct NameValue * l_next;
|
||||
char name[64];
|
||||
char value[128];
|
||||
};
|
||||
|
||||
struct NameValueParserData {
|
||||
struct NameValue * l_head;
|
||||
char curelt[64];
|
||||
char * portListing;
|
||||
int portListingLength;
|
||||
int topelt;
|
||||
const char * cdata;
|
||||
int cdatalen;
|
||||
};
|
||||
|
||||
/* ParseNameValue() */
|
||||
void
|
||||
ParseNameValue(const char * buffer, int bufsize,
|
||||
struct NameValueParserData * data);
|
||||
|
||||
/* ClearNameValueList() */
|
||||
void
|
||||
ClearNameValueList(struct NameValueParserData * pdata);
|
||||
|
||||
/* GetValueFromNameValueList() */
|
||||
char *
|
||||
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||
const char * Name);
|
||||
|
||||
#if 0
|
||||
/* GetValueFromNameValueListIgnoreNS() */
|
||||
char *
|
||||
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
|
||||
const char * Name);
|
||||
#endif
|
||||
|
||||
/* DisplayNameValueList() */
|
||||
#ifdef DEBUG
|
||||
void
|
||||
DisplayNameValueList(char * buffer, int bufsize);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -8,6 +8,7 @@ build/
|
|||
Makefile.bak
|
||||
miniupnpcstrings.h
|
||||
pythonmodule
|
||||
pythonmodule3
|
||||
upnpc-shared
|
||||
upnpc-static
|
||||
minihttptestserver
|
||||
|
@ -22,4 +23,6 @@ jnaerator-*.jar
|
|||
miniupnpc.h.bak
|
||||
testupnpreplyparse
|
||||
validateupnpreplyparse
|
||||
testportlistingparse
|
||||
validateportlistingparse
|
||||
listdevices
|
||||
|
|
|
@ -36,7 +36,7 @@ else (NOT WIN32)
|
|||
endif (NOT WIN32)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
add_definitions (-DMACOSX -D_DARWIN_C_SOURCE)
|
||||
add_definitions (-D_DARWIN_C_SOURCE)
|
||||
endif ()
|
||||
|
||||
# Set compiler specific build flags
|
||||
|
@ -86,7 +86,7 @@ endif (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
|
|||
|
||||
if (WIN32)
|
||||
set_source_files_properties (${MINIUPNPC_SOURCES} PROPERTIES
|
||||
COMPILE_DEFINITIONS STATICLIB
|
||||
COMPILE_DEFINITIONS MINIUPNP_STATICLIB
|
||||
COMPILE_DEFINITIONS MINIUPNP_EXPORTS
|
||||
)
|
||||
endif (WIN32)
|
||||
|
@ -165,6 +165,8 @@ install (FILES
|
|||
igd_desc_parse.h
|
||||
upnpreplyparse.h
|
||||
upnperrors.h
|
||||
miniupnpctypes.h
|
||||
portlistingparse.h
|
||||
declspec.h
|
||||
DESTINATION include/miniupnpc
|
||||
)
|
||||
|
|
|
@ -1,6 +1,24 @@
|
|||
$Id: Changelog.txt,v 1.193 2014/02/05 17:26:45 nanard Exp $
|
||||
$Id: Changelog.txt,v 1.199 2014/11/05 06:06:37 nanard Exp $
|
||||
miniUPnP client Changelog.
|
||||
|
||||
2014/11/05:
|
||||
simplified function GetUPNPUrls()
|
||||
|
||||
2014/09/11:
|
||||
use remoteHost arg of DeletePortMapping
|
||||
|
||||
2014/09/06:
|
||||
Fix python3 build
|
||||
|
||||
2014/07/01:
|
||||
Fix parsing of IGD2 root descriptions
|
||||
|
||||
2014/06/10:
|
||||
rename LIBSPEC to MINIUPNP_LIBSPEC
|
||||
|
||||
2014/05/15:
|
||||
Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange
|
||||
|
||||
2014/02/05:
|
||||
handle EINPROGRESS after connect()
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
MiniUPnPc
|
||||
Copyright (c) 2005-2011, Thomas BERNARD
|
||||
Copyright (c) 2005-2014, Thomas BERNARD
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $Id: Makefile,v 1.105 2013/05/14 20:37:36 nanard Exp $
|
||||
# $Id: Makefile,v 1.113 2014/11/01 10:37:32 nanard Exp $
|
||||
# MiniUPnP Project
|
||||
# http://miniupnp.free.fr/
|
||||
# http://miniupnp.tuxfamily.org/
|
||||
|
@ -59,9 +59,11 @@ APIVERSION = 11
|
|||
|
||||
SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \
|
||||
upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \
|
||||
minixmlvalid.c testupnpreplyparse.c minissdpc.c \
|
||||
upnperrors.c testigddescparse.c testminiwget.c \
|
||||
minixmlvalid.c testupnpreplyparse.c minissdpc.c \
|
||||
upnperrors.c testigddescparse.c testminiwget.c \
|
||||
connecthostport.c portlistingparse.c receivedata.c \
|
||||
testportlistingparse.c miniupnpcmodule.c \
|
||||
minihttptestserver.c \
|
||||
listdevices.c
|
||||
|
||||
LIBOBJS = miniwget.o minixml.o igd_desc_parse.o minisoap.o \
|
||||
|
@ -86,7 +88,7 @@ LIBRARY = libminiupnpc.a
|
|||
ifeq ($(OS), Darwin)
|
||||
SHAREDLIBRARY = libminiupnpc.dylib
|
||||
SONAME = $(basename $(SHAREDLIBRARY)).$(APIVERSION).dylib
|
||||
CFLAGS := -DMACOSX -D_DARWIN_C_SOURCE $(CFLAGS)
|
||||
CFLAGS := -D_DARWIN_C_SOURCE $(CFLAGS)
|
||||
else
|
||||
ifeq ($(JARSUFFIX), win32)
|
||||
SHAREDLIBRARY = miniupnpc.dll
|
||||
|
@ -99,7 +101,7 @@ endif
|
|||
|
||||
EXECUTABLES = upnpc-static listdevices
|
||||
EXECUTABLES_ADDTESTS = testminixml minixmlvalid testupnpreplyparse \
|
||||
testigddescparse testminiwget
|
||||
testigddescparse testminiwget testportlistingparse
|
||||
|
||||
TESTMINIXMLOBJS = minixml.o igd_desc_parse.o testminixml.o
|
||||
|
||||
|
@ -107,6 +109,8 @@ TESTMINIWGETOBJS = miniwget.o testminiwget.o connecthostport.o receivedata.o
|
|||
|
||||
TESTUPNPREPLYPARSE = testupnpreplyparse.o minixml.o upnpreplyparse.o
|
||||
|
||||
TESTPORTLISTINGPARSE = testportlistingparse.o minixml.o portlistingparse.o
|
||||
|
||||
TESTIGDDESCPARSE = testigddescparse.o igd_desc_parse.o minixml.o \
|
||||
miniupnpc.o miniwget.o upnpcommands.o upnpreplyparse.o \
|
||||
minisoap.o connecthostport.o receivedata.o \
|
||||
|
@ -140,7 +144,8 @@ all: $(LIBRARY) $(EXECUTABLES)
|
|||
|
||||
test: check
|
||||
|
||||
check: validateminixml validateminiwget validateupnpreplyparse
|
||||
check: validateminixml validateminiwget validateupnpreplyparse \
|
||||
validateportlistingparse
|
||||
|
||||
everything: all $(EXECUTABLES_ADDTESTS)
|
||||
|
||||
|
@ -173,11 +178,18 @@ validateupnpreplyparse: testupnpreplyparse testupnpreplyparse.sh
|
|||
./testupnpreplyparse.sh
|
||||
touch $@
|
||||
|
||||
validateportlistingparse: testportlistingparse
|
||||
@echo "portlistingparse validation test"
|
||||
./testportlistingparse
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
$(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h
|
||||
$(RM) $(EXECUTABLES_ADDTESTS)
|
||||
# clean python stuff
|
||||
$(RM) pythonmodule pythonmodule3
|
||||
$(RM) validateminixml validateminiwget validateupnpreplyparse
|
||||
$(RM) minihttptestserver
|
||||
$(RM) -r build/ dist/
|
||||
#python setup.py clean
|
||||
# clean jnaerator stuff
|
||||
|
@ -208,9 +220,9 @@ endif
|
|||
$(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip
|
||||
ifneq ($(OS), AmigaOS)
|
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRMAN)/man3
|
||||
$(INSTALL) man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
|
||||
$(INSTALL) -m 644 man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
|
||||
ifeq ($(OS), Linux)
|
||||
gzip $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
|
||||
gzip -f $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -253,6 +265,8 @@ testupnpreplyparse: $(TESTUPNPREPLYPARSE)
|
|||
|
||||
testigddescparse: $(TESTIGDDESCPARSE)
|
||||
|
||||
testportlistingparse: $(TESTPORTLISTINGPARSE)
|
||||
|
||||
miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh VERSION
|
||||
$(SH) updateminiupnpcstrings.sh
|
||||
|
||||
|
@ -320,4 +334,9 @@ upnperrors.o: igd_desc_parse.h
|
|||
testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.h declspec.h
|
||||
testminiwget.o: miniwget.h declspec.h
|
||||
connecthostport.o: connecthostport.h
|
||||
portlistingparse.o: portlistingparse.h declspec.h miniupnpctypes.h minixml.h
|
||||
receivedata.o: receivedata.h
|
||||
testportlistingparse.o: portlistingparse.h declspec.h miniupnpctypes.h
|
||||
miniupnpcmodule.o: miniupnpc.h declspec.h igd_desc_parse.h upnpcommands.h
|
||||
miniupnpcmodule.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h
|
||||
miniupnpcmodule.o: upnperrors.h
|
||||
|
|
|
@ -50,11 +50,11 @@ dll/upnpc.o: upnpc.o
|
|||
echo $@ generated with $<
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -DSTATICLIB -c -o $@ $<
|
||||
$(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $<
|
||||
$(CC) $(CFLAGS) -DMINIUPNP_EXPORTS -c -o dll/$@ $<
|
||||
|
||||
upnpc.o:
|
||||
$(CC) $(CFLAGS) -DSTATICLIB -c -o $@ $<
|
||||
$(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $<
|
||||
$(CC) $(CFLAGS) -c -o dll/$@ $<
|
||||
|
||||
# --enable-stdcall-fixup
|
||||
|
|
|
@ -3,16 +3,11 @@ Project web page: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
|||
github: https://github.com/miniupnp/miniupnp
|
||||
freecode: http://freecode.com/projects/miniupnp
|
||||
Author: Thomas Bernard
|
||||
Copyright (c) 2005-2012 Thomas Bernard
|
||||
Copyright (c) 2005-2014 Thomas Bernard
|
||||
This software is subject to the conditions detailed in the
|
||||
LICENSE file provided within this distribution.
|
||||
|
||||
|
||||
For the comfort of Win32 users, bsdqueue.h is included in the distribution.
|
||||
Its licence is included in the header of the file.
|
||||
bsdqueue.h is a copy of the sys/queue.h of an OpenBSD system.
|
||||
|
||||
|
||||
* miniUPnP Client - miniUPnPc *
|
||||
|
||||
To compile, simply run 'gmake' (could be 'make' on your system).
|
||||
|
|
|
@ -1,531 +0,0 @@
|
|||
/* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */
|
||||
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
*/
|
||||
|
||||
#ifndef _SYS_QUEUE_H_
|
||||
#define _SYS_QUEUE_H_
|
||||
|
||||
/*
|
||||
* This file defines five types of data structures: singly-linked lists,
|
||||
* lists, simple queues, tail queues, and circular queues.
|
||||
*
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The elements
|
||||
* are singly linked for minimum space and pointer manipulation overhead at
|
||||
* the expense of O(n) removal for arbitrary elements. New elements can be
|
||||
* added to the list after an existing element or at the head of the list.
|
||||
* Elements being removed from the head of the list should use the explicit
|
||||
* macro for this purpose for optimum efficiency. A singly-linked list may
|
||||
* only be traversed in the forward direction. Singly-linked lists are ideal
|
||||
* for applications with large datasets and few or no removals or for
|
||||
* implementing a LIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may only be traversed in the forward direction.
|
||||
*
|
||||
* A simple queue is headed by a pair of pointers, one the head of the
|
||||
* list and the other to the tail of the list. The elements are singly
|
||||
* linked to save space, so elements can only be removed from the
|
||||
* head of the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the
|
||||
* list. A simple queue may only be traversed in the forward direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the list.
|
||||
* A circle queue may be traversed in either direction, but has a more
|
||||
* complex end of list detection.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*/
|
||||
|
||||
#ifdef QUEUE_MACRO_DEBUG
|
||||
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
|
||||
#else
|
||||
#define _Q_INVALIDATE(a)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Singly-linked List definitions.
|
||||
*/
|
||||
#define SLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#ifdef SLIST_ENTRY
|
||||
#undef SLIST_ENTRY
|
||||
#endif
|
||||
|
||||
#define SLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List access methods.
|
||||
*/
|
||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||
#define SLIST_END(head) NULL
|
||||
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
|
||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
#define SLIST_FOREACH(var, head, field) \
|
||||
for((var) = SLIST_FIRST(head); \
|
||||
(var) != SLIST_END(head); \
|
||||
(var) = SLIST_NEXT(var, field))
|
||||
|
||||
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
|
||||
for ((varp) = &SLIST_FIRST((head)); \
|
||||
((var) = *(varp)) != SLIST_END(head); \
|
||||
(varp) = &SLIST_NEXT((var), field))
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define SLIST_INIT(head) { \
|
||||
SLIST_FIRST(head) = SLIST_END(head); \
|
||||
}
|
||||
|
||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||
(slistelm)->field.sle_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_NEXT(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->slh_first == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
struct type *curelm = (head)->slh_first; \
|
||||
\
|
||||
while (curelm->field.sle_next != (elm)) \
|
||||
curelm = curelm->field.sle_next; \
|
||||
curelm->field.sle_next = \
|
||||
curelm->field.sle_next->field.sle_next; \
|
||||
_Q_INVALIDATE((elm)->field.sle_next); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* List definitions.
|
||||
*/
|
||||
#define LIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define LIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List access methods
|
||||
*/
|
||||
#define LIST_FIRST(head) ((head)->lh_first)
|
||||
#define LIST_END(head) NULL
|
||||
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
|
||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for((var) = LIST_FIRST(head); \
|
||||
(var)!= LIST_END(head); \
|
||||
(var) = LIST_NEXT(var, field))
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
#define LIST_INIT(head) do { \
|
||||
LIST_FIRST(head) = LIST_END(head); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||
(listelm)->field.le_next->field.le_prev = \
|
||||
&(elm)->field.le_next; \
|
||||
(listelm)->field.le_next = (elm); \
|
||||
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
(elm)->field.le_next = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||
(head)->lh_first = (elm); \
|
||||
(elm)->field.le_prev = &(head)->lh_first; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_REMOVE(elm, field) do { \
|
||||
if ((elm)->field.le_next != NULL) \
|
||||
(elm)->field.le_next->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||
_Q_INVALIDATE((elm)->field.le_next); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_REPLACE(elm, elm2, field) do { \
|
||||
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
||||
(elm2)->field.le_next->field.le_prev = \
|
||||
&(elm2)->field.le_next; \
|
||||
(elm2)->field.le_prev = (elm)->field.le_prev; \
|
||||
*(elm2)->field.le_prev = (elm2); \
|
||||
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||
_Q_INVALIDATE((elm)->field.le_next); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Simple queue definitions.
|
||||
*/
|
||||
#define SIMPLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sqh_first; /* first element */ \
|
||||
struct type **sqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define SIMPLEQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).sqh_first }
|
||||
|
||||
#define SIMPLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple queue access methods.
|
||||
*/
|
||||
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||
#define SIMPLEQ_END(head) NULL
|
||||
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
|
||||
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||
|
||||
#define SIMPLEQ_FOREACH(var, head, field) \
|
||||
for((var) = SIMPLEQ_FIRST(head); \
|
||||
(var) != SIMPLEQ_END(head); \
|
||||
(var) = SIMPLEQ_NEXT(var, field))
|
||||
|
||||
/*
|
||||
* Simple queue functions.
|
||||
*/
|
||||
#define SIMPLEQ_INIT(head) do { \
|
||||
(head)->sqh_first = NULL; \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(head)->sqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.sqe_next = NULL; \
|
||||
*(head)->sqh_last = (elm); \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(listelm)->field.sqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
|
||||
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Tail queue definitions.
|
||||
*/
|
||||
#define TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *tqh_first; /* first element */ \
|
||||
struct type **tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* tail queue access methods
|
||||
*/
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define TAILQ_END(head) NULL
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
/* XXX */
|
||||
#define TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
#define TAILQ_EMPTY(head) \
|
||||
(TAILQ_FIRST(head) == TAILQ_END(head))
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for((var) = TAILQ_FIRST(head); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_NEXT(var, field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for((var) = TAILQ_LAST(head, headname); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_PREV(var, headname, field))
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define TAILQ_INIT(head) do { \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(listelm)->field.tqe_next = (elm); \
|
||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
_Q_INVALIDATE((elm)->field.tqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.tqe_next); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
|
||||
(elm2)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm2)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm2)->field.tqe_next; \
|
||||
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||
*(elm2)->field.tqe_prev = (elm2); \
|
||||
_Q_INVALIDATE((elm)->field.tqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.tqe_next); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Circular queue definitions.
|
||||
*/
|
||||
#define CIRCLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *cqh_first; /* first element */ \
|
||||
struct type *cqh_last; /* last element */ \
|
||||
}
|
||||
|
||||
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
|
||||
|
||||
#define CIRCLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *cqe_next; /* next element */ \
|
||||
struct type *cqe_prev; /* previous element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Circular queue access methods
|
||||
*/
|
||||
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||
#define CIRCLEQ_END(head) ((void *)(head))
|
||||
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
||||
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
||||
#define CIRCLEQ_EMPTY(head) \
|
||||
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
|
||||
|
||||
#define CIRCLEQ_FOREACH(var, head, field) \
|
||||
for((var) = CIRCLEQ_FIRST(head); \
|
||||
(var) != CIRCLEQ_END(head); \
|
||||
(var) = CIRCLEQ_NEXT(var, field))
|
||||
|
||||
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||
for((var) = CIRCLEQ_LAST(head); \
|
||||
(var) != CIRCLEQ_END(head); \
|
||||
(var) = CIRCLEQ_PREV(var, field))
|
||||
|
||||
/*
|
||||
* Circular queue functions.
|
||||
*/
|
||||
#define CIRCLEQ_INIT(head) do { \
|
||||
(head)->cqh_first = CIRCLEQ_END(head); \
|
||||
(head)->cqh_last = CIRCLEQ_END(head); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||
(elm)->field.cqe_prev = (listelm); \
|
||||
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||
(listelm)->field.cqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm); \
|
||||
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||
(listelm)->field.cqe_prev = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
|
||||
if ((head)->cqh_last == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||
(head)->cqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = CIRCLEQ_END(head); \
|
||||
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||
if ((head)->cqh_first == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(head)->cqh_last->field.cqe_next = (elm); \
|
||||
(head)->cqh_last = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||
else \
|
||||
(elm)->field.cqe_next->field.cqe_prev = \
|
||||
(elm)->field.cqe_prev; \
|
||||
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||
else \
|
||||
(elm)->field.cqe_prev->field.cqe_next = \
|
||||
(elm)->field.cqe_next; \
|
||||
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.cqe_next); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_last = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
|
||||
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_first = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
|
||||
_Q_INVALIDATE((elm)->field.cqe_prev); \
|
||||
_Q_INVALIDATE((elm)->field.cqe_next); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !_SYS_QUEUE_H_ */
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: connecthostport.c,v 1.12 2014/02/05 17:26:46 nanard Exp $ */
|
||||
/* $Id: connecthostport.c,v 1.13 2014/03/31 12:36:36 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2010-2014 Thomas Bernard
|
||||
|
@ -35,6 +35,7 @@
|
|||
#ifndef USE_GETHOSTBYNAME
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#endif /* #ifndef USE_GETHOSTBYNAME */
|
||||
#endif /* #else _WIN32 */
|
||||
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
#ifndef DECLSPEC_H_INCLUDED
|
||||
#define DECLSPEC_H_INCLUDED
|
||||
|
||||
#if defined(_WIN32) && !defined(STATICLIB)
|
||||
#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB)
|
||||
/* for windows dll */
|
||||
#ifdef MINIUPNP_EXPORTS
|
||||
#define LIBSPEC __declspec(dllexport)
|
||||
#define MINIUPNP_LIBSPEC __declspec(dllexport)
|
||||
#else
|
||||
#define LIBSPEC __declspec(dllimport)
|
||||
#define MINIUPNP_LIBSPEC __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
/* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */
|
||||
#define LIBSPEC __attribute__ ((visibility ("default")))
|
||||
#define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define LIBSPEC
|
||||
#define MINIUPNP_LIBSPEC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* $Id: igd_desc_parse.c,v 1.14 2011/04/11 09:19:24 nanard Exp $ */
|
||||
/* $Id: igd_desc_parse.c,v 1.15 2014/07/01 13:01:17 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2010 Thomas Bernard
|
||||
* Copyright (c) 2005-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution. */
|
||||
|
||||
|
@ -26,6 +26,8 @@ void IGDstartelt(void * d, const char * name, int l)
|
|||
}
|
||||
}
|
||||
|
||||
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
|
||||
|
||||
/* End element handler :
|
||||
* update nesting level counter and update parser state if
|
||||
* service element is parsed */
|
||||
|
@ -36,23 +38,16 @@ void IGDendelt(void * d, const char * name, int l)
|
|||
/*printf("endelt %2d %.*s\n", datas->level, l, name);*/
|
||||
if( (l==7) && !memcmp(name, "service", l) )
|
||||
{
|
||||
/*
|
||||
if( datas->state < 1
|
||||
&& !strcmp(datas->servicetype,
|
||||
// "urn:schemas-upnp-org:service:WANIPConnection:1") )
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"))
|
||||
datas->state ++;
|
||||
*/
|
||||
if(0==strcmp(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) {
|
||||
if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) {
|
||||
memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else if(0==strcmp(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1")) {
|
||||
} else if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) {
|
||||
memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else if(0==strcmp(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:1")
|
||||
|| 0==strcmp(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:1") ) {
|
||||
} else if(COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANIPConnection:")
|
||||
|| COMPARE(datas->tmp.servicetype,
|
||||
"urn:schemas-upnp-org:service:WANPPPConnection:") ) {
|
||||
if(datas->first.servicetype[0] == '\0') {
|
||||
memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||
} else {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $Id: minisoap.c,v 1.22 2012/01/21 13:30:31 nanard Exp $ */
|
||||
/* $Id: minisoap.c,v 1.23 2014/11/04 22:31:55 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2012 Thomas Bernard
|
||||
* Copyright (c) 2005-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
*
|
||||
|
@ -96,7 +96,7 @@ int soapPostSubmit(int fd,
|
|||
headerssize = snprintf(headerbuf, sizeof(headerbuf),
|
||||
"POST %s HTTP/%s\r\n"
|
||||
"Host: %s%s\r\n"
|
||||
"User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
|
||||
"User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"Content-Type: text/xml\r\n"
|
||||
"SOAPAction: \"%s\"\r\n"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: miniupnpc.c,v 1.116 2014/01/31 14:09:03 nanard Exp $ */
|
||||
/* $Id: miniupnpc.c,v 1.120 2014/11/05 06:06:38 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD
|
||||
|
@ -6,7 +6,7 @@
|
|||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENSE file. */
|
||||
#define __EXTENSIONS__ 1
|
||||
#if !defined(MACOSX) && !defined(__sun)
|
||||
#if !defined(__APPLE__) && !defined(__sun)
|
||||
#if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__)
|
||||
#ifndef __cplusplus
|
||||
#define _XOPEN_SOURCE 600
|
||||
|
@ -17,7 +17,7 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(MACOSX) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun)
|
||||
#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__)
|
||||
#define HAS_IP_MREQN
|
||||
#endif
|
||||
|
||||
|
@ -70,6 +70,9 @@
|
|||
/* Amiga OS specific stuff */
|
||||
#define TIMEVAL struct timeval
|
||||
#endif
|
||||
#ifdef __GNU__
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN)
|
||||
|
@ -106,7 +109,7 @@ struct ip_mreqn
|
|||
#define SERVICEPREFIX2 'u'
|
||||
|
||||
/* root description parsing */
|
||||
LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
|
||||
MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data)
|
||||
{
|
||||
struct xmlparser parser;
|
||||
/* xmlparser object */
|
||||
|
@ -335,7 +338,7 @@ parseMSEARCHReply(const char * reply, int size,
|
|||
* no devices was found.
|
||||
* It is up to the caller to free the chained list
|
||||
* delay is in millisecond (poll) */
|
||||
LIBSPEC struct UPNPDev *
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscoverDevices(const char * const deviceTypes[],
|
||||
int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int sameport,
|
||||
|
@ -765,7 +768,7 @@ upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
|
|||
|
||||
/* freeUPNPDevlist() should be used to
|
||||
* free the chained list returned by upnpDiscover() */
|
||||
LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist)
|
||||
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist)
|
||||
{
|
||||
struct UPNPDev * next;
|
||||
while(devlist)
|
||||
|
@ -776,122 +779,106 @@ LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
url_cpy_or_cat(char * dst, const char * src, int n)
|
||||
{
|
||||
if( (src[0] == 'h')
|
||||
&&(src[1] == 't')
|
||||
&&(src[2] == 't')
|
||||
&&(src[3] == 'p')
|
||||
&&(src[4] == ':')
|
||||
&&(src[5] == '/')
|
||||
&&(src[6] == '/'))
|
||||
{
|
||||
strncpy(dst, src, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
int l = strlen(dst);
|
||||
if(src[0] != '/')
|
||||
dst[l++] = '/';
|
||||
if(l<=n)
|
||||
strncpy(dst + l, src, n - l);
|
||||
}
|
||||
}
|
||||
|
||||
/* Prepare the Urls for usage...
|
||||
*/
|
||||
LIBSPEC void
|
||||
GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||
const char * descURL, unsigned int scope_id)
|
||||
static char *
|
||||
build_absolute_url(const char * baseurl, const char * descURL,
|
||||
const char * url, unsigned int scope_id)
|
||||
{
|
||||
int l, n;
|
||||
char * s;
|
||||
const char * base;
|
||||
char * p;
|
||||
int n1, n2, n3, n4;
|
||||
#ifdef IF_NAMESIZE
|
||||
char ifname[IF_NAMESIZE];
|
||||
#else
|
||||
char scope_str[8];
|
||||
#endif
|
||||
|
||||
n1 = strlen(data->urlbase);
|
||||
if(n1==0)
|
||||
n1 = strlen(descURL);
|
||||
if( (url[0] == 'h')
|
||||
&&(url[1] == 't')
|
||||
&&(url[2] == 't')
|
||||
&&(url[3] == 'p')
|
||||
&&(url[4] == ':')
|
||||
&&(url[5] == '/')
|
||||
&&(url[6] == '/'))
|
||||
return strdup(url);
|
||||
base = (baseurl[0] == '\0') ? descURL : baseurl;
|
||||
n = strlen(base);
|
||||
if(n > 7) {
|
||||
p = strchr(base + 7, '/');
|
||||
if(p)
|
||||
n = p - base;
|
||||
}
|
||||
l = n + strlen(url) + 1;
|
||||
if(url[0] != '/')
|
||||
l++;
|
||||
if(scope_id != 0) {
|
||||
#ifdef IF_NAMESIZE
|
||||
if(if_indextoname(scope_id, ifname)) {
|
||||
n1 += 3 + strlen(ifname); /* 3 == strlen(%25) */
|
||||
l += 3 + strlen(ifname); /* 3 == strlen(%25) */
|
||||
}
|
||||
#else
|
||||
/* under windows, scope is numerical */
|
||||
snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
|
||||
/* under windows, scope is numerical */
|
||||
l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
|
||||
#endif
|
||||
}
|
||||
n1 += 2; /* 1 byte more for Null terminator, 1 byte for '/' if needed */
|
||||
n2 = n1; n3 = n1; n4 = n1;
|
||||
n1 += strlen(data->first.scpdurl);
|
||||
n2 += strlen(data->first.controlurl);
|
||||
n3 += strlen(data->CIF.controlurl);
|
||||
n4 += strlen(data->IPv6FC.controlurl);
|
||||
|
||||
/* allocate memory to store URLs */
|
||||
urls->ipcondescURL = (char *)malloc(n1);
|
||||
urls->controlURL = (char *)malloc(n2);
|
||||
urls->controlURL_CIF = (char *)malloc(n3);
|
||||
urls->controlURL_6FC = (char *)malloc(n4);
|
||||
|
||||
/* strdup descURL */
|
||||
urls->rootdescURL = strdup(descURL);
|
||||
|
||||
/* get description of WANIPConnection */
|
||||
if(data->urlbase[0] != '\0')
|
||||
strncpy(urls->ipcondescURL, data->urlbase, n1);
|
||||
else
|
||||
strncpy(urls->ipcondescURL, descURL, n1);
|
||||
p = strchr(urls->ipcondescURL+7, '/');
|
||||
if(p) p[0] = '\0';
|
||||
s = malloc(l);
|
||||
if(s == NULL) return NULL;
|
||||
memcpy(s, base, n);
|
||||
if(scope_id != 0) {
|
||||
if(0 == memcmp(urls->ipcondescURL, "http://[fe80:", 13)) {
|
||||
s[n] = '\0';
|
||||
if(0 == memcmp(s, "http://[fe80:", 13)) {
|
||||
/* this is a linklocal IPv6 address */
|
||||
p = strchr(urls->ipcondescURL, ']');
|
||||
p = strchr(s, ']');
|
||||
if(p) {
|
||||
/* insert %25<scope> into URL */
|
||||
#ifdef IF_NAMESIZE
|
||||
memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
|
||||
memcpy(p, "%25", 3);
|
||||
memcpy(p + 3, ifname, strlen(ifname));
|
||||
n += 3 + strlen(ifname);
|
||||
#else
|
||||
memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
|
||||
memcpy(p, "%25", 3);
|
||||
memcpy(p + 3, scope_str, strlen(scope_str));
|
||||
n += 3 + strlen(scope_str);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
strncpy(urls->controlURL, urls->ipcondescURL, n2);
|
||||
strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3);
|
||||
strncpy(urls->controlURL_6FC, urls->ipcondescURL, n4);
|
||||
if(url[0] != '/')
|
||||
s[n++] = '/';
|
||||
memcpy(s + n, url, l - n);
|
||||
return s;
|
||||
}
|
||||
|
||||
url_cpy_or_cat(urls->ipcondescURL, data->first.scpdurl, n1);
|
||||
/* Prepare the Urls for usage...
|
||||
*/
|
||||
MINIUPNP_LIBSPEC void
|
||||
GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||
const char * descURL, unsigned int scope_id)
|
||||
{
|
||||
/* strdup descURL */
|
||||
urls->rootdescURL = strdup(descURL);
|
||||
|
||||
url_cpy_or_cat(urls->controlURL, data->first.controlurl, n2);
|
||||
|
||||
url_cpy_or_cat(urls->controlURL_CIF, data->CIF.controlurl, n3);
|
||||
|
||||
url_cpy_or_cat(urls->controlURL_6FC, data->IPv6FC.controlurl, n4);
|
||||
/* get description of WANIPConnection */
|
||||
urls->ipcondescURL = build_absolute_url(data->urlbase, descURL,
|
||||
data->first.scpdurl, scope_id);
|
||||
urls->controlURL = build_absolute_url(data->urlbase, descURL,
|
||||
data->first.controlurl, scope_id);
|
||||
urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL,
|
||||
data->CIF.controlurl, scope_id);
|
||||
urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL,
|
||||
data->IPv6FC.controlurl, scope_id);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("urls->ipcondescURL='%s' %u n1=%d\n", urls->ipcondescURL,
|
||||
(unsigned)strlen(urls->ipcondescURL), n1);
|
||||
printf("urls->controlURL='%s' %u n2=%d\n", urls->controlURL,
|
||||
(unsigned)strlen(urls->controlURL), n2);
|
||||
printf("urls->controlURL_CIF='%s' %u n3=%d\n", urls->controlURL_CIF,
|
||||
(unsigned)strlen(urls->controlURL_CIF), n3);
|
||||
printf("urls->controlURL_6FC='%s' %u n4=%d\n", urls->controlURL_6FC,
|
||||
(unsigned)strlen(urls->controlURL_6FC), n4);
|
||||
printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL);
|
||||
printf("urls->controlURL='%s'\n", urls->controlURL);
|
||||
printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF);
|
||||
printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC);
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBSPEC void
|
||||
MINIUPNP_LIBSPEC void
|
||||
FreeUPNPUrls(struct UPNPUrls * urls)
|
||||
{
|
||||
if(!urls)
|
||||
|
@ -938,7 +925,7 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
|
|||
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
|
||||
* free allocated memory.
|
||||
*/
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetValidIGD(struct UPNPDev * devlist,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
|
|
|
@ -24,7 +24,9 @@ EXPORTS
|
|||
UPNP_GetExternalIPAddress
|
||||
UPNP_GetLinkLayerMaxBitRates
|
||||
UPNP_AddPortMapping
|
||||
UPNP_AddAnyPortMapping
|
||||
UPNP_DeletePortMapping
|
||||
UPNP_DeletePortMappingRange
|
||||
UPNP_GetPortMappingNumberOfEntries
|
||||
UPNP_GetSpecificPortMappingEntry
|
||||
UPNP_GetGenericPortMappingEntry
|
||||
|
|
|
@ -54,7 +54,7 @@ struct UPNPDev {
|
|||
* multicast interface for sending SSDP discover packets.
|
||||
* If sameport is not null, SSDP packets will be sent from the source port
|
||||
* 1900 (same as destination port) otherwise system assign a source port. */
|
||||
LIBSPEC struct UPNPDev *
|
||||
MINIUPNP_LIBSPEC struct UPNPDev *
|
||||
upnpDiscover(int delay, const char * multicastif,
|
||||
const char * minissdpdsock, int sameport,
|
||||
int ipv6,
|
||||
|
@ -81,12 +81,12 @@ upnpDiscoverDevices(const char * const deviceTypes[],
|
|||
|
||||
/* freeUPNPDevlist()
|
||||
* free list returned by upnpDiscover() */
|
||||
LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
|
||||
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
|
||||
|
||||
/* parserootdesc() :
|
||||
* parse root XML description of a UPnP device and fill the IGDdatas
|
||||
* structure. */
|
||||
LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *);
|
||||
MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *);
|
||||
|
||||
/* structure used to get fast access to urls
|
||||
* controlURL: controlURL of the WANIPConnection
|
||||
|
@ -114,7 +114,7 @@ struct UPNPUrls {
|
|||
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
|
||||
* free allocated memory.
|
||||
*/
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetValidIGD(struct UPNPDev * devlist,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
|
@ -125,21 +125,21 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
|
|||
* return value :
|
||||
* 0 - Not ok
|
||||
* 1 - OK */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetIGDFromUrl(const char * rootdescurl,
|
||||
struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
char * lanaddr, int lanaddrlen);
|
||||
|
||||
LIBSPEC void
|
||||
MINIUPNP_LIBSPEC void
|
||||
GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *,
|
||||
const char *, unsigned int);
|
||||
|
||||
LIBSPEC void
|
||||
MINIUPNP_LIBSPEC void
|
||||
FreeUPNPUrls(struct UPNPUrls *);
|
||||
|
||||
/* return 0 or 1 */
|
||||
LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
|
||||
MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: miniupnpcmodule.c,v 1.22 2014/01/31 13:18:25 nanard Exp $*/
|
||||
/* $Id: miniupnpcmodule.c,v 1.24 2014/06/10 09:48:11 nanard Exp $*/
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas BERNARD
|
||||
* website : http://miniupnp.tuxfamily.org/
|
||||
|
@ -6,7 +6,7 @@
|
|||
* This software is subjet to the conditions detailed in the
|
||||
* provided LICENCE file. */
|
||||
#include <Python.h>
|
||||
#define STATICLIB
|
||||
#define MINIUPNP_STATICLIB
|
||||
#include "structmember.h"
|
||||
#include "miniupnpc.h"
|
||||
#include "upnpcommands.h"
|
||||
|
@ -265,6 +265,42 @@ Py_END_ALLOW_THREADS
|
|||
}
|
||||
}
|
||||
|
||||
/* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc,
|
||||
* remoteHost)
|
||||
* protocol is 'UDP' or 'TCP' */
|
||||
static PyObject *
|
||||
UPnP_addanyportmapping(UPnPObject *self, PyObject *args)
|
||||
{
|
||||
char extPort[6];
|
||||
unsigned short ePort;
|
||||
char inPort[6];
|
||||
unsigned short iPort;
|
||||
char reservedPort[6];
|
||||
const char * proto;
|
||||
const char * host;
|
||||
const char * desc;
|
||||
const char * remoteHost;
|
||||
const char * leaseDuration = "0";
|
||||
int r;
|
||||
if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto, &host, &iPort, &desc, &remoteHost))
|
||||
return NULL;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
sprintf(extPort, "%hu", ePort);
|
||||
sprintf(inPort, "%hu", iPort);
|
||||
r = UPNP_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype,
|
||||
extPort, inPort, host, desc, proto,
|
||||
remoteHost, leaseDuration, reservedPort);
|
||||
Py_END_ALLOW_THREADS
|
||||
if(r==UPNPCOMMAND_SUCCESS) {
|
||||
return Py_BuildValue("i", atoi(reservedPort));
|
||||
} else {
|
||||
/* TODO: have our own exception type ! */
|
||||
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* DeletePortMapping(extPort, proto, removeHost='')
|
||||
* proto = 'UDP', 'TCP' */
|
||||
static PyObject *
|
||||
|
@ -291,6 +327,37 @@ Py_END_ALLOW_THREADS
|
|||
}
|
||||
}
|
||||
|
||||
/* DeletePortMappingRange(extPort, proto, removeHost='')
|
||||
* proto = 'UDP', 'TCP' */
|
||||
static PyObject *
|
||||
UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args)
|
||||
{
|
||||
char extPortStart[6];
|
||||
unsigned short ePortStart;
|
||||
char extPortEnd[6];
|
||||
unsigned short ePortEnd;
|
||||
const char * proto;
|
||||
unsigned char manage;
|
||||
char manageStr[1];
|
||||
int r;
|
||||
if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage))
|
||||
return NULL;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
sprintf(extPortStart, "%hu", ePortStart);
|
||||
sprintf(extPortEnd, "%hu", ePortEnd);
|
||||
sprintf(manageStr, "%hhu", manage);
|
||||
r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype,
|
||||
extPortStart, extPortEnd, proto, manageStr);
|
||||
Py_END_ALLOW_THREADS
|
||||
if(r==UPNPCOMMAND_SUCCESS) {
|
||||
Py_RETURN_TRUE;
|
||||
} else {
|
||||
/* TODO: have our own exception type ! */
|
||||
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
UPnP_getportmappingnumberofentries(UPnPObject *self)
|
||||
{
|
||||
|
@ -429,9 +496,15 @@ static PyMethodDef UPnP_methods[] = {
|
|||
{"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,
|
||||
"add a port mapping"
|
||||
},
|
||||
{"addanyportmapping", (PyCFunction)UPnP_addanyportmapping, METH_VARARGS,
|
||||
"add a port mapping, IGD to select alternative if necessary"
|
||||
},
|
||||
{"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,
|
||||
"delete a port mapping"
|
||||
},
|
||||
{"deleteportmappingrange", (PyCFunction)UPnP_deleteportmappingrange, METH_VARARGS,
|
||||
"delete a range of port mappings"
|
||||
},
|
||||
{"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,
|
||||
"-- non standard --"
|
||||
},
|
||||
|
@ -526,7 +599,11 @@ initminiupnpc(void)
|
|||
UPnPType.tp_new = PyType_GenericNew;
|
||||
#endif
|
||||
if (PyType_Ready(&UPnPType) < 0)
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return 0;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
m = PyModule_Create(&moduledef);
|
||||
|
@ -537,7 +614,7 @@ initminiupnpc(void)
|
|||
|
||||
Py_INCREF(&UPnPType);
|
||||
PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);
|
||||
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return m;
|
||||
#endif
|
||||
|
|
|
@ -4,4 +4,12 @@
|
|||
#define OS_STRING "${CMAKE_SYSTEM_NAME}"
|
||||
#define MINIUPNPC_VERSION_STRING "${MINIUPNPC_VERSION}"
|
||||
|
||||
#if 0
|
||||
/* according to "UPnP Device Architecture 1.0" */
|
||||
#define UPNP_VERSION_STRING "UPnP/1.0"
|
||||
#else
|
||||
/* according to "UPnP Device Architecture 1.1" */
|
||||
#define UPNP_VERSION_STRING "UPnP/1.1"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* $Id: miniupnpcstrings.h.in,v 1.4 2011/01/04 11:41:53 nanard Exp $ */
|
||||
/* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */
|
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard
|
||||
* Copyright (c) 2005-2011 Thomas Bernard
|
||||
* Copyright (c) 2005-2014 Thomas Bernard
|
||||
* This software is subjects to the conditions detailed
|
||||
* in the LICENCE file provided within this distribution */
|
||||
#ifndef MINIUPNPCSTRINGS_H_INCLUDED
|
||||
|
@ -11,5 +11,13 @@
|
|||
#define OS_STRING "OS/version"
|
||||
#define MINIUPNPC_VERSION_STRING "version"
|
||||
|
||||
#if 0
|
||||
/* according to "UPnP Device Architecture 1.0" */
|
||||
#define UPNP_VERSION_STRING "UPnP/1.0"
|
||||
#else
|
||||
/* according to "UPnP Device Architecture 1.1" */
|
||||
#define UPNP_VERSION_STRING "UPnP/1.1"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: miniwget.c,v 1.61 2014/02/05 17:27:48 nanard Exp $ */
|
||||
/* $Id: miniwget.c,v 1.65 2014/11/04 22:31:55 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard
|
||||
|
@ -15,7 +15,6 @@
|
|||
#include <ws2tcpip.h>
|
||||
#include <io.h>
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||
#define snprintf _snprintf
|
||||
#define socklen_t int
|
||||
#ifndef strncasecmp
|
||||
|
@ -40,9 +39,14 @@
|
|||
#include <netdb.h>
|
||||
#define closesocket close
|
||||
#endif /* #else _WIN32 */
|
||||
#if defined(__sun) || defined(sun)
|
||||
#ifdef __GNU__
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif /* __GNU__ */
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||
#endif
|
||||
#endif /* MIN */
|
||||
|
||||
|
||||
#include "miniupnpcstrings.h"
|
||||
#include "miniwget.h"
|
||||
|
@ -364,7 +368,7 @@ miniwget3(const char * host,
|
|||
"GET %s HTTP/%s\r\n"
|
||||
"Host: %s:%d\r\n"
|
||||
"Connection: Close\r\n"
|
||||
"User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
|
||||
"User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
|
||||
|
||||
"\r\n",
|
||||
path, httpversion, host, port);
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
LIBSPEC void * getHTTPResponse(int s, int * size);
|
||||
MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size);
|
||||
|
||||
LIBSPEC void * miniwget(const char *, int *, unsigned int);
|
||||
MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int);
|
||||
|
||||
LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int);
|
||||
MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int);
|
||||
|
||||
int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *);
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;WIN32;STATICLIB;DEBUG"
|
||||
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB;DEBUG"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
|
@ -104,7 +104,7 @@
|
|||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;WIN32;STATICLIB"
|
||||
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
|
@ -198,10 +198,6 @@
|
|||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\bsdqueue.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\connecthostport.h"
|
||||
>
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;STATICLIB;DEBUG;_CRT_SECURE_NO_WARNINGS"
|
||||
PreprocessorDefinitions="_DEBUG;_CONSOLE;MINIUPNP_STATICLIB;DEBUG;_CRT_SECURE_NO_WARNINGS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
|
@ -115,7 +115,7 @@
|
|||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;STATICLIB"
|
||||
PreprocessorDefinitions="NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;MINIUPNP_STATICLIB"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: portlistingparse.c,v 1.6 2012/05/29 10:26:51 nanard Exp $ */
|
||||
/* $Id: portlistingparse.c,v 1.7 2014/11/01 10:37:32 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2011 Thomas Bernard
|
||||
|
@ -62,7 +62,8 @@ startelt(void * d, const char * name, int l)
|
|||
{
|
||||
struct PortMapping * pm;
|
||||
pm = calloc(1, sizeof(struct PortMapping));
|
||||
LIST_INSERT_HEAD( &(pdata->head), pm, entries);
|
||||
pm->l_next = pdata->l_head; /* insert in list */
|
||||
pdata->l_head = pm;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,7 +83,7 @@ data(void * d, const char * data, int l)
|
|||
{
|
||||
struct PortMapping * pm;
|
||||
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
|
||||
pm = pdata->head.lh_first;
|
||||
pm = pdata->l_head;
|
||||
if(!pm)
|
||||
return;
|
||||
if(l > 63)
|
||||
|
@ -134,7 +135,6 @@ ParsePortListing(const char * buffer, int bufsize,
|
|||
struct xmlparser parser;
|
||||
|
||||
memset(pdata, 0, sizeof(struct PortMappingParserData));
|
||||
LIST_INIT(&(pdata->head));
|
||||
/* init xmlparser */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
|
@ -150,9 +150,10 @@ void
|
|||
FreePortListing(struct PortMappingParserData * pdata)
|
||||
{
|
||||
struct PortMapping * pm;
|
||||
while((pm = pdata->head.lh_first) != NULL)
|
||||
while((pm = pdata->l_head) != NULL)
|
||||
{
|
||||
LIST_REMOVE(pm, entries);
|
||||
/* remove from list */
|
||||
pdata->l_head = pm->l_next;
|
||||
free(pm);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: portlistingparse.h,v 1.5 2012/01/21 13:30:33 nanard Exp $ */
|
||||
/* $Id: portlistingparse.h,v 1.10 2014/11/01 10:37:32 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2011-2012 Thomas Bernard
|
||||
|
@ -11,12 +11,6 @@
|
|||
/* for the definition of UNSIGNED_INTEGER */
|
||||
#include "miniupnpctypes.h"
|
||||
|
||||
#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__)
|
||||
#include "bsdqueue.h"
|
||||
#else
|
||||
#include <sys/queue.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -41,7 +35,7 @@ typedef enum { PortMappingEltNone,
|
|||
NewLeaseTime } portMappingElt;
|
||||
|
||||
struct PortMapping {
|
||||
LIST_ENTRY(PortMapping) entries;
|
||||
struct PortMapping * l_next; /* list next element */
|
||||
UNSIGNED_INTEGER leaseTime;
|
||||
unsigned short externalPort;
|
||||
unsigned short internalPort;
|
||||
|
@ -53,15 +47,15 @@ struct PortMapping {
|
|||
};
|
||||
|
||||
struct PortMappingParserData {
|
||||
LIST_HEAD(portmappinglisthead, PortMapping) head;
|
||||
struct PortMapping * l_head; /* list head */
|
||||
portMappingElt curelt;
|
||||
};
|
||||
|
||||
LIBSPEC void
|
||||
MINIUPNP_LIBSPEC void
|
||||
ParsePortListing(const char * buffer, int bufsize,
|
||||
struct PortMappingParserData * pdata);
|
||||
|
||||
LIBSPEC void
|
||||
MINIUPNP_LIBSPEC void
|
||||
FreePortListing(struct PortMappingParserData * pdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#! /usr/bin/python
|
||||
# $Id: setup.py,v 1.9 2012/05/23 08:50:10 nanard Exp $
|
||||
# the MiniUPnP Project (c) 2007-2012 Thomas Bernard
|
||||
# the MiniUPnP Project (c) 2007-2014 Thomas Bernard
|
||||
# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
|
||||
#
|
||||
# python script to build the miniupnpc module under unix
|
||||
|
@ -10,9 +10,15 @@ from distutils.core import setup, Extension
|
|||
from distutils import sysconfig
|
||||
sysconfig.get_config_vars()["OPT"] = ''
|
||||
sysconfig.get_config_vars()["CFLAGS"] = ''
|
||||
setup(name="miniupnpc", version="1.7",
|
||||
setup(name="miniupnpc",
|
||||
version=open('VERSION').read().strip(),
|
||||
author='Thomas BERNARD',
|
||||
author_email='miniupnp@free.fr',
|
||||
license=open('LICENSE').read(),
|
||||
url='http://miniupnp.free.fr/',
|
||||
description='miniUPnP client',
|
||||
ext_modules=[
|
||||
Extension(name="miniupnpc", sources=["miniupnpcmodule.c"],
|
||||
extra_objects=["libminiupnpc.a"])
|
||||
])
|
||||
Extension(name="miniupnpc", sources=["miniupnpcmodule.c"],
|
||||
extra_objects=["libminiupnpc.a"])
|
||||
])
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#! /usr/bin/python
|
||||
# $Id: setupmingw32.py,v 1.8 2012/05/23 08:50:10 nanard Exp $
|
||||
# the MiniUPnP Project (c) 2007-2012 Thomas Bernard
|
||||
# the MiniUPnP Project (c) 2007-2014 Thomas Bernard
|
||||
# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
|
||||
#
|
||||
# python script to build the miniupnpc module under windows (using mingw32)
|
||||
|
@ -9,10 +9,16 @@ from distutils.core import setup, Extension
|
|||
from distutils import sysconfig
|
||||
sysconfig.get_config_vars()["OPT"] = ''
|
||||
sysconfig.get_config_vars()["CFLAGS"] = ''
|
||||
setup(name="miniupnpc", version="1.7",
|
||||
setup(name="miniupnpc",
|
||||
version=open('VERSION').read().strip(),
|
||||
author='Thomas BERNARD',
|
||||
author_email='miniupnp@free.fr',
|
||||
license=open('LICENSE').read(),
|
||||
url='http://miniupnp.free.fr/',
|
||||
description='miniUPnP client',
|
||||
ext_modules=[
|
||||
Extension(name="miniupnpc", sources=["miniupnpcmodule.c"],
|
||||
libraries=["ws2_32", "iphlpapi"],
|
||||
extra_objects=["libminiupnpc.a"])
|
||||
])
|
||||
Extension(name="miniupnpc", sources=["miniupnpcmodule.c"],
|
||||
libraries=["ws2_32", "iphlpapi"],
|
||||
extra_objects=["libminiupnpc.a"])
|
||||
])
|
||||
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
/* $Id: testportlistingparse.c,v 1.2 2014/11/01 10:37:32 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed in the
|
||||
* LICENCE file provided in this distribution.
|
||||
* */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "portlistingparse.h"
|
||||
|
||||
struct port_mapping {
|
||||
unsigned int leasetime;
|
||||
unsigned short externalport;
|
||||
unsigned short internalport;
|
||||
const char * remotehost;
|
||||
const char * client;
|
||||
const char * proto;
|
||||
const char * desc;
|
||||
unsigned char enabled;
|
||||
};
|
||||
|
||||
/* return the number of differences */
|
||||
int test(const char * portListingXml, int portListingXmlLen,
|
||||
const struct port_mapping * ref, int count)
|
||||
{
|
||||
int i;
|
||||
int r = 0;
|
||||
struct PortMappingParserData data;
|
||||
struct PortMapping * pm;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
ParsePortListing(portListingXml, portListingXmlLen, &data);
|
||||
for(i = 0, pm = data.l_head;
|
||||
(pm != NULL) && (i < count);
|
||||
i++, pm = pm->l_next) {
|
||||
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
|
||||
i, pm->protocol, pm->externalPort, pm->internalClient,
|
||||
pm->internalPort,
|
||||
pm->description, pm->remoteHost,
|
||||
(unsigned)pm->leaseTime);
|
||||
if(0 != strcmp(pm->protocol, ref[i].proto)) {
|
||||
printf("protocol : '%s' != '%s'\n", pm->protocol, ref[i].proto);
|
||||
r++;
|
||||
}
|
||||
if(pm->externalPort != ref[i].externalport) {
|
||||
printf("externalPort : %hu != %hu\n",
|
||||
pm->externalPort, ref[i].externalport);
|
||||
r++;
|
||||
}
|
||||
if(0 != strcmp(pm->internalClient, ref[i].client)) {
|
||||
printf("client : '%s' != '%s'\n",
|
||||
pm->internalClient, ref[i].client);
|
||||
r++;
|
||||
}
|
||||
if(pm->internalPort != ref[i].internalport) {
|
||||
printf("internalPort : %hu != %hu\n",
|
||||
pm->internalPort, ref[i].internalport);
|
||||
r++;
|
||||
}
|
||||
if(0 != strcmp(pm->description, ref[i].desc)) {
|
||||
printf("description : '%s' != '%s'\n",
|
||||
pm->description, ref[i].desc);
|
||||
r++;
|
||||
}
|
||||
if(0 != strcmp(pm->remoteHost, ref[i].remotehost)) {
|
||||
printf("remoteHost : '%s' != '%s'\n",
|
||||
pm->remoteHost, ref[i].remotehost);
|
||||
r++;
|
||||
}
|
||||
if((unsigned)pm->leaseTime != ref[i].leasetime) {
|
||||
printf("leaseTime : %u != %u\n",
|
||||
(unsigned)pm->leaseTime, ref[i].leasetime);
|
||||
r++;
|
||||
}
|
||||
if(pm->enabled != ref[i].enabled) {
|
||||
printf("enabled : %d != %d\n",
|
||||
(int)pm->enabled, (int)ref[i].enabled);
|
||||
r++;
|
||||
}
|
||||
}
|
||||
if((i != count) || (pm != NULL)) {
|
||||
printf("count mismatch : i=%d count=%d pm=%p\n", i, count, pm);
|
||||
r++;
|
||||
}
|
||||
FreePortListing(&data);
|
||||
return r;
|
||||
}
|
||||
|
||||
const char test_document[] =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\"\n"
|
||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n"
|
||||
"xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection "
|
||||
"http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">\n"
|
||||
" <p:PortMappingEntry>\n"
|
||||
" <p:NewRemoteHost></p:NewRemoteHost>\n"
|
||||
" <p:NewExternalPort>5002</p:NewExternalPort>\n"
|
||||
" <p:NewProtocol>UDP</p:NewProtocol>\n"
|
||||
" <p:NewInternalPort>4001</p:NewInternalPort>\n"
|
||||
" <p:NewInternalClient>192.168.1.123</p:NewInternalClient>\n"
|
||||
" <p:NewEnabled>1</p:NewEnabled>\n"
|
||||
" <p:NewDescription>xxx</p:NewDescription>\n"
|
||||
" <p:NewLeaseTime>0</p:NewLeaseTime>\n"
|
||||
" </p:PortMappingEntry>\n"
|
||||
" <p:PortMappingEntry>\n"
|
||||
" <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>\n"
|
||||
" <p:NewExternalPort>2345</p:NewExternalPort>\n"
|
||||
" <p:NewProtocol>TCP</p:NewProtocol>\n"
|
||||
" <p:NewInternalPort>2349</p:NewInternalPort>\n"
|
||||
" <p:NewInternalClient>192.168.1.137</p:NewInternalClient>\n"
|
||||
" <p:NewEnabled>1</p:NewEnabled>\n"
|
||||
" <p:NewDescription>dooom</p:NewDescription>\n"
|
||||
" <p:NewLeaseTime>346</p:NewLeaseTime>\n"
|
||||
" </p:PortMappingEntry>\n"
|
||||
" <p:PortMappingEntry>\n"
|
||||
" <p:NewRemoteHost>134.231.2.11</p:NewRemoteHost>\n"
|
||||
" <p:NewExternalPort>12345</p:NewExternalPort>\n"
|
||||
" <p:NewProtocol>TCP</p:NewProtocol>\n"
|
||||
" <p:NewInternalPort>12345</p:NewInternalPort>\n"
|
||||
" <p:NewInternalClient>192.168.1.137</p:NewInternalClient>\n"
|
||||
" <p:NewEnabled>1</p:NewEnabled>\n"
|
||||
" <p:NewDescription>dooom A</p:NewDescription>\n"
|
||||
" <p:NewLeaseTime>347</p:NewLeaseTime>\n"
|
||||
" </p:PortMappingEntry>\n"
|
||||
"</p:PortMappingList>";
|
||||
|
||||
#define PORT_MAPPINGS_COUNT 3
|
||||
const struct port_mapping port_mappings[PORT_MAPPINGS_COUNT] = {
|
||||
{347, 12345, 12345, "134.231.2.11", "192.168.1.137", "TCP", "dooom A", 1},
|
||||
{346, 2345, 2349, "202.233.2.1", "192.168.1.137", "TCP", "dooom", 1},
|
||||
{0, 5002, 4001, "", "192.168.1.123", "UDP", "xxx", 1}
|
||||
};
|
||||
|
||||
/* --- main --- */
|
||||
int main(void)
|
||||
{
|
||||
int r;
|
||||
r = test(test_document, sizeof(test_document) - 1,
|
||||
port_mappings, PORT_MAPPINGS_COUNT);
|
||||
if(r == 0) {
|
||||
printf("test of portlistingparse OK\n");
|
||||
return 0;
|
||||
} else {
|
||||
printf("test FAILED (%d differences counted)\n", r);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: upnpc.c,v 1.102 2014/02/05 17:27:14 nanard Exp $ */
|
||||
/* $Id: upnpc.c,v 1.105 2014/11/01 10:37:32 nanard Exp $ */
|
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard
|
||||
* Copyright (c) 2005-2014 Thomas Bernard
|
||||
|
@ -174,7 +174,7 @@ static void NewListRedirections(struct UPNPUrls * urls,
|
|||
if(r == UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
|
||||
for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next)
|
||||
for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
|
||||
{
|
||||
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
|
||||
i, pm->protocol, pm->externalPort, pm->internalClient,
|
||||
|
@ -199,7 +199,7 @@ static void NewListRedirections(struct UPNPUrls * urls,
|
|||
&pdata);
|
||||
if(r == UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next)
|
||||
for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
|
||||
{
|
||||
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
|
||||
i, pm->protocol, pm->externalPort, pm->internalClient,
|
||||
|
@ -223,17 +223,19 @@ static void NewListRedirections(struct UPNPUrls * urls,
|
|||
* 3 - Add port mapping
|
||||
* 4 - get this port mapping from the IGD */
|
||||
static void SetRedirectAndTest(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
const char * iaddr,
|
||||
const char * iport,
|
||||
const char * eport,
|
||||
const char * proto,
|
||||
const char * leaseDuration,
|
||||
const char * description)
|
||||
struct IGDdatas * data,
|
||||
const char * iaddr,
|
||||
const char * iport,
|
||||
const char * eport,
|
||||
const char * proto,
|
||||
const char * leaseDuration,
|
||||
const char * description,
|
||||
int addAny)
|
||||
{
|
||||
char externalIPAddress[40];
|
||||
char intClient[40];
|
||||
char intPort[6];
|
||||
char reservedPort[6];
|
||||
char duration[16];
|
||||
int r;
|
||||
|
||||
|
@ -249,31 +251,41 @@ static void SetRedirectAndTest(struct UPNPUrls * urls,
|
|||
return;
|
||||
}
|
||||
|
||||
UPNP_GetExternalIPAddress(urls->controlURL,
|
||||
data->first.servicetype,
|
||||
externalIPAddress);
|
||||
if(externalIPAddress[0])
|
||||
printf("ExternalIPAddress = %s\n", externalIPAddress);
|
||||
else
|
||||
printf("GetExternalIPAddress failed.\n");
|
||||
|
||||
r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype,
|
||||
eport, iport, iaddr, description,
|
||||
proto, 0, leaseDuration);
|
||||
r = UPNP_GetExternalIPAddress(urls->controlURL,
|
||||
data->first.servicetype,
|
||||
externalIPAddress);
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
|
||||
eport, iport, iaddr, r, strupnperror(r));
|
||||
printf("GetExternalIPAddress failed.\n");
|
||||
else
|
||||
printf("ExternalIPAddress = %s\n", externalIPAddress);
|
||||
|
||||
if (addAny) {
|
||||
r = UPNP_AddAnyPortMapping(urls->controlURL, data->first.servicetype,
|
||||
eport, iport, iaddr, description,
|
||||
proto, 0, leaseDuration, reservedPort);
|
||||
if(r==UPNPCOMMAND_SUCCESS)
|
||||
eport = reservedPort;
|
||||
else
|
||||
printf("AddAnyPortMapping(%s, %s, %s) failed with code %d (%s)\n",
|
||||
eport, iport, iaddr, r, strupnperror(r));
|
||||
} else {
|
||||
r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype,
|
||||
eport, iport, iaddr, description,
|
||||
proto, 0, leaseDuration);
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
|
||||
eport, iport, iaddr, r, strupnperror(r));
|
||||
}
|
||||
|
||||
r = UPNP_GetSpecificPortMappingEntry(urls->controlURL,
|
||||
data->first.servicetype,
|
||||
eport, proto, NULL/*remoteHost*/,
|
||||
intClient, intPort, NULL/*desc*/,
|
||||
NULL/*enabled*/, duration);
|
||||
data->first.servicetype,
|
||||
eport, proto, NULL/*remoteHost*/,
|
||||
intClient, intPort, NULL/*desc*/,
|
||||
NULL/*enabled*/, duration);
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n",
|
||||
r, strupnperror(r));
|
||||
|
||||
if(intClient[0]) {
|
||||
else {
|
||||
printf("InternalIP:Port = %s:%s\n", intClient, intPort);
|
||||
printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n",
|
||||
externalIPAddress, eport, proto, intClient, intPort, duration);
|
||||
|
@ -283,8 +295,9 @@ static void SetRedirectAndTest(struct UPNPUrls * urls,
|
|||
static void
|
||||
RemoveRedirect(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
const char * eport,
|
||||
const char * proto)
|
||||
const char * eport,
|
||||
const char * proto,
|
||||
const char * remoteHost)
|
||||
{
|
||||
int r;
|
||||
if(!proto || !eport)
|
||||
|
@ -298,10 +311,36 @@ RemoveRedirect(struct UPNPUrls * urls,
|
|||
fprintf(stderr, "protocol invalid\n");
|
||||
return;
|
||||
}
|
||||
r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, 0);
|
||||
r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, remoteHost);
|
||||
printf("UPNP_DeletePortMapping() returned : %d\n", r);
|
||||
}
|
||||
|
||||
static void
|
||||
RemoveRedirectRange(struct UPNPUrls * urls,
|
||||
struct IGDdatas * data,
|
||||
const char * ePortStart, char const * ePortEnd,
|
||||
const char * proto, const char * manage)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!manage)
|
||||
manage = "0";
|
||||
|
||||
if(!proto || !ePortStart || !ePortEnd)
|
||||
{
|
||||
fprintf(stderr, "invalid arguments\n");
|
||||
return;
|
||||
}
|
||||
proto = protofix(proto);
|
||||
if(!proto)
|
||||
{
|
||||
fprintf(stderr, "protocol invalid\n");
|
||||
return;
|
||||
}
|
||||
r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage);
|
||||
printf("UPNP_DeletePortMappingRange() returned : %d\n", r);
|
||||
}
|
||||
|
||||
/* IGD:2, functions for service WANIPv6FirewallControl:1 */
|
||||
static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data)
|
||||
{
|
||||
|
@ -546,10 +585,12 @@ int main(int argc, char ** argv)
|
|||
|| (command == 'D' && commandargc<1))
|
||||
{
|
||||
fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration]\n\t\tAdd port redirection\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -d external_port protocol [port2 protocol2] [...]\n\t\tDelete port redirection\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -d external_port protocol <remote host>\n\t\tDelete port redirection\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings, IGD v2)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -n ip port external_port protocol [duration]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port redirections (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -r port1 protocol1 [port2 protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]);
|
||||
fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]);
|
||||
|
@ -631,16 +672,28 @@ int main(int argc, char ** argv)
|
|||
break;
|
||||
case 'a':
|
||||
SetRedirectAndTest(&urls, &data,
|
||||
commandargv[0], commandargv[1],
|
||||
commandargv[2], commandargv[3],
|
||||
(commandargc > 4)?commandargv[4]:"0",
|
||||
description);
|
||||
commandargv[0], commandargv[1],
|
||||
commandargv[2], commandargv[3],
|
||||
(commandargc > 4)?commandargv[4]:"0",
|
||||
description, 0);
|
||||
break;
|
||||
case 'd':
|
||||
for(i=0; i<commandargc; i+=2)
|
||||
{
|
||||
RemoveRedirect(&urls, &data, commandargv[i], commandargv[i+1]);
|
||||
}
|
||||
RemoveRedirect(&urls, &data, commandargv[0], commandargv[1],
|
||||
commandargc > 2 ? commandargv[2] : NULL);
|
||||
break;
|
||||
case 'n': /* aNy */
|
||||
SetRedirectAndTest(&urls, &data,
|
||||
commandargv[0], commandargv[1],
|
||||
commandargv[2], commandargv[3],
|
||||
(commandargc > 4)?commandargv[4]:"0",
|
||||
description, 1);
|
||||
break;
|
||||
case 'N':
|
||||
if (commandargc < 3)
|
||||
fprintf(stderr, "too few arguments\n");
|
||||
|
||||
RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2],
|
||||
commandargc > 3 ? commandargv[3] : NULL);
|
||||
break;
|
||||
case 's':
|
||||
GetConnectionStatus(&urls, &data);
|
||||
|
@ -650,9 +703,9 @@ int main(int argc, char ** argv)
|
|||
{
|
||||
/*printf("port %s protocol %s\n", argv[i], argv[i+1]);*/
|
||||
SetRedirectAndTest(&urls, &data,
|
||||
lanaddr, commandargv[i],
|
||||
commandargv[i], commandargv[i+1], "0",
|
||||
description);
|
||||
lanaddr, commandargv[i],
|
||||
commandargv[i], commandargv[i+1], "0",
|
||||
description, 0);
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
|
|
|
@ -20,7 +20,7 @@ my_atoui(const char * s)
|
|||
|
||||
/*
|
||||
* */
|
||||
LIBSPEC UNSIGNED_INTEGER
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalBytesSent(const char * controlURL,
|
||||
const char * servicetype)
|
||||
{
|
||||
|
@ -44,7 +44,7 @@ UPNP_GetTotalBytesSent(const char * controlURL,
|
|||
|
||||
/*
|
||||
* */
|
||||
LIBSPEC UNSIGNED_INTEGER
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalBytesReceived(const char * controlURL,
|
||||
const char * servicetype)
|
||||
{
|
||||
|
@ -68,7 +68,7 @@ UPNP_GetTotalBytesReceived(const char * controlURL,
|
|||
|
||||
/*
|
||||
* */
|
||||
LIBSPEC UNSIGNED_INTEGER
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalPacketsSent(const char * controlURL,
|
||||
const char * servicetype)
|
||||
{
|
||||
|
@ -92,7 +92,7 @@ UPNP_GetTotalPacketsSent(const char * controlURL,
|
|||
|
||||
/*
|
||||
* */
|
||||
LIBSPEC UNSIGNED_INTEGER
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalPacketsReceived(const char * controlURL,
|
||||
const char * servicetype)
|
||||
{
|
||||
|
@ -116,7 +116,7 @@ UPNP_GetTotalPacketsReceived(const char * controlURL,
|
|||
|
||||
/* UPNP_GetStatusInfo() call the corresponding UPNP method
|
||||
* returns the current status and uptime */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetStatusInfo(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * status,
|
||||
|
@ -181,7 +181,7 @@ UPNP_GetStatusInfo(const char * controlURL,
|
|||
|
||||
/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method
|
||||
* returns the connection type */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetConnectionTypeInfo(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * connectionType)
|
||||
|
@ -224,7 +224,7 @@ UPNP_GetConnectionTypeInfo(const char * controlURL,
|
|||
* One of the values can be null
|
||||
* Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only
|
||||
* We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetLinkLayerMaxBitRates(const char * controlURL,
|
||||
const char * servicetype,
|
||||
unsigned int * bitrateDown,
|
||||
|
@ -293,7 +293,7 @@ UPNP_GetLinkLayerMaxBitRates(const char * controlURL,
|
|||
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||
* 501 Action Failed - See UPnP Device Architecture section on Control.
|
||||
*/
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetExternalIPAddress(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * extIpAdd)
|
||||
|
@ -333,15 +333,15 @@ UPNP_GetExternalIPAddress(const char * controlURL,
|
|||
return ret;
|
||||
}
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort,
|
||||
const char * inPort,
|
||||
const char * inClient,
|
||||
const char * desc,
|
||||
const char * proto,
|
||||
const char * remoteHost,
|
||||
const char * leaseDuration)
|
||||
const char * extPort,
|
||||
const char * inPort,
|
||||
const char * inClient,
|
||||
const char * desc,
|
||||
const char * proto,
|
||||
const char * remoteHost,
|
||||
const char * leaseDuration)
|
||||
{
|
||||
struct UPNParg * AddPortMappingArgs;
|
||||
char * buffer;
|
||||
|
@ -394,7 +394,74 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
|||
return ret;
|
||||
}
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort,
|
||||
const char * inPort,
|
||||
const char * inClient,
|
||||
const char * desc,
|
||||
const char * proto,
|
||||
const char * remoteHost,
|
||||
const char * leaseDuration,
|
||||
char * reservedPort)
|
||||
{
|
||||
struct UPNParg * AddPortMappingArgs;
|
||||
char * buffer;
|
||||
int bufsize;
|
||||
struct NameValueParserData pdata;
|
||||
const char * resVal;
|
||||
int ret;
|
||||
|
||||
if(!inPort || !inClient || !proto || !extPort)
|
||||
return UPNPCOMMAND_INVALID_ARGS;
|
||||
|
||||
AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
|
||||
AddPortMappingArgs[0].elt = "NewRemoteHost";
|
||||
AddPortMappingArgs[0].val = remoteHost;
|
||||
AddPortMappingArgs[1].elt = "NewExternalPort";
|
||||
AddPortMappingArgs[1].val = extPort;
|
||||
AddPortMappingArgs[2].elt = "NewProtocol";
|
||||
AddPortMappingArgs[2].val = proto;
|
||||
AddPortMappingArgs[3].elt = "NewInternalPort";
|
||||
AddPortMappingArgs[3].val = inPort;
|
||||
AddPortMappingArgs[4].elt = "NewInternalClient";
|
||||
AddPortMappingArgs[4].val = inClient;
|
||||
AddPortMappingArgs[5].elt = "NewEnabled";
|
||||
AddPortMappingArgs[5].val = "1";
|
||||
AddPortMappingArgs[6].elt = "NewPortMappingDescription";
|
||||
AddPortMappingArgs[6].val = desc?desc:"libminiupnpc";
|
||||
AddPortMappingArgs[7].elt = "NewLeaseDuration";
|
||||
AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0";
|
||||
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
|
||||
"AddAnyPortMapping", AddPortMappingArgs,
|
||||
&bufsize))) {
|
||||
free(AddPortMappingArgs);
|
||||
return UPNPCOMMAND_HTTP_ERROR;
|
||||
}
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
free(buffer); buffer = NULL;
|
||||
resVal = GetValueFromNameValueList(&pdata, "errorCode");
|
||||
if(resVal) {
|
||||
ret = UPNPCOMMAND_UNKNOWN_ERROR;
|
||||
sscanf(resVal, "%d", &ret);
|
||||
} else {
|
||||
char *p;
|
||||
|
||||
p = GetValueFromNameValueList(&pdata, "NewReservedPort");
|
||||
if(p) {
|
||||
strncpy(reservedPort, p, 6);
|
||||
reservedPort[5] = '\0';
|
||||
ret = UPNPCOMMAND_SUCCESS;
|
||||
} else {
|
||||
ret = UPNPCOMMAND_INVALID_RESPONSE;
|
||||
}
|
||||
}
|
||||
ClearNameValueList(&pdata);
|
||||
free(AddPortMappingArgs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort, const char * proto,
|
||||
const char * remoteHost)
|
||||
|
@ -438,7 +505,53 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
|
|||
return ret;
|
||||
}
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
|
||||
const char * extPortStart, const char * extPortEnd,
|
||||
const char * proto,
|
||||
const char * manage)
|
||||
{
|
||||
struct UPNParg * DeletePortMappingArgs;
|
||||
char * buffer;
|
||||
int bufsize;
|
||||
struct NameValueParserData pdata;
|
||||
const char * resVal;
|
||||
int ret;
|
||||
|
||||
if(!extPortStart || !extPortEnd || !proto || !manage)
|
||||
return UPNPCOMMAND_INVALID_ARGS;
|
||||
|
||||
DeletePortMappingArgs = calloc(5, sizeof(struct UPNParg));
|
||||
DeletePortMappingArgs[0].elt = "NewStartPort";
|
||||
DeletePortMappingArgs[0].val = extPortStart;
|
||||
DeletePortMappingArgs[1].elt = "NewEndPort";
|
||||
DeletePortMappingArgs[1].val = extPortEnd;
|
||||
DeletePortMappingArgs[2].elt = "NewProtocol";
|
||||
DeletePortMappingArgs[2].val = proto;
|
||||
DeletePortMappingArgs[3].elt = "NewManage";
|
||||
DeletePortMappingArgs[3].val = manage;
|
||||
|
||||
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
|
||||
"DeletePortMappingRange",
|
||||
DeletePortMappingArgs, &bufsize))) {
|
||||
free(DeletePortMappingArgs);
|
||||
return UPNPCOMMAND_HTTP_ERROR;
|
||||
}
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
free(buffer); buffer = NULL;
|
||||
resVal = GetValueFromNameValueList(&pdata, "errorCode");
|
||||
if(resVal) {
|
||||
ret = UPNPCOMMAND_UNKNOWN_ERROR;
|
||||
sscanf(resVal, "%d", &ret);
|
||||
} else {
|
||||
ret = UPNPCOMMAND_SUCCESS;
|
||||
}
|
||||
ClearNameValueList(&pdata);
|
||||
free(DeletePortMappingArgs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetGenericPortMappingEntry(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * index,
|
||||
|
@ -533,7 +646,7 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
|
|||
return r;
|
||||
}
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetPortMappingNumberOfEntries(const char * controlURL,
|
||||
const char * servicetype,
|
||||
unsigned int * numEntries)
|
||||
|
@ -574,7 +687,7 @@ UPNP_GetPortMappingNumberOfEntries(const char * controlURL,
|
|||
/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping
|
||||
* the result is returned in the intClient and intPort strings
|
||||
* please provide 16 and 6 bytes of data */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * extPort,
|
||||
|
@ -666,7 +779,7 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
|||
* 733 InconsistantParameters - NewStartPort and NewEndPort values are not
|
||||
* consistent.
|
||||
*/
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetListOfPortMappings(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * startPort,
|
||||
|
@ -748,7 +861,7 @@ UPNP_GetListOfPortMappings(const char * controlURL,
|
|||
}
|
||||
|
||||
/* IGD:2, functions for service WANIPv6FirewallControl:1 */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetFirewallStatus(const char * controlURL,
|
||||
const char * servicetype,
|
||||
int * firewallEnabled,
|
||||
|
@ -792,7 +905,7 @@ UPNP_GetFirewallStatus(const char * controlURL,
|
|||
return ret;
|
||||
}
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype,
|
||||
const char * remoteHost,
|
||||
const char * remotePort,
|
||||
|
@ -847,7 +960,7 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
|
|||
return ret;
|
||||
}
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_AddPinhole(const char * controlURL, const char * servicetype,
|
||||
const char * remoteHost,
|
||||
const char * remotePort,
|
||||
|
@ -926,7 +1039,7 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
|
|||
return ret;
|
||||
}
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID,
|
||||
const char * leaseTime)
|
||||
|
@ -968,7 +1081,7 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
|
|||
return ret;
|
||||
}
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID)
|
||||
{
|
||||
/*struct NameValueParserData pdata;*/
|
||||
|
@ -1007,7 +1120,7 @@ UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char
|
|||
return ret;
|
||||
}
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID, int * isWorking)
|
||||
{
|
||||
|
@ -1052,7 +1165,7 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
|
|||
return ret;
|
||||
}
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID, int * packets)
|
||||
{
|
||||
|
|
|
@ -17,24 +17,25 @@
|
|||
#define UPNPCOMMAND_UNKNOWN_ERROR (-1)
|
||||
#define UPNPCOMMAND_INVALID_ARGS (-2)
|
||||
#define UPNPCOMMAND_HTTP_ERROR (-3)
|
||||
#define UPNPCOMMAND_INVALID_RESPONSE (-4)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
LIBSPEC UNSIGNED_INTEGER
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalBytesSent(const char * controlURL,
|
||||
const char * servicetype);
|
||||
|
||||
LIBSPEC UNSIGNED_INTEGER
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalBytesReceived(const char * controlURL,
|
||||
const char * servicetype);
|
||||
|
||||
LIBSPEC UNSIGNED_INTEGER
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalPacketsSent(const char * controlURL,
|
||||
const char * servicetype);
|
||||
|
||||
LIBSPEC UNSIGNED_INTEGER
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER
|
||||
UPNP_GetTotalPacketsReceived(const char * controlURL,
|
||||
const char * servicetype);
|
||||
|
||||
|
@ -43,7 +44,7 @@ UPNP_GetTotalPacketsReceived(const char * controlURL,
|
|||
* Return values :
|
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||
* or a UPnP Error code */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetStatusInfo(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * status,
|
||||
|
@ -55,7 +56,7 @@ UPNP_GetStatusInfo(const char * controlURL,
|
|||
* Return Values :
|
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||
* or a UPnP Error code */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetConnectionTypeInfo(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * connectionType);
|
||||
|
@ -71,7 +72,7 @@ UPNP_GetConnectionTypeInfo(const char * controlURL,
|
|||
* possible UPnP Errors :
|
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||
* 501 Action Failed - See UPnP Device Architecture section on Control. */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetExternalIPAddress(const char * controlURL,
|
||||
const char * servicetype,
|
||||
char * extIpAdd);
|
||||
|
@ -82,7 +83,7 @@ UPNP_GetExternalIPAddress(const char * controlURL,
|
|||
* return values :
|
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||
* or a UPnP Error Code. */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
|
||||
const char* servicetype,
|
||||
unsigned int * bitrateDown,
|
||||
|
@ -121,15 +122,49 @@ UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
|
|||
* due to conflict with other mechanisms.
|
||||
* 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded
|
||||
*/
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort,
|
||||
const char * inPort,
|
||||
const char * inClient,
|
||||
const char * desc,
|
||||
const char * proto,
|
||||
const char * remoteHost,
|
||||
const char * leaseDuration);
|
||||
const char * extPort,
|
||||
const char * inPort,
|
||||
const char * inClient,
|
||||
const char * desc,
|
||||
const char * proto,
|
||||
const char * remoteHost,
|
||||
const char * leaseDuration);
|
||||
|
||||
/* UPNP_AddAnyPortMapping()
|
||||
* if desc is NULL, it will be defaulted to "libminiupnpc"
|
||||
* remoteHost is usually NULL because IGD don't support it.
|
||||
*
|
||||
* Return values :
|
||||
* 0 : SUCCESS
|
||||
* NON ZERO : ERROR. Either an UPnP error code or an unknown error.
|
||||
*
|
||||
* List of possible UPnP errors for AddPortMapping :
|
||||
* errorCode errorDescription (short) - Description (long)
|
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||
* 501 Action Failed - See UPnP Device Architecture section on Control.
|
||||
* 606 Action not authorized - The action requested REQUIRES authorization and
|
||||
* the sender was not authorized.
|
||||
* 715 WildCardNotPermittedInSrcIP - The source IP address cannot be
|
||||
* wild-carded
|
||||
* 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded
|
||||
* 728 NoPortMapsAvailable - There are not enough free ports available to
|
||||
* complete port mapping.
|
||||
* 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed
|
||||
* due to conflict with other mechanisms.
|
||||
* 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded
|
||||
*/
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort,
|
||||
const char * inPort,
|
||||
const char * inClient,
|
||||
const char * desc,
|
||||
const char * proto,
|
||||
const char * remoteHost,
|
||||
const char * leaseDuration,
|
||||
char * reservedPort);
|
||||
|
||||
/* UPNP_DeletePortMapping()
|
||||
* Use same argument values as what was used for AddPortMapping().
|
||||
|
@ -143,14 +178,33 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
|||
* 606 Action not authorized - The action requested REQUIRES authorization
|
||||
* and the sender was not authorized.
|
||||
* 714 NoSuchEntryInArray - The specified value does not exist in the array */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
|
||||
const char * extPort, const char * proto,
|
||||
const char * remoteHost);
|
||||
const char * extPort, const char * proto,
|
||||
const char * remoteHost);
|
||||
|
||||
/* UPNP_DeletePortRangeMapping()
|
||||
* Use same argument values as what was used for AddPortMapping().
|
||||
* remoteHost is usually NULL because IGD don't support it.
|
||||
* Return Values :
|
||||
* 0 : SUCCESS
|
||||
* NON ZERO : error. Either an UPnP error code or an undefined error.
|
||||
*
|
||||
* List of possible UPnP errors for DeletePortMapping :
|
||||
* 606 Action not authorized - The action requested REQUIRES authorization
|
||||
* and the sender was not authorized.
|
||||
* 730 PortMappingNotFound - This error message is returned if no port
|
||||
* mapping is found in the specified range.
|
||||
* 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
|
||||
const char * extPortStart, const char * extPortEnd,
|
||||
const char * proto,
|
||||
const char * manage);
|
||||
|
||||
/* UPNP_GetPortMappingNumberOfEntries()
|
||||
* not supported by all routers */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetPortMappingNumberOfEntries(const char* controlURL,
|
||||
const char* servicetype,
|
||||
unsigned int * num);
|
||||
|
@ -178,7 +232,7 @@ UPNP_GetPortMappingNumberOfEntries(const char* controlURL,
|
|||
* and the sender was not authorized.
|
||||
* 714 NoSuchEntryInArray - The specified value does not exist in the array.
|
||||
*/
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * extPort,
|
||||
|
@ -212,7 +266,7 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
|||
* and the sender was not authorized.
|
||||
* 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds
|
||||
*/
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetGenericPortMappingEntry(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * index,
|
||||
|
@ -234,7 +288,7 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
|
|||
* 733 InconsistantParameters - NewStartPort and NewEndPort values are not
|
||||
* consistent.
|
||||
*/
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetListOfPortMappings(const char * controlURL,
|
||||
const char * servicetype,
|
||||
const char * startPort,
|
||||
|
@ -244,13 +298,13 @@ UPNP_GetListOfPortMappings(const char * controlURL,
|
|||
struct PortMappingParserData * data);
|
||||
|
||||
/* IGD:2, functions for service WANIPv6FirewallControl:1 */
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetFirewallStatus(const char * controlURL,
|
||||
const char * servicetype,
|
||||
int * firewallEnabled,
|
||||
int * inboundPinholeAllowed);
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype,
|
||||
const char * remoteHost,
|
||||
const char * remotePort,
|
||||
|
@ -259,7 +313,7 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
|
|||
const char * proto,
|
||||
int * opTimeout);
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_AddPinhole(const char * controlURL, const char * servicetype,
|
||||
const char * remoteHost,
|
||||
const char * remotePort,
|
||||
|
@ -269,19 +323,19 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
|
|||
const char * leaseTime,
|
||||
char * uniqueID);
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID,
|
||||
const char * leaseTime);
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID);
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID, int * isWorking);
|
||||
|
||||
LIBSPEC int
|
||||
MINIUPNP_LIBSPEC int
|
||||
UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
|
||||
const char * uniqueID, int * packets);
|
||||
|
||||
|
|
|
@ -24,6 +24,9 @@ const char * strupnperror(int err)
|
|||
case UPNPCOMMAND_INVALID_ARGS:
|
||||
s = "Miniupnpc Invalid Arguments";
|
||||
break;
|
||||
case UPNPCOMMAND_INVALID_RESPONSE:
|
||||
s = "Miniupnpc Invalid response";
|
||||
break;
|
||||
case UPNPDISCOVER_SOCKET_ERROR:
|
||||
s = "Miniupnpc Socket error";
|
||||
break;
|
||||
|
|
|
@ -17,7 +17,7 @@ extern "C" {
|
|||
/* strupnperror()
|
||||
* Return a string description of the UPnP error code
|
||||
* or NULL for undefinded errors */
|
||||
LIBSPEC const char * strupnperror(int err);
|
||||
MINIUPNP_LIBSPEC const char * strupnperror(int err);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $Id: upnpreplyparse.c,v 1.15 2013/06/06 21:36:40 nanard Exp $ */
|
||||
/* $Id: upnpreplyparse.c,v 1.17 2014/11/04 22:25:48 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2013 Thomas Bernard
|
||||
* (c) 2006-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
|
@ -53,7 +53,8 @@ NameValueParserEndElt(void * d, const char * name, int l)
|
|||
{
|
||||
nv->value[0] = '\0';
|
||||
}
|
||||
LIST_INSERT_HEAD( &(data->head), nv, entries);
|
||||
nv->l_next = data->l_head; /* insert in list */
|
||||
data->l_head = nv;
|
||||
}
|
||||
data->cdata = NULL;
|
||||
data->cdatalen = 0;
|
||||
|
@ -89,19 +90,19 @@ void
|
|||
ParseNameValue(const char * buffer, int bufsize,
|
||||
struct NameValueParserData * data)
|
||||
{
|
||||
struct xmlparser parser;
|
||||
LIST_INIT(&(data->head));
|
||||
struct xmlparser parser;
|
||||
data->l_head = NULL;
|
||||
data->portListing = NULL;
|
||||
data->portListingLength = 0;
|
||||
/* init xmlparser object */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = data;
|
||||
parser.starteltfunc = NameValueParserStartElt;
|
||||
parser.endeltfunc = NameValueParserEndElt;
|
||||
parser.datafunc = NameValueParserGetData;
|
||||
/* init xmlparser object */
|
||||
parser.xmlstart = buffer;
|
||||
parser.xmlsize = bufsize;
|
||||
parser.data = data;
|
||||
parser.starteltfunc = NameValueParserStartElt;
|
||||
parser.endeltfunc = NameValueParserEndElt;
|
||||
parser.datafunc = NameValueParserGetData;
|
||||
parser.attfunc = 0;
|
||||
parsexml(&parser);
|
||||
parsexml(&parser);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -114,9 +115,9 @@ ClearNameValueList(struct NameValueParserData * pdata)
|
|||
pdata->portListing = NULL;
|
||||
pdata->portListingLength = 0;
|
||||
}
|
||||
while((nv = pdata->head.lh_first) != NULL)
|
||||
while((nv = pdata->l_head) != NULL)
|
||||
{
|
||||
LIST_REMOVE(nv, entries);
|
||||
pdata->l_head = nv->l_next;
|
||||
free(nv);
|
||||
}
|
||||
}
|
||||
|
@ -127,9 +128,9 @@ GetValueFromNameValueList(struct NameValueParserData * pdata,
|
|||
{
|
||||
struct NameValue * nv;
|
||||
char * p = NULL;
|
||||
for(nv = pdata->head.lh_first;
|
||||
for(nv = pdata->l_head;
|
||||
(nv != NULL) && (p == NULL);
|
||||
nv = nv->entries.le_next)
|
||||
nv = nv->l_next)
|
||||
{
|
||||
if(strcmp(nv->name, Name) == 0)
|
||||
p = nv->value;
|
||||
|
@ -171,9 +172,9 @@ DisplayNameValueList(char * buffer, int bufsize)
|
|||
struct NameValueParserData pdata;
|
||||
struct NameValue * nv;
|
||||
ParseNameValue(buffer, bufsize, &pdata);
|
||||
for(nv = pdata.head.lh_first;
|
||||
for(nv = pdata.l_head;
|
||||
nv != NULL;
|
||||
nv = nv->entries.le_next)
|
||||
nv = nv->l_next)
|
||||
{
|
||||
printf("%s = %s\n", nv->name, nv->value);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: upnpreplyparse.h,v 1.17 2013/06/06 21:36:40 nanard Exp $ */
|
||||
/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2013 Thomas Bernard
|
||||
|
@ -8,25 +8,19 @@
|
|||
#ifndef UPNPREPLYPARSE_H_INCLUDED
|
||||
#define UPNPREPLYPARSE_H_INCLUDED
|
||||
|
||||
#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__)
|
||||
#include "bsdqueue.h"
|
||||
#else
|
||||
#include <sys/queue.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct NameValue {
|
||||
LIST_ENTRY(NameValue) entries;
|
||||
char name[64];
|
||||
char value[128];
|
||||
struct NameValue * l_next;
|
||||
char name[64];
|
||||
char value[128];
|
||||
};
|
||||
|
||||
struct NameValueParserData {
|
||||
LIST_HEAD(listhead, NameValue) head;
|
||||
char curelt[64];
|
||||
struct NameValue * l_head;
|
||||
char curelt[64];
|
||||
char * portListing;
|
||||
int portListingLength;
|
||||
int topelt;
|
||||
|
|
|
@ -1,4 +1,60 @@
|
|||
$Id: Changelog.txt,v 1.366 2014/03/24 11:03:50 nanard Exp $
|
||||
$Id: Changelog.txt,v 1.383 2014/11/07 11:53:37 nanard Exp $
|
||||
|
||||
2014/11/07:
|
||||
sockaddr_to_string() includes scope in IPv6 addresses
|
||||
|
||||
VERSION 1.9 : released on 2014/10/27
|
||||
|
||||
2014/10/23:
|
||||
Properly implements NAT-PMP mapping removal according to RCF6886
|
||||
|
||||
2014/10/22:
|
||||
Discard NAT-PMP packets coming from the WAN
|
||||
Send SSDP announces to IPv6 link-local, site-local
|
||||
and global multicast addresses
|
||||
|
||||
2014/10/21:
|
||||
small modifications to compile with exotic C libraries
|
||||
|
||||
2014/10/14:
|
||||
add comments in miniupnpd.conf regarding security
|
||||
|
||||
2014/09/25:
|
||||
DeletePortMapping now checks for client IP in Securemode
|
||||
|
||||
2014/06/xx:
|
||||
Various fixes :
|
||||
e->ipv6.flags |= IP6T_F_PROTO; (netfilter)
|
||||
fix natpmp.c byte order conversion
|
||||
add small delay before SSDP response to prevent flooding
|
||||
|
||||
2014/05/22:
|
||||
Add ipv6_bind_address (option "ipv6_listening_ip")
|
||||
disable IPv6 when socket(PF_INTET6, ...) errors with EAFNOSUPPORT
|
||||
Add IPV6 multicast membership only on selected "LAN" interfaces
|
||||
|
||||
2014/05/20:
|
||||
be more strict when parsing LAN addresses / interface names
|
||||
|
||||
2014/05/19:
|
||||
set source address for IPV6 packets sendto_schedule2() etc.
|
||||
|
||||
2014/05/15:
|
||||
Fix deletePortMappingRange()
|
||||
|
||||
2014/04/21:
|
||||
Fix PCP when request contain 0 IPv4 external address
|
||||
Remove pointer casting in natpmp.c
|
||||
|
||||
2014/04/15:
|
||||
rewrite iptables_*.sh scripts
|
||||
|
||||
2014/04/12:
|
||||
Add FreeBSD support for CHECK_PORTINUSE
|
||||
Add PCP support for CHECK_PORTINUSE
|
||||
|
||||
2014/04/09:
|
||||
Add HTTPS support and skeleton of DeviceProtection implementation
|
||||
|
||||
2014/03/24:
|
||||
start work to enable IPv6 PCP operations
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $Id: Makefile,v 1.80 2014/04/07 10:32:20 nanard Exp $
|
||||
# $Id: Makefile,v 1.83 2014/04/18 08:24:41 nanard Exp $
|
||||
# MiniUPnP project
|
||||
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
# Author: Thomas Bernard
|
||||
|
@ -34,32 +34,48 @@ STRIP = strip
|
|||
OSNAME != uname -s
|
||||
ARCH != uname -m
|
||||
.ifndef FWNAME
|
||||
.if exists(/usr/include/net/pfvar.h)
|
||||
#.if exists(/usr/include/net/pfvar.h)
|
||||
#FWNAME = pf
|
||||
#.else
|
||||
#FWNAME = ipf
|
||||
#.endif
|
||||
|
||||
.if $(OSNAME) == "OpenBSD"
|
||||
FWNAME = pf
|
||||
.else
|
||||
FWNAME = ipf
|
||||
.endif
|
||||
|
||||
# better way to find if we are using ipf or pf
|
||||
.if exists(/etc/rc.subr) && exists(/etc/rc.conf)
|
||||
.if $(OSNAME) == "FreeBSD"
|
||||
.if exists(/etc/rc.subr) && exists(/etc/rc.conf)
|
||||
FWNAME != . /etc/rc.subr; . /etc/rc.conf; \
|
||||
if checkyesno ipfilter_enable; then \
|
||||
echo "ipf"; elif checkyesno pf_enable; then \
|
||||
echo "pf"; else echo "ipfw"; fi
|
||||
echo "pf"; elif checkyesno firewall_enable; then \
|
||||
echo "ipfw"; else echo "pf"; fi
|
||||
.else
|
||||
FWNAME = pf
|
||||
.endif
|
||||
.endif
|
||||
|
||||
.if $(OSNAME) == "NetBSD"
|
||||
.if exists(/etc/rc.subr) && exists(/etc/rc.conf)
|
||||
FWNAME != . /etc/rc.subr; . /etc/rc.conf; \
|
||||
if checkyesno ipfilter; then \
|
||||
if checkyesno pf; then \
|
||||
echo "pf"; elif checkyesno ipfilter; then \
|
||||
echo "ipf"; else echo "pf"; fi
|
||||
.else
|
||||
FWNAME = pf
|
||||
.endif
|
||||
.endif
|
||||
|
||||
.if $(OSNAME) == "DragonFly"
|
||||
.if exists(/etc/rc.subr) && exists(/etc/rc.conf)
|
||||
FWNAME != . /etc/rc.subr; . /etc/rc.conf; \
|
||||
if checkyesno ipfilter; then \
|
||||
echo "ipf"; elif checkyesno pf_enable; then \
|
||||
echo "pf"; else echo "ipfw"; fi
|
||||
if checkyesno pf; then \
|
||||
echo "pf"; elif checkyesno ipfilter; then \
|
||||
echo "ipf"; else echo "pf"; fi
|
||||
.else
|
||||
FWNAME = pf
|
||||
.endif
|
||||
.endif
|
||||
|
||||
|
@ -138,6 +154,8 @@ LIBS = -lkvm
|
|||
LIBS += -lsocket -lnsl -lkstat -lresolv
|
||||
.endif
|
||||
|
||||
LIBS += -lssl -lcrypto
|
||||
|
||||
# set PREFIX variable to install in the wanted place
|
||||
|
||||
INSTALLBINDIR = $(PREFIX)/sbin
|
||||
|
@ -213,7 +231,7 @@ testasyncsendto: config.h $(TESTASYNCSENDTOOBJS)
|
|||
$(CC) $(CFLAGS) -o $@ $(TESTASYNCSENDTOOBJS)
|
||||
|
||||
testportinuse: config.h $(TESTPORTINUSEOBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(TESTPORTINUSEOBJS) -lkvm
|
||||
$(CC) $(CFLAGS) -o $@ $(TESTPORTINUSEOBJS) $(LIBS)
|
||||
|
||||
# gmake :
|
||||
# $(CC) $(CFLAGS) -o $@ $^
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $Id: Makefile.linux,v 1.84 2014/03/24 10:43:25 nanard Exp $
|
||||
# $Id: Makefile.linux,v 1.86 2014/04/09 07:22:28 nanard Exp $
|
||||
# MiniUPnP project
|
||||
# (c) 2006-2014 Thomas Bernard
|
||||
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
|
@ -25,7 +25,7 @@
|
|||
CFLAGS ?= -Os
|
||||
CFLAGS += -fno-strict-aliasing
|
||||
CFLAGS += -fno-common
|
||||
CFLAGS += -D_GNU_SOURCE
|
||||
CPPFLAGS += -D_GNU_SOURCE
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra -Wstrict-prototypes -Wdeclaration-after-statement
|
||||
#CFLAGS += -Wno-missing-field-initializers
|
||||
|
@ -34,6 +34,7 @@ CC ?= gcc
|
|||
RM = rm -f
|
||||
INSTALL = install
|
||||
STRIP ?= strip
|
||||
PKG_CONFIG ?= pkg-config
|
||||
CP = cp
|
||||
|
||||
|
||||
|
@ -54,39 +55,39 @@ NETFILTEROBJS = netfilter/iptcrdr.o netfilter/iptpinhole.o netfilter/nfct_get.o
|
|||
|
||||
ALLOBJS = $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS)
|
||||
|
||||
PCFILE_FOUND := $(shell pkg-config --exists libiptc; echo $$?)
|
||||
PCFILE_FOUND := $(shell $(PKG_CONFIG) --exists libiptc; echo $$?)
|
||||
|
||||
ifeq (${PCFILE_FOUND},0)
|
||||
|
||||
IPTABLESVERSION := $(shell pkg-config --modversion libiptc)
|
||||
IPTABLESVERSION := $(shell $(PKG_CONFIG) --modversion libiptc)
|
||||
IPTABLESVERSION1 := $(shell echo $(IPTABLESVERSION) | cut -d. -f1 )
|
||||
IPTABLESVERSION2 := $(shell echo $(IPTABLESVERSION) | cut -d. -f2 )
|
||||
IPTABLESVERSION3 := $(shell echo $(IPTABLESVERSION) | cut -d. -f3 )
|
||||
# test if iptables version >= 1.4.3
|
||||
TEST := $(shell [ \( \( $(IPTABLESVERSION1) -ge 1 \) -a \( $(IPTABLESVERSION2) -ge 4 \) \) -a \( $(IPTABLESVERSION3) -ge 3 \) ] && echo 1 )
|
||||
ifeq ($(TEST), 1)
|
||||
CFLAGS += -DIPTABLES_143
|
||||
CPPFLAGS += -DIPTABLES_143
|
||||
endif
|
||||
|
||||
CFLAGS += $(shell pkg-config --cflags libiptc)
|
||||
LIBS += $(shell pkg-config --static --libs-only-l libiptc)
|
||||
LDFLAGS += $(shell pkg-config --libs-only-L libiptc)
|
||||
LDFLAGS += $(shell pkg-config --libs-only-other libiptc)
|
||||
CFLAGS += $(shell $(PKG_CONFIG) --cflags libiptc)
|
||||
LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libiptc)
|
||||
LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-L libiptc)
|
||||
LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-other libiptc)
|
||||
else
|
||||
|
||||
ifeq "$(wildcard /etc/gentoo-release )" ""
|
||||
LIBS ?= -liptc
|
||||
LDLIBS ?= -liptc
|
||||
else # gentoo
|
||||
# the following is better, at least on gentoo with iptables 1.4.6
|
||||
# see http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1618
|
||||
# and http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=2183
|
||||
LIBS ?= -lip4tc
|
||||
CFLAGS := -DIPTABLES_143 $(CFLAGS)
|
||||
LDLIBS ?= -lip4tc
|
||||
CPPFLAGS := -DIPTABLES_143 $(CPPFLAGS)
|
||||
endif
|
||||
|
||||
ARCH ?= $(shell uname -m | grep -q "x86_64" && echo 64)
|
||||
ifdef IPTABLESPATH
|
||||
CFLAGS := $(CFLAGS) -I$(IPTABLESPATH)/include/
|
||||
CPPFLAGS := $(CPPFLAGS) -I$(IPTABLESPATH)/include/
|
||||
LDFLAGS := $(LDFLAFGS) -L$(IPTABLESPATH)/libiptc/
|
||||
# get iptables version and set IPTABLES_143 macro if needed
|
||||
ifeq ($(TARGET_OPENWRT),)
|
||||
|
@ -97,12 +98,12 @@ IPTABLESVERSION3 := $(shell echo $(IPTABLESVERSION) | cut -d. -f3 )
|
|||
# test if iptables version >= 1.4.3
|
||||
TEST := $(shell [ \( \( $(IPTABLESVERSION1) -ge 1 \) -a \( $(IPTABLESVERSION2) -ge 4 \) \) -a \( $(IPTABLESVERSION3) -ge 3 \) ] && echo 1 )
|
||||
ifeq ($(TEST), 1)
|
||||
CFLAGS := $(CFLAGS) -DIPTABLES_143
|
||||
CPPFLAGS := $(CPPFLAGS) -DIPTABLES_143
|
||||
# the following sucks, but works
|
||||
LIBS = $(IPTABLESPATH)/libiptc/.libs/libip4tc.o
|
||||
#LIBS = $(IPTABLESPATH)/libiptc/.libs/libiptc.a
|
||||
LDLIBS = $(IPTABLESPATH)/libiptc/.libs/libip4tc.o
|
||||
#LDLIBS = $(IPTABLESPATH)/libiptc/.libs/libiptc.a
|
||||
else # ifeq ($(TEST), 1)
|
||||
LIBS = $(IPTABLESPATH)/libiptc/libiptc.a
|
||||
LDLIBS = $(IPTABLESPATH)/libiptc/libiptc.a
|
||||
endif # ifeq ($(TEST), 1)
|
||||
else # ($(TARGET_OPENWRT),)
|
||||
# openWRT :
|
||||
|
@ -110,12 +111,12 @@ else # ($(TARGET_OPENWRT),)
|
|||
# the following test has to be verified :
|
||||
TEST := $(shell test -f /usr/include/iptables/internal.h && grep -q "\#define IPTABLES_VERSION" /usr/include/iptables/internal.h && echo 1)
|
||||
ifeq ($(TEST), 1)
|
||||
CFLAGS := $(CFLAGS) -DIPTABLES_143
|
||||
LIBS = -liptc
|
||||
CPPFLAGS := $(CPPFLAGS) -DIPTABLES_143
|
||||
LDLIBS = -liptc
|
||||
endif # ($(TEST), 1)
|
||||
TEST_LIB := $(shell test -f /usr/lib$(ARCH)/libiptc.a && echo 1)
|
||||
ifeq ($(TEST_LIB), 1)
|
||||
LIBS = -liptc /usr/lib$(ARCH)/libiptc.a
|
||||
LDLIBS = -liptc /usr/lib$(ARCH)/libiptc.a
|
||||
endif # ($(TEST_LIB), 1)
|
||||
endif # ($(TARGET_OPENWRT),)
|
||||
else # ifdef IPTABLESPATH
|
||||
|
@ -123,29 +124,31 @@ else # ifdef IPTABLESPATH
|
|||
# the following test has to be verified :
|
||||
TEST := $(shell test -f /usr/include/xtables.h && grep -q "XTABLES_VERSION_CODE" /usr/include/xtables.h && echo 1)
|
||||
ifeq ($(TEST), 1)
|
||||
CFLAGS := $(CFLAGS) -DIPTABLES_143
|
||||
LIBS = -liptc
|
||||
CPPFLAGS := $(CPPFLAGS) -DIPTABLES_143
|
||||
LDLIBS = -liptc
|
||||
TESTIP4TC := $(shell test -f /lib/libip4tc.so && echo 1)
|
||||
ifeq ($(TESTIP4TC), 1)
|
||||
LIBS := $(LIBS) -lip4tc
|
||||
LDLIBS := $(LDLIBS) -lip4tc
|
||||
endif # ($(TESTIP4TC), 1)
|
||||
TESTIP6TC := $(shell test -f /lib/libip6tc.so && echo 1)
|
||||
ifeq ($(TESTIP6TC), 1)
|
||||
LIBS := $(LIBS) -lip6tc
|
||||
LDLIBS := $(LDLIBS) -lip6tc
|
||||
endif # ($(TESTIP6TC), 1)
|
||||
endif # ($(TEST), 1)
|
||||
endif # ifdef IPTABLESPATH
|
||||
endif # ifdef PCFILE_FOUND
|
||||
|
||||
LIBS += -lnfnetlink
|
||||
LDLIBS += -lnfnetlink
|
||||
|
||||
TEST := $(shell pkg-config --atleast-version=1.0.2 libnetfilter_conntrack && pkg-config --atleast-version=1.0.3 libmnl && echo 1)
|
||||
TEST := $(shell $(PKG_CONFIG) --atleast-version=1.0.2 libnetfilter_conntrack && $(PKG_CONFIG) --atleast-version=1.0.3 libmnl && echo 1)
|
||||
ifeq ($(TEST),1)
|
||||
CFLAGS += -DUSE_NFCT
|
||||
LIBS += $(shell pkg-config --static --libs-only-l libmnl)
|
||||
LIBS += $(shell pkg-config --static --libs-only-l libnetfilter_conntrack)
|
||||
CPPFLAGS += -DUSE_NFCT
|
||||
LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libmnl)
|
||||
LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libnetfilter_conntrack)
|
||||
endif # ($(TEST),1)
|
||||
|
||||
LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libssl)
|
||||
|
||||
TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o
|
||||
|
||||
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
|
||||
|
@ -181,7 +184,7 @@ install: miniupnpd miniupnpd.8 miniupnpd.conf genuuid \
|
|||
$(INSTALL) linux/miniupnpd.init.d.script $(DESTDIR)$(PREFIX)/etc/init.d/miniupnpd
|
||||
$(INSTALL) -d $(DESTDIR)$(MANINSTALLDIR)
|
||||
$(INSTALL) --mode=0644 miniupnpd.8 $(DESTDIR)$(MANINSTALLDIR)
|
||||
gzip $(DESTDIR)$(MANINSTALLDIR)/miniupnpd.8
|
||||
gzip -f $(DESTDIR)$(MANINSTALLDIR)/miniupnpd.8
|
||||
|
||||
# genuuid is using the uuidgen CLI tool which is part of libuuid
|
||||
# from the e2fsprogs
|
||||
|
@ -193,7 +196,7 @@ else
|
|||
sed -i -e "s/^uuid=[-0-9a-f]*/uuid=`($(STAGING_DIR_HOST)/bin/genuuid||$(STAGING_DIR_HOST)/bin/uuidgen||$(STAGING_DIR_HOST)/bin/uuid) 2>/dev/null`/" miniupnpd.conf
|
||||
endif
|
||||
|
||||
miniupnpd: $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS) $(LIBS)
|
||||
miniupnpd: $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS)
|
||||
|
||||
testupnpdescgen: $(TESTUPNPDESCGENOBJS)
|
||||
|
||||
|
@ -203,13 +206,13 @@ testupnppermissions: testupnppermissions.o upnppermissions.o
|
|||
|
||||
testgetifaddr: testgetifaddr.o getifaddr.o
|
||||
|
||||
testgetroute: testgetroute.o linux/getroute.o upnputils.o -lnfnetlink
|
||||
testgetroute: testgetroute.o linux/getroute.o upnputils.o
|
||||
|
||||
testasyncsendto: testasyncsendto.o asyncsendto.o upnputils.o \
|
||||
linux/getroute.o -lnfnetlink
|
||||
linux/getroute.o
|
||||
|
||||
testportinuse: testportinuse.o portinuse.o getifaddr.o \
|
||||
netfilter/iptcrdr.o $(LIBS)
|
||||
netfilter/iptcrdr.o
|
||||
|
||||
miniupnpdctl: miniupnpdctl.o
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#
|
||||
# To compile with pf with OS X 10.7+, you need to specify
|
||||
# path to XNU bsd sources :
|
||||
# INCLUDES="-I.../xnu/bsd I.../xnu/libkern" make -f Makefile.macosx
|
||||
# INCLUDES="-I.../xnu/bsd -I.../xnu/libkern" make -f Makefile.macosx
|
||||
#
|
||||
# To install use :
|
||||
# $ PREFIX=/dummyinstalldir make -f Makefile.macosx install
|
||||
|
@ -20,8 +20,6 @@ MV = mv
|
|||
INSTALL = install
|
||||
STRIP = strip
|
||||
|
||||
CFLAGS += -DMACOSX
|
||||
|
||||
# OSNAME and FWNAME are used for building OS or FW dependent code.
|
||||
OSNAME = $(shell uname)
|
||||
ARCH = $(shell uname -p)
|
||||
|
@ -33,10 +31,11 @@ STD_OBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
|||
upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \
|
||||
options.o upnppermissions.o minissdp.o natpmp.o \
|
||||
upnpevents.o getconnstatus.o upnputils.o \
|
||||
asyncsendto.o portinuse.o pcpserver.o
|
||||
MAC_OBJS = mac/getifstats.o bsd/ifacewatcher.o
|
||||
upnppinhole.o asyncsendto.o portinuse.o pcpserver.o
|
||||
MAC_OBJS = mac/getifstats.o bsd/ifacewatcher.o bsd/getroute.o
|
||||
IPFW_OBJS = ipfw/ipfwrdr.o ipfw/ipfwaux.o
|
||||
PF_OBJS = pf/obsdrdr.o pf/pfpinhole.o
|
||||
PF_OBJS = pf/obsdrdr.o
|
||||
# pf/pfpinhole.o # SHOULD be used, but doesn't compile on e.g. OS X 10.9.
|
||||
MISC_OBJS = upnpreplyparse.o minixml.o
|
||||
|
||||
ALL_OBJS = $(STD_OBJS) $(MISC_OBJS) $(MAC_OBJS)
|
||||
|
@ -52,7 +51,7 @@ TEST_GETIFSTATS_OBJS = testgetifstats.o mac/getifstats.o
|
|||
TEST_UPNPPERMISSIONS_OBJS = testupnppermissions.o upnppermissions.o
|
||||
TEST_GETIFADDR_OBJS = testgetifaddr.o getifaddr.o
|
||||
TEST_PORTINUSE_OBJS = testportinuse.o portinuse.o getifaddr.o
|
||||
TEST_ASYNCSENDTO_OBJS = testasyncsendto.o asyncsendto.o upnputils.o
|
||||
TEST_ASYNCSENDTO_OBJS = testasyncsendto.o asyncsendto.o upnputils.o bsd/getroute.o
|
||||
MINIUPNPDCTL_OBJS = miniupnpdctl.o
|
||||
|
||||
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
|
||||
|
|
|
@ -2,17 +2,9 @@
|
|||
=> Done (ifacewatcher 2011/05)
|
||||
To be improved.
|
||||
- improve logging.
|
||||
- add support for IPv6 thanks to http://www.upnp.org/download/Annex%20A%20-%20IPv6.doc
|
||||
=> work in progress
|
||||
- send also NOTIFY packets in IPv6 => done (2012/04/06)
|
||||
- make minissdpd know IPv6 also... => done
|
||||
- improve NAT-PMP compliance
|
||||
=> to be checked
|
||||
- Clean Option parsing/processing.
|
||||
=> done 2012/02/05
|
||||
|
||||
- Option to hide the windows Interconnection icon and pop-up - something to do with optionally having a blank presentation_url
|
||||
Done (2009/02/13)
|
||||
- Tomato's version used to dynamically include the local LAN IP and WAN IP as the windows icon name - if it was displayed...
|
||||
|
||||
- I just enabled my lease file to save the port mappings so I don't have to recreate them every time miniupnp gets restarted but instead what happens is the lease file gets recreated and the leases erased.
|
||||
|
@ -27,10 +19,4 @@ support IGD v2 : http://upnp.org/specs/gw/igd2/
|
|||
- netfilter : ok ?
|
||||
- ipfw/ipf : TODO
|
||||
|
||||
use non blocking sockets everywhere :
|
||||
- HTTP => OK
|
||||
- SSDP => OK
|
||||
- NAT-PMP => OK
|
||||
- not needed for miniupnpdctl
|
||||
|
||||
implement port_in_use() for NetBSD and FreeBSD
|
||||
implement port_in_use() for NetBSD
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.8
|
||||
1.9
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: $ */
|
||||
/* $Id: asyncsendto.c,v 1.6 2014/05/19 14:26:56 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2014 Thomas Bernard
|
||||
|
@ -13,6 +13,8 @@
|
|||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <sys/uio.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "asyncsendto.h"
|
||||
#include "upnputils.h"
|
||||
|
@ -36,6 +38,7 @@ struct scheduled_send {
|
|||
int flags;
|
||||
const struct sockaddr *dest_addr;
|
||||
socklen_t addrlen;
|
||||
const struct sockaddr_in6 *src_addr;
|
||||
char data[];
|
||||
};
|
||||
|
||||
|
@ -45,21 +48,60 @@ static LIST_HEAD(listhead, scheduled_send) send_list = { NULL };
|
|||
* ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
|
||||
* const struct sockaddr *dest_addr, socklen_t addrlen);
|
||||
*/
|
||||
static ssize_t
|
||||
send_from_to(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr_in6 *src_addr,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen)
|
||||
{
|
||||
#ifdef IPV6_PKTINFO
|
||||
if(src_addr) {
|
||||
struct iovec iov;
|
||||
struct in6_pktinfo ipi6;
|
||||
uint8_t c[CMSG_SPACE(sizeof(ipi6))];
|
||||
struct msghdr msg;
|
||||
struct cmsghdr* cmsg;
|
||||
|
||||
iov.iov_base = (void *)buf;
|
||||
iov.iov_len = len;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
ipi6.ipi6_addr = src_addr->sin6_addr;
|
||||
ipi6.ipi6_ifindex = src_addr->sin6_scope_id;
|
||||
msg.msg_control = c;
|
||||
msg.msg_controllen = sizeof(c);
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = IPPROTO_IPV6;
|
||||
cmsg->cmsg_type = IPV6_PKTINFO;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(ipi6));
|
||||
memcpy(CMSG_DATA(cmsg), &ipi6, sizeof(ipi6));
|
||||
msg.msg_name = (void *)dest_addr;
|
||||
msg.msg_namelen = addrlen;
|
||||
return sendmsg(sockfd, &msg, flags);
|
||||
} else {
|
||||
#endif /* IPV6_PKTINFO */
|
||||
return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
|
||||
#ifdef IPV6_PKTINFO
|
||||
}
|
||||
#endif /* IPV6_PKTINFO */
|
||||
}
|
||||
|
||||
/* delay = milli seconds */
|
||||
ssize_t
|
||||
sendto_schedule(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen,
|
||||
unsigned int delay)
|
||||
sendto_schedule2(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen,
|
||||
const struct sockaddr_in6 *src_addr,
|
||||
unsigned int delay)
|
||||
{
|
||||
enum {ESCHEDULED, EWAITREADY, ESENDNOW} state;
|
||||
ssize_t n;
|
||||
size_t alloc_len;
|
||||
struct timeval tv;
|
||||
struct scheduled_send * elt;
|
||||
|
||||
if(delay == 0) {
|
||||
/* first try to send at once */
|
||||
n = sendto(sockfd, buf, len, flags, dest_addr, addrlen);
|
||||
n = send_from_to(sockfd, buf, len, flags, src_addr, dest_addr, addrlen);
|
||||
if(n >= 0)
|
||||
return n;
|
||||
else if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
|
@ -80,10 +122,13 @@ sendto_schedule(int sockfd, const void *buf, size_t len, int flags,
|
|||
return -1;
|
||||
}
|
||||
/* allocate enough space for structure + buffers */
|
||||
elt = malloc(sizeof(struct scheduled_send) + len + addrlen);
|
||||
alloc_len = sizeof(struct scheduled_send) + len + addrlen;
|
||||
if(src_addr)
|
||||
alloc_len += sizeof(struct sockaddr_in6);
|
||||
elt = malloc(alloc_len);
|
||||
if(elt == NULL) {
|
||||
syslog(LOG_ERR, "malloc failed to allocate %u bytes",
|
||||
(unsigned)(sizeof(struct scheduled_send) + len + addrlen));
|
||||
(unsigned)alloc_len);
|
||||
return -1;
|
||||
}
|
||||
elt->state = state;
|
||||
|
@ -99,21 +144,35 @@ sendto_schedule(int sockfd, const void *buf, size_t len, int flags,
|
|||
memcpy(elt->data, dest_addr, addrlen);
|
||||
elt->dest_addr = (struct sockaddr *)elt->data;
|
||||
elt->addrlen = addrlen;
|
||||
memcpy(elt->data + addrlen, buf, len);
|
||||
elt->buf = (void *)(elt->data + addrlen);
|
||||
if(src_addr) {
|
||||
elt->src_addr = (struct sockaddr_in6 *)(elt->data + addrlen);
|
||||
memcpy((void *)elt->src_addr, src_addr, sizeof(struct sockaddr_in6));
|
||||
elt->buf = (void *)(elt->data + addrlen + sizeof(struct sockaddr_in6));
|
||||
} else {
|
||||
elt->src_addr = NULL;
|
||||
elt->buf = (void *)(elt->data + addrlen);
|
||||
}
|
||||
elt->len = len;
|
||||
memcpy((void *)elt->buf, buf, len);
|
||||
/* insert */
|
||||
LIST_INSERT_HEAD( &send_list, elt, entries);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* try to send at once, and queue the packet if needed */
|
||||
ssize_t
|
||||
sendto_or_schedule(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen)
|
||||
{
|
||||
return sendto_schedule(sockfd, buf, len, flags, dest_addr, addrlen, 0);
|
||||
return sendto_schedule2(sockfd, buf, len, flags, dest_addr, addrlen, NULL, 0);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
sendto_or_schedule2(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen,
|
||||
const struct sockaddr_in6 *src_addr)
|
||||
{
|
||||
return sendto_schedule2(sockfd, buf, len, flags, dest_addr, addrlen, src_addr, 0);
|
||||
}
|
||||
|
||||
/* get_next_scheduled_send() return number of scheduled send in list */
|
||||
|
@ -168,10 +227,14 @@ int try_sendto(fd_set * writefds)
|
|||
next = elt->entries.le_next;
|
||||
if((elt->state == ESENDNOW) ||
|
||||
(elt->state == EWAITREADY && FD_ISSET(elt->sockfd, writefds))) {
|
||||
#ifdef DEBUG
|
||||
syslog(LOG_DEBUG, "%s: %d bytes on socket %d",
|
||||
"try_sendto", (int)elt->len, elt->sockfd);
|
||||
n = sendto(elt->sockfd, elt->buf, elt->len, elt->flags,
|
||||
elt->dest_addr, elt->addrlen);
|
||||
#endif
|
||||
n = send_from_to(elt->sockfd, elt->buf, elt->len, elt->flags,
|
||||
elt->src_addr, elt->dest_addr, elt->addrlen);
|
||||
/*n = sendto(elt->sockfd, elt->buf, elt->len, elt->flags,
|
||||
elt->dest_addr, elt->addrlen);*/
|
||||
if(n < 0) {
|
||||
if(errno == EINTR) {
|
||||
/* retry at once */
|
||||
|
@ -234,8 +297,10 @@ void finalize_sendto(void)
|
|||
next = elt->entries.le_next;
|
||||
syslog(LOG_DEBUG, "finalize_sendto(): %d bytes on socket %d",
|
||||
(int)elt->len, elt->sockfd);
|
||||
n = sendto(elt->sockfd, elt->buf, elt->len, elt->flags,
|
||||
elt->dest_addr, elt->addrlen);
|
||||
n = send_from_to(elt->sockfd, elt->buf, elt->len, elt->flags,
|
||||
elt->src_addr, elt->dest_addr, elt->addrlen);
|
||||
/*n = sendto(elt->sockfd, elt->buf, elt->len, elt->flags,
|
||||
elt->dest_addr, elt->addrlen);*/
|
||||
if(n < 0) {
|
||||
if(errno==EAGAIN || errno==EWOULDBLOCK) {
|
||||
FD_SET(elt->sockfd, &writefds);
|
||||
|
|
|
@ -11,9 +11,13 @@
|
|||
/* sendto_schedule() : see sendto(2)
|
||||
* schedule sendto() call after delay (milliseconds) */
|
||||
ssize_t
|
||||
sendto_schedule(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen,
|
||||
unsigned int delay);
|
||||
sendto_schedule2(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen,
|
||||
const struct sockaddr_in6 *src_addr,
|
||||
unsigned int delay);
|
||||
|
||||
#define sendto_schedule(sockfd, buf, len, flags, dest_addr, addrlen, delay) \
|
||||
sendto_schedule2(sockfd, buf, len, flags, dest_addr, addrlen, NULL, delay)
|
||||
|
||||
/* sendto_schedule() : see sendto(2)
|
||||
* try sendto() at once and schedule if EINTR/EAGAIN/EWOULDBLOCK */
|
||||
|
@ -21,6 +25,13 @@ ssize_t
|
|||
sendto_or_schedule(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen);
|
||||
|
||||
/* same as sendto_schedule() except it will try to set source address
|
||||
* (for IPV6 only) */
|
||||
ssize_t
|
||||
sendto_or_schedule2(int sockfd, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen,
|
||||
const struct sockaddr_in6 *src_addr);
|
||||
|
||||
/* get_next_scheduled_send()
|
||||
* return number of scheduled sendto
|
||||
* set next_send to timestamp to send next packet */
|
||||
|
|
|
@ -1,61 +1,32 @@
|
|||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* author: Ryan Wagoner and Thomas Bernard
|
||||
* author: Gleb Smirnoff <glebius@FreeBSD.org>
|
||||
* (c) 2006 Ryan Wagoner
|
||||
* (c) 2014 Gleb Smirnoff
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
#include <syslog.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#ifdef __DragonFly__
|
||||
#define _KERNEL_STRUCTURES
|
||||
#endif
|
||||
#include <net/if_var.h>
|
||||
#endif
|
||||
#if defined(__DragonFly__)
|
||||
#include <net/pf/pfvar.h>
|
||||
#else
|
||||
#include <net/pfvar.h>
|
||||
#endif
|
||||
#include <kvm.h>
|
||||
#include <fcntl.h>
|
||||
#include <nlist.h>
|
||||
#include <sys/queue.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include "../getifstats.h"
|
||||
#include "../config.h"
|
||||
|
||||
static struct nlist list[] = {
|
||||
{"_ifnet", 0, 0, 0, 0},
|
||||
{NULL,0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int
|
||||
getifstats(const char * ifname, struct ifdata * data)
|
||||
getifstats(const char *ifname, struct ifdata *data)
|
||||
{
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
struct ifnethead ifh;
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
struct ifnet_head ifh;
|
||||
#else
|
||||
#error "Dont know if I should use struct ifnethead or struct ifnet_head"
|
||||
#endif
|
||||
struct ifnet ifc;
|
||||
struct ifnet *ifp;
|
||||
kvm_t *kd;
|
||||
ssize_t n;
|
||||
char errstr[_POSIX2_LINE_MAX];
|
||||
static struct ifaddrs *ifap, *ifa;
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
static time_t cache_timestamp = 0;
|
||||
static struct ifdata cache_data;
|
||||
static time_t cache_timestamp;
|
||||
time_t current_time;
|
||||
#endif
|
||||
if(!data)
|
||||
|
@ -67,70 +38,40 @@ getifstats(const char * ifname, struct ifdata * data)
|
|||
data->ibytes = 0;
|
||||
if(!ifname || ifname[0]=='\0')
|
||||
return -1;
|
||||
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
current_time = time(NULL);
|
||||
if(current_time == ((time_t)-1)) {
|
||||
syslog(LOG_ERR, "getifstats() : time() error : %m");
|
||||
} else {
|
||||
if(current_time < cache_timestamp + GETIFSTATS_CACHING_DURATION) {
|
||||
memcpy(data, &cache_data, sizeof(struct ifdata));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (ifap != NULL &&
|
||||
current_time < cache_timestamp + GETIFSTATS_CACHING_DURATION)
|
||||
goto copy;
|
||||
#endif
|
||||
|
||||
/*kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);*/
|
||||
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errstr);
|
||||
if(!kd)
|
||||
{
|
||||
syslog (LOG_ERR, "getifstats() : kvm_open(): %s", errstr);
|
||||
return -1;
|
||||
if (ifap != NULL) {
|
||||
freeifaddrs(ifap);
|
||||
ifap = NULL;
|
||||
}
|
||||
if(kvm_nlist(kd, list) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "getifstats() : kvm_nlist(): FAILED");
|
||||
goto error;
|
||||
}
|
||||
if(!list[0].n_value)
|
||||
{
|
||||
syslog(LOG_ERR, "getifstats() : n_value(): FAILED");
|
||||
goto error;
|
||||
}
|
||||
n = kvm_read(kd, list[0].n_value, &ifh, sizeof(ifh));
|
||||
if(n<0)
|
||||
{
|
||||
syslog(LOG_ERR, "getifstats() : kvm_read(head): %s", kvm_geterr(kd));
|
||||
goto error;
|
||||
}
|
||||
for(ifp = TAILQ_FIRST(&ifh); ifp; ifp = TAILQ_NEXT(&ifc, if_list))
|
||||
{
|
||||
n = kvm_read(kd, (u_long)ifp, &ifc, sizeof(ifc));
|
||||
if(n<0)
|
||||
{
|
||||
syslog(LOG_ERR, "getifstats() : kvm_read(element): %s", kvm_geterr(kd));
|
||||
goto error;
|
||||
}
|
||||
if(strcmp(ifname, ifc.if_xname) == 0)
|
||||
{
|
||||
/* found the right interface */
|
||||
data->opackets = ifc.if_data.ifi_opackets;
|
||||
data->ipackets = ifc.if_data.ifi_ipackets;
|
||||
data->obytes = ifc.if_data.ifi_obytes;
|
||||
data->ibytes = ifc.if_data.ifi_ibytes;
|
||||
data->baudrate = ifc.if_data.ifi_baudrate;
|
||||
kvm_close(kd);
|
||||
|
||||
if (getifaddrs(&ifap) != 0) {
|
||||
syslog (LOG_ERR, "getifstats() : getifaddrs(): %s",
|
||||
strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (ifa = ifap; ifa; ifa = ifa->ifa_next)
|
||||
if (ifa->ifa_addr->sa_family == AF_LINK &&
|
||||
strcmp(ifa->ifa_name, ifname) == 0) {
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
if(current_time!=((time_t)-1)) {
|
||||
cache_timestamp = current_time;
|
||||
memcpy(&cache_data, data, sizeof(struct ifdata));
|
||||
}
|
||||
cache_timestamp = current_time;
|
||||
copy:
|
||||
#endif
|
||||
return 0; /* ok */
|
||||
#define IFA_STAT(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
|
||||
data->opackets = IFA_STAT(opackets);
|
||||
data->ipackets = IFA_STAT(ipackets);
|
||||
data->obytes = IFA_STAT(obytes);
|
||||
data->ibytes = IFA_STAT(ibytes);
|
||||
data->baudrate = IFA_STAT(baudrate);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
error:
|
||||
kvm_close(kd);
|
||||
return -1; /* not found or error */
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: ifacewatcher.c,v 1.6 2014/03/31 12:27:14 nanard Exp $ */
|
||||
/* $Id: ifacewatcher.c,v 1.8 2014/04/18 08:23:51 nanard Exp $ */
|
||||
/* Project MiniUPnP
|
||||
* web : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2011 Thomas BERNARD
|
||||
|
@ -73,6 +73,18 @@ ProcessInterfaceWatchNotify(int s)
|
|||
syslog(LOG_DEBUG, " RTM_IFINFO: addrs=%x flags=%x index=%hu",
|
||||
ifm->ifm_addrs, ifm->ifm_flags, ifm->ifm_index);
|
||||
break;
|
||||
case RTM_ADD: /* Add Route */
|
||||
syslog(LOG_DEBUG, " RTM_ADD");
|
||||
break;
|
||||
case RTM_DELETE: /* Delete Route */
|
||||
syslog(LOG_DEBUG, " RTM_DELETE");
|
||||
break;
|
||||
case RTM_CHANGE: /* Change Metrics or flags */
|
||||
syslog(LOG_DEBUG, " RTM_CHANGE");
|
||||
break;
|
||||
case RTM_GET: /* Report Metrics */
|
||||
syslog(LOG_DEBUG, " RTM_GET");
|
||||
break;
|
||||
#ifdef RTM_IFANNOUNCE
|
||||
case RTM_IFANNOUNCE: /* iface arrival/departure */
|
||||
ifanm = (struct if_announcemsghdr *)buf;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#! /bin/sh
|
||||
# $Id: genconfig.sh,v 1.72 2014/03/10 10:17:17 nanard Exp $
|
||||
# $Id: genconfig.sh,v 1.74 2014/04/09 07:21:00 nanard Exp $
|
||||
# miniupnp daemon
|
||||
# http://miniupnp.free.fr or http://miniupnp.tuxfamily.org/
|
||||
# (c) 2006-2014 Thomas Bernard
|
||||
|
@ -443,6 +443,9 @@ echo "" >> ${CONFIGFILE}
|
|||
echo "#ifdef IGD_V2" >> ${CONFIGFILE}
|
||||
echo "/* Enable DeviceProtection service (IGDv2) */" >> ${CONFIGFILE}
|
||||
echo "#define ENABLE_DP_SERVICE" >> ${CONFIGFILE}
|
||||
echo "/*#define ENABLE_HTTPS*/" >> ${CONFIGFILE}
|
||||
echo "/*#define HTTPS_CERTFILE \"/path/to/certificate.pem\"*/" >> ${CONFIGFILE}
|
||||
echo "/*#define HTTPS_KEYFILE \"/path/to/private.key\"*/" >> ${CONFIGFILE}
|
||||
echo "" >> ${CONFIGFILE}
|
||||
echo "/* Enable WANIPv6FirewallControl service (IGDv2). needs IPv6 */" >> ${CONFIGFILE}
|
||||
echo "#ifdef ENABLE_IPV6" >> ${CONFIGFILE}
|
||||
|
@ -507,6 +510,13 @@ else
|
|||
fi
|
||||
echo "" >> ${CONFIGFILE}
|
||||
|
||||
cat >> ${CONFIGFILE} <<EOF
|
||||
#if defined(ENABLE_6FC_SERVICE) || (defined(ENABLE_PCP) && defined(ENABLE_IPV6))
|
||||
#define ENABLE_UPNPPINHOLE
|
||||
#endif
|
||||
|
||||
EOF
|
||||
|
||||
echo "#endif /* ${CONFIGMACRO} */" >> ${CONFIGFILE}
|
||||
|
||||
${MV} ${CONFIGFILE} ${CONFIGFILE_FINAL}
|
||||
|
|
|
@ -138,9 +138,8 @@ getifaddr(const char * ifname, char * buf, int len,
|
|||
}
|
||||
|
||||
#ifdef ENABLE_PCP
|
||||
/* XXX I don't know if this function should return
|
||||
* IPv4 or IPv6 if both are enabled... */
|
||||
int getifaddr_in6(const char * ifname, struct in6_addr * addr)
|
||||
|
||||
int getifaddr_in6(const char * ifname, int af, struct in6_addr * addr)
|
||||
{
|
||||
#if defined(ENABLE_IPV6) || defined(USE_GETIFADDRS)
|
||||
struct ifaddrs * ifap;
|
||||
|
@ -164,6 +163,8 @@ int getifaddr_in6(const char * ifname, struct in6_addr * addr)
|
|||
continue;
|
||||
if(ife->ifa_addr == NULL)
|
||||
continue;
|
||||
if (ife->ifa_addr->sa_family != af)
|
||||
continue;
|
||||
switch(ife->ifa_addr->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
|
@ -197,6 +198,8 @@ int getifaddr_in6(const char * ifname, struct in6_addr * addr)
|
|||
#else /* defined(ENABLE_IPV6) || defined(USE_GETIFADDRS) */
|
||||
/* IPv4 only */
|
||||
struct in_addr addr4;
|
||||
if(af != AF_INET)
|
||||
return -1;
|
||||
if(getifaddr(ifname, NULL, 0, &addr4, NULL) < 0)
|
||||
return -1;
|
||||
/* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */
|
||||
|
|
|
@ -20,7 +20,7 @@ getifaddr(const char * ifname, char * buf, int len,
|
|||
struct in_addr * addr, struct in_addr * mask);
|
||||
|
||||
int
|
||||
getifaddr_in6(const char * ifname, struct in6_addr* addr);
|
||||
getifaddr_in6(const char * ifname, int af, struct in6_addr* addr);
|
||||
|
||||
/* find a non link local IP v6 address for the interface.
|
||||
* if ifname is NULL, look for all interfaces */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: minissdp.c,v 1.62 2014/03/24 09:31:23 nanard Exp $ */
|
||||
/* $Id: minissdp.c,v 1.72 2014/10/22 11:54:45 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2014 Thomas Bernard
|
||||
|
@ -26,12 +26,22 @@
|
|||
#include "getroute.h"
|
||||
#include "asyncsendto.h"
|
||||
#include "codelength.h"
|
||||
#include "macros.h"
|
||||
|
||||
/* SSDP ip/port */
|
||||
#define SSDP_PORT (1900)
|
||||
#define SSDP_MCAST_ADDR ("239.255.255.250")
|
||||
#define LL_SSDP_MCAST_ADDR "FF02::C"
|
||||
#define SL_SSDP_MCAST_ADDR "FF05::C"
|
||||
#define GL_SSDP_MCAST_ADDR "FF0E::C"
|
||||
|
||||
/* maximum lenght of SSDP packets we are generating
|
||||
* (reception is done in a 1500byte buffer) */
|
||||
#ifdef ENABLE_HTTPS
|
||||
#define SSDP_PACKET_MAX_LEN 768
|
||||
#else
|
||||
#define SSDP_PACKET_MAX_LEN 512
|
||||
#endif
|
||||
|
||||
/* AddMulticastMembership()
|
||||
* param s socket
|
||||
|
@ -58,21 +68,19 @@ AddMulticastMembership(int s, in_addr_t ifaddr)
|
|||
|
||||
/* AddMulticastMembershipIPv6()
|
||||
* param s socket (IPv6)
|
||||
* To be improved to target specific network interfaces */
|
||||
* param ifindex : interface index (0 : All interfaces) */
|
||||
#ifdef ENABLE_IPV6
|
||||
static int
|
||||
AddMulticastMembershipIPv6(int s)
|
||||
AddMulticastMembershipIPv6(int s, unsigned int ifindex)
|
||||
{
|
||||
struct ipv6_mreq mr;
|
||||
/*unsigned int ifindex;*/
|
||||
|
||||
memset(&mr, 0, sizeof(mr));
|
||||
inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
|
||||
/*mr.ipv6mr_interface = ifindex;*/
|
||||
mr.ipv6mr_interface = 0; /* 0 : all interfaces */
|
||||
mr.ipv6mr_interface = ifindex; /* 0 : all interfaces */
|
||||
#ifndef IPV6_ADD_MEMBERSHIP
|
||||
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||
#endif
|
||||
inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
|
||||
if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
|
||||
|
@ -84,6 +92,12 @@ AddMulticastMembershipIPv6(int s)
|
|||
syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
|
||||
return -1;
|
||||
}
|
||||
inet_pton(AF_INET6, GL_SSDP_MCAST_ADDR, &mr.ipv6mr_multiaddr);
|
||||
if(setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(struct ipv6_mreq)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "setsockopt(udp, IPV6_ADD_MEMBERSHIP): %m");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -108,13 +122,18 @@ OpenAndConfSSDPReceiveSocket(int ipv6)
|
|||
}
|
||||
|
||||
memset(&sockname, 0, sizeof(struct sockaddr_storage));
|
||||
if(ipv6) {
|
||||
#ifdef ENABLE_IPV6
|
||||
if(ipv6)
|
||||
{
|
||||
struct sockaddr_in6 * saddr = (struct sockaddr_in6 *)&sockname;
|
||||
saddr->sin6_family = AF_INET6;
|
||||
saddr->sin6_port = htons(SSDP_PORT);
|
||||
saddr->sin6_addr = in6addr_any;
|
||||
saddr->sin6_addr = ipv6_bind_addr;
|
||||
sockname_len = sizeof(struct sockaddr_in6);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
#endif /* ENABLE_IPV6 */
|
||||
{
|
||||
struct sockaddr_in * saddr = (struct sockaddr_in *)&sockname;
|
||||
saddr->sin_family = AF_INET;
|
||||
saddr->sin_port = htons(SSDP_PORT);
|
||||
|
@ -147,10 +166,14 @@ OpenAndConfSSDPReceiveSocket(int ipv6)
|
|||
#ifdef ENABLE_IPV6
|
||||
if(ipv6)
|
||||
{
|
||||
if(AddMulticastMembershipIPv6(s) < 0)
|
||||
for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
|
||||
{
|
||||
syslog(LOG_WARNING,
|
||||
"Failed to add IPv6 multicast membership");
|
||||
if(AddMulticastMembershipIPv6(s, lan_addr->index) < 0)
|
||||
{
|
||||
syslog(LOG_WARNING,
|
||||
"Failed to add IPv6 multicast membership for interface %s",
|
||||
lan_addr->str ? lan_addr->str : "NULL");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -219,6 +242,10 @@ OpenAndConfSSDPNotifySocket(in_addr_t addr)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* bind() socket before using sendto() is not mandatory
|
||||
* (sendto() will implicitly bind the socket when called on
|
||||
* an unbound socket)
|
||||
* here it is used to se a specific sending address */
|
||||
memset(&sockname, 0, sizeof(struct sockaddr_in));
|
||||
sockname.sin_family = AF_INET;
|
||||
sockname.sin_addr.s_addr = addr; /*inet_addr(addr);*/
|
||||
|
@ -241,6 +268,7 @@ OpenAndConfSSDPNotifySocketIPv6(unsigned int if_index)
|
|||
{
|
||||
int s;
|
||||
unsigned int loop = 0;
|
||||
struct sockaddr_in6 sockname;
|
||||
|
||||
s = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
if(s < 0)
|
||||
|
@ -260,6 +288,23 @@ OpenAndConfSSDPNotifySocketIPv6(unsigned int if_index)
|
|||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* bind() socket before using sendto() is not mandatory
|
||||
* (sendto() will implicitly bind the socket when called on
|
||||
* an unbound socket)
|
||||
* but explicit bind permits to set port/scope_id/etc. */
|
||||
memset(&sockname, 0, sizeof(sockname));
|
||||
sockname.sin6_family = AF_INET6;
|
||||
sockname.sin6_addr = in6addr_any;
|
||||
/*sockname.sin6_port = htons(port);*/
|
||||
/*sockname.sin6_scope_id = if_index;*/
|
||||
if(bind(s, (struct sockaddr *)&sockname, sizeof(sockname)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "bind(udp_notify IPv6): %m");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
@ -336,11 +381,14 @@ EXT:
|
|||
static void
|
||||
SendSSDPResponse(int s, const struct sockaddr * addr,
|
||||
const char * st, int st_len, const char * suffix,
|
||||
const char * host, unsigned short port, const char * uuidvalue,
|
||||
unsigned int delay)
|
||||
const char * host, unsigned short http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
unsigned short https_port,
|
||||
#endif
|
||||
const char * uuidvalue, unsigned int delay)
|
||||
{
|
||||
int l, n;
|
||||
char buf[512];
|
||||
char buf[SSDP_PACKET_MAX_LEN];
|
||||
char addr_str[64];
|
||||
socklen_t addrlen;
|
||||
int st_is_uuid;
|
||||
|
@ -375,6 +423,9 @@ SendSSDPResponse(int s, const struct sockaddr * addr,
|
|||
"EXT:\r\n"
|
||||
"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
|
||||
"LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
|
||||
#ifdef ENABLE_HTTPS
|
||||
"SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH "\r\n"
|
||||
#endif
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
|
||||
"01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
|
||||
"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
|
||||
|
@ -386,7 +437,10 @@ SendSSDPResponse(int s, const struct sockaddr * addr,
|
|||
st_len, st, suffix,
|
||||
uuidvalue, st_is_uuid ? "" : "::",
|
||||
st_is_uuid ? 0 : st_len, st, suffix,
|
||||
host, (unsigned int)port,
|
||||
host, (unsigned int)http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
host, (unsigned int)https_port,
|
||||
#endif
|
||||
upnp_bootid, upnp_bootid, upnp_configid);
|
||||
if(l<0)
|
||||
{
|
||||
|
@ -396,8 +450,8 @@ SendSSDPResponse(int s, const struct sockaddr * addr,
|
|||
}
|
||||
else if((unsigned)l>=sizeof(buf))
|
||||
{
|
||||
syslog(LOG_WARNING, "%s: truncated output",
|
||||
"SendSSDPResponse()");
|
||||
syslog(LOG_WARNING, "%s: truncated output (%u>=%u)",
|
||||
"SendSSDPResponse()", (unsigned)l, (unsigned)sizeof(buf));
|
||||
l = sizeof(buf) - 1;
|
||||
}
|
||||
addrlen = (addr->sa_family == AF_INET6)
|
||||
|
@ -447,24 +501,36 @@ static struct {
|
|||
#ifdef ENABLE_6FC_SERVICE
|
||||
{"url:schemas-upnp-org:service:WANIPv6FirewallControl:", 1, uuidvalue_wcd},
|
||||
#endif
|
||||
/* we might want to support urn:schemas-wifialliance-org:device:WFADevice:1
|
||||
* urn:schemas-wifialliance-org:device:WFADevice:1
|
||||
* in the future */
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
/* SendSSDPNotify() sends the SSDP NOTIFY to a specific
|
||||
* destination, for a specific UPnP service or device */
|
||||
static void
|
||||
SendSSDPNotify(int s, const struct sockaddr * dest,
|
||||
const char * host, unsigned short port,
|
||||
SendSSDPNotify(int s, const struct sockaddr * dest, socklen_t dest_len,
|
||||
const char * dest_str,
|
||||
const char * host, unsigned short http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
unsigned short https_port,
|
||||
#endif
|
||||
const char * nt, const char * suffix,
|
||||
const char * usn1, const char * usn2, const char * usn3,
|
||||
unsigned int lifetime, int ipv6)
|
||||
unsigned int lifetime)
|
||||
{
|
||||
char bufr[512];
|
||||
char bufr[SSDP_PACKET_MAX_LEN];
|
||||
int n, l;
|
||||
|
||||
l = snprintf(bufr, sizeof(bufr),
|
||||
"NOTIFY * HTTP/1.1\r\n"
|
||||
"HOST: %s:%d\r\n"
|
||||
"CACHE-CONTROL: max-age=%u\r\n"
|
||||
"LOCATION: http://%s:%d" ROOTDESC_PATH"\r\n"
|
||||
"LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
|
||||
#ifdef ENABLE_HTTPS
|
||||
"SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH "\r\n"
|
||||
#endif
|
||||
"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
|
||||
"NT: %s%s\r\n"
|
||||
"USN: %s%s%s%s\r\n"
|
||||
|
@ -474,139 +540,182 @@ SendSSDPNotify(int s, const struct sockaddr * dest,
|
|||
"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
|
||||
"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
|
||||
"\r\n",
|
||||
ipv6 ? "[" LL_SSDP_MCAST_ADDR "]" : SSDP_MCAST_ADDR,
|
||||
SSDP_PORT,
|
||||
lifetime,
|
||||
host, port,
|
||||
nt, suffix, /* NT: */
|
||||
usn1, usn2, usn3, suffix, /* USN: */
|
||||
upnp_bootid, upnp_bootid, upnp_configid );
|
||||
if(l<0)
|
||||
{
|
||||
syslog(LOG_ERR, "SendSSDPNotify() snprintf error");
|
||||
dest_str, SSDP_PORT, /* HOST: */
|
||||
lifetime, /* CACHE-CONTROL: */
|
||||
host, (unsigned int)http_port, /* LOCATION: */
|
||||
#ifdef ENABLE_HTTPS
|
||||
host, (unsigned int)https_port, /* SECURE-LOCATION: */
|
||||
#endif
|
||||
nt, suffix, /* NT: */
|
||||
usn1, usn2, usn3, suffix, /* USN: */
|
||||
upnp_bootid, /* 01-NLS: */
|
||||
upnp_bootid, /* BOOTID.UPNP.ORG: */
|
||||
upnp_configid ); /* CONFIGID.UPNP.ORG: */
|
||||
if(l<0) {
|
||||
syslog(LOG_ERR, "%s: snprintf error", "SendSSDPNotify()");
|
||||
return;
|
||||
}
|
||||
else if((unsigned int)l >= sizeof(bufr))
|
||||
{
|
||||
syslog(LOG_WARNING, "SendSSDPNotify(): truncated output");
|
||||
} else if((unsigned int)l >= sizeof(bufr)) {
|
||||
syslog(LOG_WARNING, "%s: truncated output (%u>=%u)",
|
||||
"SendSSDPNotify()", (unsigned)l, (unsigned)sizeof(bufr));
|
||||
l = sizeof(bufr) - 1;
|
||||
}
|
||||
n = sendto_or_schedule(s, bufr, l, 0, dest,
|
||||
#ifdef ENABLE_IPV6
|
||||
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)
|
||||
#else
|
||||
sizeof(struct sockaddr_in)
|
||||
#endif
|
||||
);
|
||||
if(n < 0)
|
||||
{
|
||||
n = sendto_or_schedule(s, bufr, l, 0, dest, dest_len);
|
||||
if(n < 0) {
|
||||
syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s,
|
||||
host ? host : "NULL");
|
||||
}
|
||||
else if(n != l)
|
||||
{
|
||||
} else if(n != l) {
|
||||
syslog(LOG_NOTICE, "sendto() sent %d out of %d bytes", n, l);
|
||||
}
|
||||
/* Due to the unreliable nature of UDP, devices SHOULD send the entire
|
||||
* set of discovery messages more than once with some delay between
|
||||
* sets e.g. a few hundred milliseconds. To avoid network congestion
|
||||
* discovery messages SHOULD NOT be sent more than three times. */
|
||||
n = sendto_schedule(s, bufr, l, 0, dest,
|
||||
#ifdef ENABLE_IPV6
|
||||
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in),
|
||||
#else
|
||||
sizeof(struct sockaddr_in),
|
||||
#endif
|
||||
250);
|
||||
if(n < 0)
|
||||
{
|
||||
n = sendto_schedule(s, bufr, l, 0, dest, dest_len, 250);
|
||||
if(n < 0) {
|
||||
syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s,
|
||||
host ? host : "NULL");
|
||||
}
|
||||
}
|
||||
|
||||
/* SendSSDPNotifies() send SSPD NOTIFY for a specific
|
||||
* LAN (network interface) for all devices / services */
|
||||
#ifdef ENABLE_HTTPS
|
||||
static void
|
||||
SendSSDPNotifies(int s, const char * host, unsigned short port,
|
||||
SendSSDPNotifies(int s, const char * host, unsigned short http_port,
|
||||
unsigned short https_port,
|
||||
unsigned int lifetime, int ipv6)
|
||||
#else
|
||||
static void
|
||||
SendSSDPNotifies(int s, const char * host, unsigned short http_port,
|
||||
unsigned int lifetime, int ipv6)
|
||||
#endif
|
||||
{
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_storage sockname;
|
||||
#else
|
||||
static struct { const char * p1, * p2; } const mcast_addrs[] =
|
||||
{ { LL_SSDP_MCAST_ADDR, "[" LL_SSDP_MCAST_ADDR "]" }, /* Link Local */
|
||||
{ SL_SSDP_MCAST_ADDR, "[" SL_SSDP_MCAST_ADDR "]" }, /* Site Local */
|
||||
{ GL_SSDP_MCAST_ADDR, "[" GL_SSDP_MCAST_ADDR "]" }, /* Global */
|
||||
{ NULL, NULL } };
|
||||
int j;
|
||||
#else /* ENABLE_IPV6 */
|
||||
struct sockaddr_in sockname;
|
||||
#endif
|
||||
int i=0;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
socklen_t sockname_len;
|
||||
const char * dest_str;
|
||||
int i;
|
||||
char ver_str[4];
|
||||
#ifndef ENABLE_IPV6
|
||||
UNUSED(ipv6);
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
memset(&sockname, 0, sizeof(sockname));
|
||||
#ifdef ENABLE_IPV6
|
||||
if(ipv6)
|
||||
{
|
||||
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockname;
|
||||
p->sin6_family = AF_INET6;
|
||||
p->sin6_port = htons(SSDP_PORT);
|
||||
inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &(p->sin6_addr));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
struct sockaddr_in *p = (struct sockaddr_in *)&sockname;
|
||||
p->sin_family = AF_INET;
|
||||
p->sin_port = htons(SSDP_PORT);
|
||||
p->sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
||||
}
|
||||
|
||||
while(known_service_types[i].s)
|
||||
{
|
||||
if(i==0)
|
||||
ver_str[0] = '\0';
|
||||
else
|
||||
snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version);
|
||||
SendSSDPNotify(s, (struct sockaddr *)&sockname, host, port,
|
||||
known_service_types[i].s, ver_str, /* NT: */
|
||||
known_service_types[i].uuid, "::",
|
||||
known_service_types[i].s, /* ver_str, USN: */
|
||||
lifetime, ipv6);
|
||||
if(0==memcmp(known_service_types[i].s,
|
||||
"urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1))
|
||||
/* first iterate destinations for this LAN interface (only 1 for IPv4) */
|
||||
for(j = 0; (mcast_addrs[j].p1 != 0 && ipv6) || j < 1; j++) {
|
||||
if(ipv6) {
|
||||
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockname;
|
||||
sockname_len = sizeof(struct sockaddr_in6);
|
||||
p->sin6_family = AF_INET6;
|
||||
p->sin6_port = htons(SSDP_PORT);
|
||||
inet_pton(AF_INET6, mcast_addrs[j].p1, &(p->sin6_addr));
|
||||
dest_str = mcast_addrs[j].p2;
|
||||
/* UPnP Device Architecture 1.1 :
|
||||
* Devices MUST multicast SSDP messages for each of the UPnP-enabled
|
||||
* interfaces. The scope of multicast SSDP messages MUST be
|
||||
* link local FF02::C if the message is sent from a link local address.
|
||||
* If the message is sent from a global address it MUST be multicast
|
||||
* using either global scope FF0E::C or site local scope FF05::C.
|
||||
* In networks with complex topologies and overlapping sites, use of
|
||||
* global scope is RECOMMENDED. */
|
||||
} else {
|
||||
#else /* ENABLE_IPV6 */
|
||||
{
|
||||
SendSSDPNotify(s, (struct sockaddr *)&sockname, host, port,
|
||||
known_service_types[i].uuid, "", /* NT: */
|
||||
known_service_types[i].uuid, "", "", /* ver_str, USN: */
|
||||
lifetime, ipv6);
|
||||
#endif /* ENABLE_IPV6 */
|
||||
/* IPv4 */
|
||||
struct sockaddr_in *p = (struct sockaddr_in *)&sockname;
|
||||
sockname_len = sizeof(struct sockaddr_in);
|
||||
p->sin_family = AF_INET;
|
||||
p->sin_port = htons(SSDP_PORT);
|
||||
p->sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
||||
dest_str = SSDP_MCAST_ADDR;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
/* iterate all services / devices */
|
||||
for(i = 0; known_service_types[i].s; i++) {
|
||||
if(i==0)
|
||||
ver_str[0] = '\0';
|
||||
else
|
||||
snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version);
|
||||
SendSSDPNotify(s, (struct sockaddr *)&sockname, sockname_len, dest_str,
|
||||
host, http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
https_port,
|
||||
#endif
|
||||
known_service_types[i].s, ver_str, /* NT: */
|
||||
known_service_types[i].uuid, "::",
|
||||
known_service_types[i].s, /* ver_str, USN: */
|
||||
lifetime);
|
||||
/* for devices, also send NOTIFY on the uuid */
|
||||
if(0==memcmp(known_service_types[i].s,
|
||||
"urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1)) {
|
||||
SendSSDPNotify(s, (struct sockaddr *)&sockname, sockname_len, dest_str,
|
||||
host, http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
https_port,
|
||||
#endif
|
||||
known_service_types[i].uuid, "", /* NT: */
|
||||
known_service_types[i].uuid, "", "", /* ver_str, USN: */
|
||||
lifetime);
|
||||
}
|
||||
} /* for(i = 0; known_service_types[i].s; i++) */
|
||||
#ifdef ENABLE_IPV6
|
||||
} /* for(j = 0; (mcast_addrs[j].p1 != 0 && ipv6) || j < 1; j++) */
|
||||
#endif /* ENABLE_IPV6 */
|
||||
}
|
||||
|
||||
/* SendSSDPNotifies2() sends SSDP NOTIFY packets on all interfaces
|
||||
* for all destinations, all devices / services */
|
||||
void
|
||||
SendSSDPNotifies2(int * sockets,
|
||||
unsigned short port,
|
||||
unsigned short http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
unsigned short https_port,
|
||||
#endif
|
||||
unsigned int lifetime)
|
||||
{
|
||||
int i;
|
||||
struct lan_addr_s * lan_addr;
|
||||
for(i=0, lan_addr = lan_addrs.lh_first;
|
||||
for(i = 0, lan_addr = lan_addrs.lh_first;
|
||||
lan_addr != NULL;
|
||||
lan_addr = lan_addr->list.le_next)
|
||||
{
|
||||
SendSSDPNotifies(sockets[i], lan_addr->str, port,
|
||||
lan_addr = lan_addr->list.le_next) {
|
||||
SendSSDPNotifies(sockets[i], lan_addr->str, http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
https_port,
|
||||
#endif
|
||||
lifetime, 0);
|
||||
i++;
|
||||
#ifdef ENABLE_IPV6
|
||||
if(sockets[i] >= 0)
|
||||
{
|
||||
SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, port,
|
||||
if(sockets[i] >= 0) {
|
||||
SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
https_port,
|
||||
#endif
|
||||
lifetime, 1);
|
||||
}
|
||||
i++;
|
||||
#endif
|
||||
#endif /* ENABLE_IPV6 */
|
||||
}
|
||||
}
|
||||
|
||||
/* ProcessSSDPRequest()
|
||||
* process SSDP M-SEARCH requests and responds to them */
|
||||
void
|
||||
ProcessSSDPRequest(int s, unsigned short port)
|
||||
#ifdef ENABLE_HTTPS
|
||||
ProcessSSDPRequest(int s, unsigned short http_port, unsigned short https_port)
|
||||
#else
|
||||
ProcessSSDPRequest(int s, unsigned short http_port)
|
||||
#endif
|
||||
{
|
||||
int n;
|
||||
char bufr[1500];
|
||||
|
@ -633,13 +742,28 @@ ProcessSSDPRequest(int s, unsigned short port)
|
|||
}
|
||||
return;
|
||||
}
|
||||
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, port);
|
||||
#ifdef ENABLE_HTTPS
|
||||
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername,
|
||||
http_port, https_port);
|
||||
#else
|
||||
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername,
|
||||
http_port);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef ENABLE_HTTPS
|
||||
void
|
||||
ProcessSSDPData(int s, const char *bufr, int n,
|
||||
const struct sockaddr * sender, unsigned short port) {
|
||||
const struct sockaddr * sender,
|
||||
unsigned short http_port, unsigned short https_port)
|
||||
#else
|
||||
void
|
||||
ProcessSSDPData(int s, const char *bufr, int n,
|
||||
const struct sockaddr * sender,
|
||||
unsigned short http_port)
|
||||
#endif
|
||||
{
|
||||
int i, l;
|
||||
struct lan_addr_s * lan_addr = NULL;
|
||||
const char * st = NULL;
|
||||
|
@ -656,7 +780,7 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
|||
#if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE)
|
||||
int mx_value = -1;
|
||||
#endif
|
||||
unsigned int delay = 0;
|
||||
unsigned int delay = 50; /* Non-zero default delay to prevent flooding */
|
||||
/* UPnP Device Architecture v1.1. 1.3.3 Search response :
|
||||
* Devices responding to a multicast M-SEARCH SHOULD wait a random period
|
||||
* of time between 0 seconds and the number of seconds specified in the
|
||||
|
@ -847,7 +971,10 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
|||
#else
|
||||
known_service_types[i].s, l, ver_str,
|
||||
#endif
|
||||
announced_host, port,
|
||||
announced_host, http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
https_port,
|
||||
#endif
|
||||
known_service_types[i].uuid,
|
||||
delay);
|
||||
break;
|
||||
|
@ -873,7 +1000,10 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
|||
l = (int)strlen(known_service_types[i].s);
|
||||
SendSSDPResponse(s, sender,
|
||||
known_service_types[i].s, l, ver_str,
|
||||
announced_host, port,
|
||||
announced_host, http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
https_port,
|
||||
#endif
|
||||
known_service_types[i].uuid,
|
||||
delay);
|
||||
}
|
||||
|
@ -882,17 +1012,29 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
|||
delay += delay_increment;
|
||||
#endif
|
||||
SendSSDPResponse(s, sender, uuidvalue_igd, strlen(uuidvalue_igd), "",
|
||||
announced_host, port, uuidvalue_igd, delay);
|
||||
announced_host, http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
https_port,
|
||||
#endif
|
||||
uuidvalue_igd, delay);
|
||||
#ifdef DELAY_MSEARCH_RESPONSE
|
||||
delay += delay_increment;
|
||||
#endif
|
||||
SendSSDPResponse(s, sender, uuidvalue_wan, strlen(uuidvalue_wan), "",
|
||||
announced_host, port, uuidvalue_wan, delay);
|
||||
announced_host, http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
https_port,
|
||||
#endif
|
||||
uuidvalue_wan, delay);
|
||||
#ifdef DELAY_MSEARCH_RESPONSE
|
||||
delay += delay_increment;
|
||||
#endif
|
||||
SendSSDPResponse(s, sender, uuidvalue_wcd, strlen(uuidvalue_wcd), "",
|
||||
announced_host, port, uuidvalue_wcd, delay);
|
||||
announced_host, http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
https_port,
|
||||
#endif
|
||||
uuidvalue_wcd, delay);
|
||||
}
|
||||
/* responds to request by UUID value */
|
||||
l = (int)strlen(uuidvalue_igd);
|
||||
|
@ -905,22 +1047,31 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
|||
{
|
||||
syslog(LOG_INFO, "ssdp:uuid (IGD) found");
|
||||
SendSSDPResponse(s, sender, st, st_len, "",
|
||||
announced_host, port, uuidvalue_igd,
|
||||
delay);
|
||||
announced_host, http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
https_port,
|
||||
#endif
|
||||
uuidvalue_igd, delay);
|
||||
}
|
||||
else if(0 == memcmp(st, uuidvalue_wan, l))
|
||||
{
|
||||
syslog(LOG_INFO, "ssdp:uuid (WAN) found");
|
||||
SendSSDPResponse(s, sender, st, st_len, "",
|
||||
announced_host, port, uuidvalue_wan,
|
||||
delay);
|
||||
announced_host, http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
https_port,
|
||||
#endif
|
||||
uuidvalue_wan, delay);
|
||||
}
|
||||
else if(0 == memcmp(st, uuidvalue_wcd, l))
|
||||
{
|
||||
syslog(LOG_INFO, "ssdp:uuid (WCD) found");
|
||||
SendSSDPResponse(s, sender, st, st_len, "",
|
||||
announced_host, port, uuidvalue_wcd,
|
||||
delay);
|
||||
announced_host, http_port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
https_port,
|
||||
#endif
|
||||
uuidvalue_wcd, delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -936,13 +1087,13 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
|||
}
|
||||
|
||||
static int
|
||||
SendSSDPbyebye(int s, const struct sockaddr * dest,
|
||||
SendSSDPbyebye(int s, const struct sockaddr * dest, socklen_t destlen,
|
||||
const char * dest_str,
|
||||
const char * nt, const char * suffix,
|
||||
const char * usn1, const char * usn2, const char * usn3,
|
||||
int ipv6)
|
||||
const char * usn1, const char * usn2, const char * usn3)
|
||||
{
|
||||
int n, l;
|
||||
char bufr[512];
|
||||
char bufr[SSDP_PACKET_MAX_LEN];
|
||||
|
||||
l = snprintf(bufr, sizeof(bufr),
|
||||
"NOTIFY * HTTP/1.1\r\n"
|
||||
|
@ -955,28 +1106,22 @@ SendSSDPbyebye(int s, const struct sockaddr * dest,
|
|||
"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
|
||||
"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
|
||||
"\r\n",
|
||||
ipv6 ? "[" LL_SSDP_MCAST_ADDR "]" : SSDP_MCAST_ADDR,
|
||||
SSDP_PORT,
|
||||
nt, suffix, /* NT: */
|
||||
dest_str, SSDP_PORT, /* HOST : */
|
||||
nt, suffix, /* NT: */
|
||||
usn1, usn2, usn3, suffix, /* USN: */
|
||||
upnp_bootid, upnp_bootid, upnp_configid);
|
||||
if(l<0)
|
||||
{
|
||||
syslog(LOG_ERR, "SendSSDPbyebye() snprintf error");
|
||||
syslog(LOG_ERR, "%s: snprintf error", "SendSSDPbyebye()");
|
||||
return -1;
|
||||
}
|
||||
else if((unsigned int)l >= sizeof(bufr))
|
||||
{
|
||||
syslog(LOG_WARNING, "SendSSDPbyebye(): truncated output");
|
||||
syslog(LOG_WARNING, "%s: truncated output (%u>=%u)",
|
||||
"SendSSDPbyebye()", (unsigned)l, (unsigned)sizeof(bufr));
|
||||
l = sizeof(bufr) - 1;
|
||||
}
|
||||
n = sendto_or_schedule(s, bufr, l, 0, dest,
|
||||
#ifdef ENABLE_IPV6
|
||||
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)
|
||||
#else
|
||||
sizeof(struct sockaddr_in)
|
||||
#endif
|
||||
);
|
||||
n = sendto_or_schedule(s, bufr, l, 0, dest, destlen);
|
||||
if(n < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "sendto(udp_shutdown=%d): %m", s);
|
||||
|
@ -995,30 +1140,44 @@ SendSSDPbyebye(int s, const struct sockaddr * dest,
|
|||
int
|
||||
SendSSDPGoodbye(int * sockets, int n_sockets)
|
||||
{
|
||||
struct sockaddr_in sockname;
|
||||
struct sockaddr_in sockname4;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct sockaddr_in6 sockname6;
|
||||
struct sockaddr * sockname;
|
||||
socklen_t socknamelen;
|
||||
int ipv6 = 0;
|
||||
#endif
|
||||
int i, j;
|
||||
char ver_str[4];
|
||||
int ret = 0;
|
||||
int ipv6 = 0;
|
||||
const char * dest_str;
|
||||
|
||||
memset(&sockname, 0, sizeof(struct sockaddr_in));
|
||||
sockname.sin_family = AF_INET;
|
||||
sockname.sin_port = htons(SSDP_PORT);
|
||||
sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
||||
memset(&sockname4, 0, sizeof(struct sockaddr_in));
|
||||
sockname4.sin_family = AF_INET;
|
||||
sockname4.sin_port = htons(SSDP_PORT);
|
||||
sockname4.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
||||
#ifdef ENABLE_IPV6
|
||||
memset(&sockname6, 0, sizeof(struct sockaddr_in6));
|
||||
sockname6.sin6_family = AF_INET6;
|
||||
sockname6.sin6_port = htons(SSDP_PORT);
|
||||
inet_pton(AF_INET6, LL_SSDP_MCAST_ADDR, &(sockname6.sin6_addr));
|
||||
#else
|
||||
dest_str = SSDP_MCAST_ADDR;
|
||||
#endif
|
||||
|
||||
for(j=0; j<n_sockets; j++)
|
||||
{
|
||||
#ifdef ENABLE_IPV6
|
||||
ipv6 = j & 1;
|
||||
if(ipv6) {
|
||||
dest_str = "[" LL_SSDP_MCAST_ADDR "]";
|
||||
sockname = (struct sockaddr *)&sockname6;
|
||||
socknamelen = sizeof(struct sockaddr_in6);
|
||||
} else {
|
||||
dest_str = SSDP_MCAST_ADDR;
|
||||
sockname = (struct sockaddr *)&sockname4;
|
||||
socknamelen = sizeof(struct sockaddr_in);
|
||||
}
|
||||
#endif
|
||||
for(i=0; known_service_types[i].s; i++)
|
||||
{
|
||||
|
@ -1028,26 +1187,26 @@ SendSSDPGoodbye(int * sockets, int n_sockets)
|
|||
snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version);
|
||||
ret += SendSSDPbyebye(sockets[j],
|
||||
#ifdef ENABLE_IPV6
|
||||
ipv6 ? (struct sockaddr *)&sockname6 : (struct sockaddr *)&sockname,
|
||||
sockname, socknamelen,
|
||||
#else
|
||||
(struct sockaddr *)&sockname,
|
||||
(struct sockaddr *)&sockname4, sizeof(struct sockaddr_in),
|
||||
#endif
|
||||
dest_str,
|
||||
known_service_types[i].s, ver_str, /* NT: */
|
||||
known_service_types[i].uuid, "::",
|
||||
known_service_types[i].s, /* ver_str, USN: */
|
||||
ipv6);
|
||||
known_service_types[i].s); /* ver_str, USN: */
|
||||
if(0==memcmp(known_service_types[i].s,
|
||||
"urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1))
|
||||
{
|
||||
ret += SendSSDPbyebye(sockets[j],
|
||||
#ifdef ENABLE_IPV6
|
||||
ipv6 ? (struct sockaddr *)&sockname6 : (struct sockaddr *)&sockname,
|
||||
sockname, socknamelen,
|
||||
#else
|
||||
(struct sockaddr *)&sockname,
|
||||
(struct sockaddr *)&sockname4, sizeof(struct sockaddr_in),
|
||||
#endif
|
||||
dest_str,
|
||||
known_service_types[i].uuid, "", /* NT: */
|
||||
known_service_types[i].uuid, "", "", /* ver_str, USN: */
|
||||
ipv6);
|
||||
known_service_types[i].uuid, "", ""); /* ver_str, USN: */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $Id: minissdp.h,v 1.10 2011/05/23 12:39:41 nanard Exp $ */
|
||||
/* $Id: minissdp.h,v 1.12 2014/04/09 07:20:59 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2007 Thomas Bernard
|
||||
* (c) 2006-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
#ifndef MINISSDP_H_INCLUDED
|
||||
|
@ -14,28 +14,39 @@ OpenAndConfSSDPReceiveSocket(int ipv6);
|
|||
|
||||
int
|
||||
OpenAndConfSSDPNotifySockets(int * sockets);
|
||||
/*OpenAndConfSSDPNotifySockets(int * sockets,
|
||||
struct lan_addr_s * lan_addr, int n_lan_addr);*/
|
||||
|
||||
/*void
|
||||
SendSSDPNotifies(int s, const char * host, unsigned short port,
|
||||
unsigned int lifetime);*/
|
||||
#ifdef ENABLE_HTTPS
|
||||
void
|
||||
SendSSDPNotifies2(int * sockets,
|
||||
unsigned short port,
|
||||
unsigned short http_port,
|
||||
unsigned short https_port,
|
||||
unsigned int lifetime);
|
||||
/*SendSSDPNotifies2(int * sockets, struct lan_addr_s * lan_addr, int n_lan_addr,
|
||||
unsigned short port,
|
||||
unsigned int lifetime);*/
|
||||
#else
|
||||
void
|
||||
SendSSDPNotifies2(int * sockets,
|
||||
unsigned short http_port,
|
||||
unsigned int lifetime);
|
||||
#endif
|
||||
|
||||
void
|
||||
ProcessSSDPRequest(int s, unsigned short port);
|
||||
/*ProcessSSDPRequest(int s, struct lan_addr_s * lan_addr, int n_lan_addr,
|
||||
unsigned short port);*/
|
||||
#ifdef ENABLE_HTTPS
|
||||
ProcessSSDPRequest(int s,
|
||||
unsigned short http_port, unsigned short https_port);
|
||||
#else
|
||||
ProcessSSDPRequest(int s, unsigned short http_port);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_HTTPS
|
||||
void
|
||||
ProcessSSDPData(int s, const char *bufr, int n,
|
||||
const struct sockaddr * sendername, unsigned short port);
|
||||
const struct sockaddr * sendername,
|
||||
unsigned short http_port, unsigned short https_port);
|
||||
#else
|
||||
void
|
||||
ProcessSSDPData(int s, const char *bufr, int n,
|
||||
const struct sockaddr * sendername,
|
||||
unsigned short http_port);
|
||||
#endif
|
||||
|
||||
int
|
||||
SendSSDPGoodbye(int * sockets, int n);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: miniupnpd.c,v 1.190 2014/03/24 10:49:44 nanard Exp $ */
|
||||
/* $Id: miniupnpd.c,v 1.199 2014/05/19 23:14:25 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2014 Thomas Bernard
|
||||
|
@ -39,7 +39,7 @@
|
|||
#include <sys/param.h>
|
||||
#if defined(sun)
|
||||
#include <kstat.h>
|
||||
#else
|
||||
#elif !defined(__linux__)
|
||||
/* for BSD's sysctl */
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
@ -77,7 +77,7 @@
|
|||
#ifdef USE_IFACEWATCHER
|
||||
#include "ifacewatcher.h"
|
||||
#endif
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
#ifdef ENABLE_UPNPPINHOLE
|
||||
#ifdef USE_NETFILTER
|
||||
void init_iptpinhole(void);
|
||||
#endif
|
||||
|
@ -113,9 +113,9 @@ volatile sig_atomic_t should_send_public_address_change_notif = 0;
|
|||
* setup the socket used to handle incoming HTTP connections. */
|
||||
static int
|
||||
#ifdef ENABLE_IPV6
|
||||
OpenAndConfHTTPSocket(unsigned short port, int ipv6)
|
||||
OpenAndConfHTTPSocket(unsigned short * port, int ipv6)
|
||||
#else
|
||||
OpenAndConfHTTPSocket(unsigned short port)
|
||||
OpenAndConfHTTPSocket(unsigned short * port)
|
||||
#endif
|
||||
{
|
||||
int s;
|
||||
|
@ -128,13 +128,24 @@ OpenAndConfHTTPSocket(unsigned short port)
|
|||
#endif
|
||||
socklen_t listenname_len;
|
||||
|
||||
if( (s = socket(
|
||||
s = socket(
|
||||
#ifdef ENABLE_IPV6
|
||||
ipv6 ? PF_INET6 : PF_INET,
|
||||
ipv6 ? PF_INET6 : PF_INET,
|
||||
#else
|
||||
PF_INET,
|
||||
PF_INET,
|
||||
#endif
|
||||
SOCK_STREAM, 0)) < 0)
|
||||
SOCK_STREAM, 0);
|
||||
#ifdef ENABLE_IPV6
|
||||
if(s < 0 && ipv6 && errno == EAFNOSUPPORT)
|
||||
{
|
||||
/* the system doesn't support IPV6 */
|
||||
syslog(LOG_WARNING, "socket(PF_INET6, ...) failed with EAFNOSUPPORT, disabling IPv6");
|
||||
SETFLAG(IPV6DISABLEDMASK);
|
||||
ipv6 = 0;
|
||||
s = socket(PF_INET, SOCK_STREAM, 0);
|
||||
}
|
||||
#endif
|
||||
if(s < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "socket(http): %m");
|
||||
return -1;
|
||||
|
@ -163,20 +174,20 @@ OpenAndConfHTTPSocket(unsigned short port)
|
|||
{
|
||||
memset(&listenname6, 0, sizeof(struct sockaddr_in6));
|
||||
listenname6.sin6_family = AF_INET6;
|
||||
listenname6.sin6_port = htons(port);
|
||||
listenname6.sin6_addr = in6addr_any;
|
||||
listenname6.sin6_port = htons(*port);
|
||||
listenname6.sin6_addr = ipv6_bind_addr;
|
||||
listenname_len = sizeof(struct sockaddr_in6);
|
||||
} else {
|
||||
memset(&listenname4, 0, sizeof(struct sockaddr_in));
|
||||
listenname4.sin_family = AF_INET;
|
||||
listenname4.sin_port = htons(port);
|
||||
listenname4.sin_port = htons(*port);
|
||||
listenname4.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
listenname_len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
#else
|
||||
memset(&listenname, 0, sizeof(struct sockaddr_in));
|
||||
listenname.sin_family = AF_INET;
|
||||
listenname.sin_port = htons(port);
|
||||
listenname.sin_port = htons(*port);
|
||||
listenname.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
listenname_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
@ -201,11 +212,34 @@ OpenAndConfHTTPSocket(unsigned short port)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if(*port == 0) {
|
||||
#ifdef ENABLE_IPV6
|
||||
if(ipv6) {
|
||||
struct sockaddr_in6 sockinfo;
|
||||
socklen_t len = sizeof(struct sockaddr_in6);
|
||||
if (getsockname(s, (struct sockaddr *)&sockinfo, &len) < 0) {
|
||||
syslog(LOG_ERR, "getsockname(): %m");
|
||||
} else {
|
||||
*port = ntohs(sockinfo.sin6_port);
|
||||
}
|
||||
} else {
|
||||
#endif /* ENABLE_IPV6 */
|
||||
struct sockaddr_in sockinfo;
|
||||
socklen_t len = sizeof(struct sockaddr_in);
|
||||
if (getsockname(s, (struct sockaddr *)&sockinfo, &len) < 0) {
|
||||
syslog(LOG_ERR, "getsockname(): %m");
|
||||
} else {
|
||||
*port = ntohs(sockinfo.sin_port);
|
||||
}
|
||||
#ifdef ENABLE_IPV6
|
||||
}
|
||||
#endif /* ENABLE_IPV6 */
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static struct upnphttp *
|
||||
ProcessIncomingHTTP(int shttpl)
|
||||
ProcessIncomingHTTP(int shttpl, const char * protocol)
|
||||
{
|
||||
int shttp;
|
||||
socklen_t clientnamelen;
|
||||
|
@ -229,13 +263,13 @@ ProcessIncomingHTTP(int shttpl)
|
|||
char addr_str[64];
|
||||
|
||||
sockaddr_to_string((struct sockaddr *)&clientname, addr_str, sizeof(addr_str));
|
||||
syslog(LOG_INFO, "HTTP connection from %s", addr_str);
|
||||
syslog(LOG_INFO, "%s connection from %s", protocol, addr_str);
|
||||
if(get_lan_for_peer((struct sockaddr *)&clientname) == NULL)
|
||||
{
|
||||
/* The peer is not a LAN ! */
|
||||
syslog(LOG_WARNING,
|
||||
"HTTP peer %s is not from a LAN, closing the connection",
|
||||
addr_str);
|
||||
"%s peer %s is not from a LAN, closing the connection",
|
||||
protocol, addr_str);
|
||||
close(shttp);
|
||||
}
|
||||
else
|
||||
|
@ -632,6 +666,9 @@ struct runtime_vars {
|
|||
/* LAN IP addresses for SSDP traffic and HTTP */
|
||||
/* moved to global vars */
|
||||
int port; /* HTTP Port */
|
||||
#ifdef ENABLE_HTTPS
|
||||
int https_port; /* HTTPS Port */
|
||||
#endif
|
||||
int notify_interval; /* seconds between SSDP announces */
|
||||
/* unused rules cleaning related variables : */
|
||||
int clean_ruleset_threshold; /* threshold for removing unused rules */
|
||||
|
@ -670,6 +707,7 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str)
|
|||
if(getifaddr(lan_addr->ifname, lan_addr->str, sizeof(lan_addr->str),
|
||||
&lan_addr->addr, &lan_addr->mask) < 0)
|
||||
goto parselan_error;
|
||||
/*printf("%s => %s\n", lan_addr->ifname, lan_addr->str);*/
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -741,7 +779,10 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str)
|
|||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Warning: please specify LAN network interface by name instead of IPv4 address\n");
|
||||
fprintf(stderr,
|
||||
"Error: please specify LAN network interface by name instead of IPv4 address : %s\n",
|
||||
str);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
@ -830,9 +871,15 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
|||
|
||||
/* set initial values */
|
||||
SETFLAG(ENABLEUPNPMASK); /* UPnP is enabled by default */
|
||||
#ifdef ENABLE_IPV6
|
||||
ipv6_bind_addr = in6addr_any;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
LIST_INIT(&lan_addrs);
|
||||
v->port = -1;
|
||||
#ifdef ENABLE_HTTPS
|
||||
v->https_port = -1;
|
||||
#endif
|
||||
v->notify_interval = 30; /* seconds between SSDP announces */
|
||||
v->clean_ruleset_threshold = 20;
|
||||
v->clean_ruleset_interval = 0; /* interval between ruleset check. 0=disabled */
|
||||
|
@ -866,15 +913,32 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
|||
}
|
||||
if(parselanaddr(lan_addr, ary_options[i].value) != 0)
|
||||
{
|
||||
fprintf(stderr, "can't parse \"%s\" as valid lan address\n", ary_options[i].value);
|
||||
fprintf(stderr, "can't parse \"%s\" as a valid "
|
||||
#ifndef ENABLE_IPV6
|
||||
"LAN address or "
|
||||
#endif
|
||||
"interface name\n", ary_options[i].value);
|
||||
free(lan_addr);
|
||||
break;
|
||||
}
|
||||
LIST_INSERT_HEAD(&lan_addrs, lan_addr, list);
|
||||
break;
|
||||
#ifdef ENABLE_IPV6
|
||||
case UPNPIPV6_LISTENING_IP:
|
||||
if (inet_pton(AF_INET6, ary_options[i].value, &ipv6_bind_addr) < 1)
|
||||
{
|
||||
fprintf(stderr, "can't parse \"%s\" as valid IPv6 listening address", ary_options[i].value);
|
||||
}
|
||||
break;
|
||||
#endif /* ENABLE_IPV6 */
|
||||
case UPNPPORT:
|
||||
v->port = atoi(ary_options[i].value);
|
||||
break;
|
||||
#ifdef ENABLE_HTTPS
|
||||
case UPNPHTTPSPORT:
|
||||
v->https_port = atoi(ary_options[i].value);
|
||||
break;
|
||||
#endif
|
||||
case UPNPBITRATE_UP:
|
||||
upstream_bitrate = strtoul(ary_options[i].value, 0, 0);
|
||||
break;
|
||||
|
@ -984,6 +1048,10 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
|||
max_lifetime = 86400;
|
||||
}
|
||||
break;
|
||||
case UPNPPCPALLOWTHIRDPARTY:
|
||||
if(strcmp(ary_options[i].value, "yes") == 0)
|
||||
SETFLAG(PCP_ALLOWTHIRDPARTYMASK);
|
||||
break;
|
||||
#endif
|
||||
#ifdef PF_ENABLE_FILTER_RULES
|
||||
case UPNPQUICKRULES:
|
||||
|
@ -1126,6 +1194,16 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
|||
if(i+1 < argc)
|
||||
v->port = atoi(argv[++i]);
|
||||
else
|
||||
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
|
||||
break;
|
||||
#ifdef ENABLE_HTTPS
|
||||
case 'H':
|
||||
if(i+1 < argc)
|
||||
v->https_port = atoi(argv[++i]);
|
||||
else
|
||||
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENABLE_NFQUEUE
|
||||
case 'Q':
|
||||
if(i+1<argc)
|
||||
|
@ -1148,8 +1226,6 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
|||
}
|
||||
break;
|
||||
#endif
|
||||
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
|
||||
break;
|
||||
case 'P':
|
||||
if(i+1 < argc)
|
||||
pidfilename = argv[++i];
|
||||
|
@ -1187,7 +1263,11 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
|||
}
|
||||
if(parselanaddr(lan_addr, argv[i]) != 0)
|
||||
{
|
||||
fprintf(stderr, "can't parse \"%s\" as valid lan address\n", argv[i]);
|
||||
fprintf(stderr, "can't parse \"%s\" as a valid "
|
||||
#ifndef ENABLE_IPV6
|
||||
"LAN address or "
|
||||
#endif
|
||||
"interface name\n", argv[i]);
|
||||
free(lan_addr);
|
||||
break;
|
||||
}
|
||||
|
@ -1222,7 +1302,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
|||
}
|
||||
if(parselanaddr(lan_addr, val) != 0)
|
||||
{
|
||||
fprintf(stderr, "can't parse \"%s\" as valid lan address\n", val);
|
||||
fprintf(stderr, "can't parse \"%s\" as a valid LAN address or interface name\n", val);
|
||||
free(lan_addr);
|
||||
free(val);
|
||||
break;
|
||||
|
@ -1358,7 +1438,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
|||
syslog(LOG_ERR, "Failed to init redirection engine. EXITING");
|
||||
return 1;
|
||||
}
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
#ifdef ENABLE_UPNPPINHOLE
|
||||
#ifdef USE_NETFILTER
|
||||
init_iptpinhole();
|
||||
#endif
|
||||
|
@ -1385,6 +1465,9 @@ print_usage:
|
|||
"\t\t[-a listening_ip]"
|
||||
#else
|
||||
"\t\t[-a listening_ip ext_ip]"
|
||||
#endif
|
||||
#ifdef ENABLE_HTTPS
|
||||
" [-H https_port]"
|
||||
#endif
|
||||
" [-p port] [-d]"
|
||||
#if defined(USE_PF) || defined(USE_IPF)
|
||||
|
@ -1453,6 +1536,12 @@ main(int argc, char * * argv)
|
|||
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
||||
int shttpl_v4 = -1; /* socket for HTTP (ipv4 only) */
|
||||
#endif
|
||||
#ifdef ENABLE_HTTPS
|
||||
int shttpsl = -1; /* socket for HTTPS */
|
||||
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
||||
int shttpsl_v4 = -1; /* socket for HTTPS (ipv4 only) */
|
||||
#endif
|
||||
#endif /* ENABLE_HTTPS */
|
||||
int sudp = -1; /* IP v4 socket for receiving SSDP */
|
||||
#ifdef ENABLE_IPV6
|
||||
int sudpv6 = -1; /* IP v6 socket for receiving SSDP */
|
||||
|
@ -1490,12 +1579,16 @@ main(int argc, char * * argv)
|
|||
struct rule_state * rule_list = 0;
|
||||
struct timeval checktime = {0, 0};
|
||||
struct lan_addr_s * lan_addr;
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
#ifdef ENABLE_UPNPPINHOLE
|
||||
unsigned int next_pinhole_ts;
|
||||
#endif
|
||||
|
||||
if(init(argc, argv, &v) != 0)
|
||||
return 1;
|
||||
#ifdef ENABLE_HTTPS
|
||||
if(init_ssl() < 0)
|
||||
return 1;
|
||||
#endif /* ENABLE_HTTPS */
|
||||
/* count lan addrs */
|
||||
addr_count = 0;
|
||||
for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
|
||||
|
@ -1545,36 +1638,56 @@ main(int argc, char * * argv)
|
|||
|
||||
if(GETFLAG(ENABLEUPNPMASK))
|
||||
{
|
||||
|
||||
unsigned short listen_port;
|
||||
listen_port = (v.port > 0) ? v.port : 0;
|
||||
/* open socket for HTTP connections. Listen on the 1st LAN address */
|
||||
#ifdef ENABLE_IPV6
|
||||
shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0, 1);
|
||||
shttpl = OpenAndConfHTTPSocket(&listen_port, 1);
|
||||
#else /* ENABLE_IPV6 */
|
||||
shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0);
|
||||
shttpl = OpenAndConfHTTPSocket(&listen_port);
|
||||
#endif /* ENABLE_IPV6 */
|
||||
if(shttpl < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");
|
||||
return 1;
|
||||
}
|
||||
if(v.port <= 0) {
|
||||
struct sockaddr_in sockinfo;
|
||||
socklen_t len = sizeof(struct sockaddr_in);
|
||||
if (getsockname(shttpl, (struct sockaddr *)&sockinfo, &len) < 0) {
|
||||
syslog(LOG_ERR, "getsockname(): %m");
|
||||
return 1;
|
||||
}
|
||||
v.port = ntohs(sockinfo.sin_port);
|
||||
}
|
||||
v.port = listen_port;
|
||||
syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);
|
||||
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
||||
shttpl_v4 = OpenAndConfHTTPSocket(v.port, 0);
|
||||
if(shttpl_v4 < 0)
|
||||
if(!GETFLAG(IPV6DISABLEDMASK))
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to open socket for HTTP on port %hu (IPv4). EXITING", v.port);
|
||||
shttpl_v4 = OpenAndConfHTTPSocket(&listen_port, 0);
|
||||
if(shttpl_v4 < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to open socket for HTTP on port %hu (IPv4). EXITING", v.port);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif /* V6SOCKETS_ARE_V6ONLY */
|
||||
#ifdef ENABLE_HTTPS
|
||||
/* https */
|
||||
listen_port = (v.https_port > 0) ? v.https_port : 0;
|
||||
#ifdef ENABLE_IPV6
|
||||
shttpsl = OpenAndConfHTTPSocket(&listen_port, 1);
|
||||
#else /* ENABLE_IPV6 */
|
||||
shttpsl = OpenAndConfHTTPSocket(&listen_port);
|
||||
#endif /* ENABLE_IPV6 */
|
||||
if(shttpl < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to open socket for HTTPS. EXITING");
|
||||
return 1;
|
||||
}
|
||||
v.https_port = listen_port;
|
||||
syslog(LOG_NOTICE, "HTTPS listening on port %d", v.https_port);
|
||||
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
||||
shttpsl_v4 = OpenAndConfHTTPSocket(&listen_port, 0);
|
||||
if(shttpsl_v4 < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to open socket for HTTPS on port %hu (IPv4). EXITING", v.https_port);
|
||||
return 1;
|
||||
}
|
||||
#endif /* V6SOCKETS_ARE_V6ONLY */
|
||||
#endif /* ENABLE_HTTPS */
|
||||
#ifdef ENABLE_IPV6
|
||||
if(find_ipv6_addr(NULL, ipv6_addr_for_http_with_brackets, sizeof(ipv6_addr_for_http_with_brackets)) > 0) {
|
||||
syslog(LOG_NOTICE, "HTTP IPv6 address given to control points : %s",
|
||||
|
@ -1712,6 +1825,9 @@ main(int argc, char * * argv)
|
|||
if (GETFLAG(ENABLEUPNPMASK))
|
||||
SendSSDPNotifies2(snotify,
|
||||
(unsigned short)v.port,
|
||||
#ifdef ENABLE_HTTPS
|
||||
(unsigned short)v.https_port,
|
||||
#endif
|
||||
v.notify_interval << 1);
|
||||
memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval));
|
||||
timeout.tv_sec = v.notify_interval;
|
||||
|
@ -1764,7 +1880,7 @@ main(int argc, char * * argv)
|
|||
syslog(LOG_DEBUG, "setting timeout to %u sec",
|
||||
(unsigned)timeout.tv_sec);
|
||||
}
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
#ifdef ENABLE_UPNPPINHOLE
|
||||
/* Clean up expired IPv6 PinHoles */
|
||||
next_pinhole_ts = 0;
|
||||
upnp_clean_expired_pinholes(&next_pinhole_ts);
|
||||
|
@ -1773,7 +1889,7 @@ main(int argc, char * * argv)
|
|||
timeout.tv_sec = next_pinhole_ts - timeofday.tv_sec;
|
||||
timeout.tv_usec = 0;
|
||||
}
|
||||
#endif
|
||||
#endif /* ENABLE_UPNPPINHOLE */
|
||||
|
||||
/* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
|
||||
FD_ZERO(&readset);
|
||||
|
@ -1803,6 +1919,20 @@ main(int argc, char * * argv)
|
|||
max_fd = MAX( max_fd, shttpl_v4);
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_HTTPS
|
||||
if (shttpsl >= 0)
|
||||
{
|
||||
FD_SET(shttpsl, &readset);
|
||||
max_fd = MAX( max_fd, shttpsl);
|
||||
}
|
||||
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
||||
if (shttpsl_v4 >= 0)
|
||||
{
|
||||
FD_SET(shttpsl_v4, &readset);
|
||||
max_fd = MAX( max_fd, shttpsl_v4);
|
||||
}
|
||||
#endif
|
||||
#endif /* ENABLE_HTTPS */
|
||||
#ifdef ENABLE_IPV6
|
||||
if (sudpv6 >= 0)
|
||||
{
|
||||
|
@ -1999,19 +2129,50 @@ main(int argc, char * * argv)
|
|||
len = ReceiveNATPMPOrPCPPacket(snatpmp[i],
|
||||
(struct sockaddr *)&senderaddr,
|
||||
&senderaddrlen,
|
||||
NULL,
|
||||
msg_buff, sizeof(msg_buff));
|
||||
if (len < 1)
|
||||
continue;
|
||||
#ifdef ENABLE_PCP
|
||||
if (msg_buff[0]==0) { /* version equals to 0 -> means NAT-PMP */
|
||||
/* Check if the packet is coming from a LAN to enforce RFC6886 :
|
||||
* The NAT gateway MUST NOT accept mapping requests destined to the NAT
|
||||
* gateway's external IP address or received on its external network
|
||||
* interface. Only packets received on the internal interface(s) with a
|
||||
* destination address matching the internal address(es) of the NAT
|
||||
* gateway should be allowed. */
|
||||
/* TODO : move to ProcessIncomingNATPMPPacket() ? */
|
||||
lan_addr = get_lan_for_peer((struct sockaddr *)&senderaddr);
|
||||
if(lan_addr == NULL) {
|
||||
char sender_str[64];
|
||||
sockaddr_to_string((struct sockaddr *)&senderaddr, sender_str, sizeof(sender_str));
|
||||
syslog(LOG_WARNING, "NAT-PMP packet sender %s not from a LAN, ignoring",
|
||||
sender_str);
|
||||
continue;
|
||||
}
|
||||
ProcessIncomingNATPMPPacket(snatpmp[i], msg_buff, len,
|
||||
&senderaddr);
|
||||
} else { /* everything else can be PCP */
|
||||
ProcessIncomingPCPPacket(snatpmp[i], msg_buff, len,
|
||||
(struct sockaddr *)&senderaddr);
|
||||
(struct sockaddr *)&senderaddr, NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Check if the packet is coming from a LAN to enforce RFC6886 :
|
||||
* The NAT gateway MUST NOT accept mapping requests destined to the NAT
|
||||
* gateway's external IP address or received on its external network
|
||||
* interface. Only packets received on the internal interface(s) with a
|
||||
* destination address matching the internal address(es) of the NAT
|
||||
* gateway should be allowed. */
|
||||
/* TODO : move to ProcessIncomingNATPMPPacket() ? */
|
||||
lan_addr = get_lan_for_peer((struct sockaddr *)&senderaddr);
|
||||
if(lan_addr == NULL) {
|
||||
char sender_str[64];
|
||||
sockaddr_to_string((struct sockaddr *)&senderaddr, sender_str, sizeof(sender_str));
|
||||
syslog(LOG_WARNING, "NAT-PMP packet sender %s not from a LAN, ignoring",
|
||||
sender_str);
|
||||
continue;
|
||||
}
|
||||
ProcessIncomingNATPMPPacket(snatpmp[i], msg_buff, len, &senderaddr);
|
||||
#endif
|
||||
}
|
||||
|
@ -2024,29 +2185,40 @@ main(int argc, char * * argv)
|
|||
unsigned char msg_buff[PCP_MAX_LEN];
|
||||
struct sockaddr_in6 senderaddr;
|
||||
socklen_t senderaddrlen;
|
||||
struct sockaddr_in6 receiveraddr;
|
||||
int len;
|
||||
memset(msg_buff, 0, PCP_MAX_LEN);
|
||||
senderaddrlen = sizeof(senderaddr);
|
||||
len = ReceiveNATPMPOrPCPPacket(spcp_v6,
|
||||
(struct sockaddr *)&senderaddr,
|
||||
&senderaddrlen,
|
||||
&receiveraddr,
|
||||
msg_buff, sizeof(msg_buff));
|
||||
if(len >= 1)
|
||||
ProcessIncomingPCPPacket(spcp_v6, msg_buff, len,
|
||||
(struct sockaddr *)&senderaddr);
|
||||
(struct sockaddr *)&senderaddr,
|
||||
&receiveraddr);
|
||||
}
|
||||
#endif
|
||||
/* process SSDP packets */
|
||||
if(sudp >= 0 && FD_ISSET(sudp, &readset))
|
||||
{
|
||||
/*syslog(LOG_INFO, "Received UDP Packet");*/
|
||||
#ifdef ENABLE_HTTPS
|
||||
ProcessSSDPRequest(sudp, (unsigned short)v.port, (unsigned short)v.https_port);
|
||||
#else
|
||||
ProcessSSDPRequest(sudp, (unsigned short)v.port);
|
||||
#endif
|
||||
}
|
||||
#ifdef ENABLE_IPV6
|
||||
if(sudpv6 >= 0 && FD_ISSET(sudpv6, &readset))
|
||||
{
|
||||
syslog(LOG_INFO, "Received UDP Packet (IPv6)");
|
||||
#ifdef ENABLE_HTTPS
|
||||
ProcessSSDPRequest(sudpv6, (unsigned short)v.port, (unsigned short)v.https_port);
|
||||
#else
|
||||
ProcessSSDPRequest(sudpv6, (unsigned short)v.port);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_IFACEWATCHER
|
||||
|
@ -2072,7 +2244,7 @@ main(int argc, char * * argv)
|
|||
if(shttpl >= 0 && FD_ISSET(shttpl, &readset))
|
||||
{
|
||||
struct upnphttp * tmp;
|
||||
tmp = ProcessIncomingHTTP(shttpl);
|
||||
tmp = ProcessIncomingHTTP(shttpl, "HTTP");
|
||||
if(tmp)
|
||||
{
|
||||
LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
|
||||
|
@ -2082,13 +2254,37 @@ main(int argc, char * * argv)
|
|||
if(shttpl_v4 >= 0 && FD_ISSET(shttpl_v4, &readset))
|
||||
{
|
||||
struct upnphttp * tmp;
|
||||
tmp = ProcessIncomingHTTP(shttpl_v4);
|
||||
tmp = ProcessIncomingHTTP(shttpl_v4, "HTTP");
|
||||
if(tmp)
|
||||
{
|
||||
LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_HTTPS
|
||||
if(shttpsl >= 0 && FD_ISSET(shttpsl, &readset))
|
||||
{
|
||||
struct upnphttp * tmp;
|
||||
tmp = ProcessIncomingHTTP(shttpsl, "HTTPS");
|
||||
if(tmp)
|
||||
{
|
||||
InitSSL_upnphttp(tmp);
|
||||
LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
|
||||
}
|
||||
}
|
||||
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
||||
if(shttpsl_v4 >= 0 && FD_ISSET(shttpsl_v4, &readset))
|
||||
{
|
||||
struct upnphttp * tmp;
|
||||
tmp = ProcessIncomingHTTP(shttpsl_v4, "HTTPS");
|
||||
if(tmp)
|
||||
{
|
||||
InitSSL_upnphttp(tmp);
|
||||
LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* ENABLE_HTTPS */
|
||||
#ifdef ENABLE_NFQUEUE
|
||||
/* process NFQ packets */
|
||||
if(nfqh >= 0 && FD_ISSET(nfqh, &readset))
|
||||
|
@ -2199,6 +2395,9 @@ shutdown:
|
|||
free(lan_addr);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_HTTPS
|
||||
free_ssl();
|
||||
#endif
|
||||
#ifdef ENABLE_NATPMP
|
||||
free(snatpmp);
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# WAN network interface
|
||||
ext_ifname=eth1
|
||||
#ext_ifname=eth1
|
||||
#ext_ifname=xl1
|
||||
# if the WAN interface has several IP addresses, you
|
||||
# can specify the one to use below
|
||||
|
@ -15,10 +15,16 @@ ext_ifname=eth1
|
|||
# address associated with the subnet follows. for example :
|
||||
# listening_ip=192.168.0.1/24 88.22.44.13
|
||||
#listening_ip=192.168.0.1/24
|
||||
listening_ip=192.168.10.109/24
|
||||
#listening_ip=10.5.0.0/16
|
||||
#listening_ip=eth0
|
||||
# CAUTION: mixing up WAN and LAN interfaces may introduce security risks!
|
||||
# be sure to assign the correct interfaces to LAN and WAN and consider
|
||||
# implementing UPnP permission rules at the bottom of this configuration file
|
||||
|
||||
# port for HTTP (descriptions and SOAP) traffic. set 0 for autoselect.
|
||||
port=0
|
||||
#http_port=0
|
||||
# port for HTTPS. set to 0 for autoselect (default)
|
||||
#https_port=0
|
||||
|
||||
# path to the unix socket used to communicate with MiniSSDPd
|
||||
# If running, MiniSSDPd will manage M-SEARCH answering.
|
||||
|
@ -26,15 +32,16 @@ port=0
|
|||
#minissdpdsocket=/var/run/minissdpd.sock
|
||||
|
||||
# enable NAT-PMP support (default is no)
|
||||
enable_natpmp=yes
|
||||
#enable_natpmp=yes
|
||||
|
||||
# enable UPNP support (default is yes)
|
||||
enable_upnp=yes
|
||||
#enable_upnp=no
|
||||
|
||||
# PCP :
|
||||
# configure minimal and maximal lifetime of the port mapping in seconds
|
||||
# 120s and 86400s (24h) are suggested values from PCP-base
|
||||
min_lifetime=120
|
||||
max_lifetime=86400
|
||||
#min_lifetime=120
|
||||
#max_lifetime=86400
|
||||
|
||||
# chain names for netfilter (not used for pf or ipf).
|
||||
# default is MINIUPNPD for both
|
||||
|
@ -66,8 +73,9 @@ max_lifetime=86400
|
|||
#model_url=http://miniupnp.free.fr/
|
||||
|
||||
# bitrates reported by daemon in bits per second
|
||||
bitrate_up=1000000
|
||||
bitrate_down=10000000
|
||||
# by default miniupnpd tries to get WAN interface speed
|
||||
#bitrate_up=1000000
|
||||
#bitrate_down=10000000
|
||||
|
||||
# "secure" mode : when enabled, UPnP client are allowed to add mappings only
|
||||
# to their IP.
|
||||
|
@ -114,12 +122,12 @@ clean_ruleset_interval=600
|
|||
#quickrules=no
|
||||
|
||||
# uuid : generate your own with "make genuuid"
|
||||
uuid=3d3cec3a-8cf0-11e0-98ee-001a6bd2d07b
|
||||
uuid=00000000-0000-0000-0000-000000000000
|
||||
|
||||
# serial and model number the daemon will report to clients
|
||||
# in its XML description
|
||||
serial=12345678
|
||||
model_number=1
|
||||
#serial=12345678
|
||||
#model_number=1
|
||||
|
||||
# UPnP permission rules
|
||||
# (allow|deny) (external port range) ip/mask (internal port range)
|
||||
|
@ -128,6 +136,11 @@ model_number=1
|
|||
# ip/mask format must be nn.nn.nn.nn/nn
|
||||
# it is advised to only allow redirection of port above 1024
|
||||
# and to finish the rule set with "deny 0-65535 0.0.0.0/0 0-65535"
|
||||
# The following default ruleset allows specific LAN side IP addresses
|
||||
# to request only ephemeral ports. it is recommended that users
|
||||
# modify the IP ranges to match their own internal networks, and
|
||||
# also consider implementing network-specific restrictions
|
||||
# CAUTION: failure to enforce any rules may permit insecure requests to be made!
|
||||
allow 1024-65535 192.168.0.0/24 1024-65535
|
||||
allow 1024-65535 192.168.1.0/24 1024-65535
|
||||
allow 1024-65535 192.168.0.0/23 22
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: natpmp.c,v 1.43 2014/03/24 10:49:45 nanard Exp $ */
|
||||
/* $Id: natpmp.c,v 1.47 2014/05/19 12:51:52 nanard Exp $ */
|
||||
/* MiniUPnP project
|
||||
* (c) 2007-2014 Thomas Bernard
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
|
@ -14,6 +14,7 @@
|
|||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "macros.h"
|
||||
#include "config.h"
|
||||
|
@ -28,6 +29,35 @@
|
|||
|
||||
#ifdef ENABLE_NATPMP
|
||||
|
||||
#define INLINE static inline
|
||||
/* theses macros are designed to read/write unsigned short/long int
|
||||
* from an unsigned char array in network order (big endian).
|
||||
* Avoid pointer casting, so avoid accessing unaligned memory, which
|
||||
* can crash with some cpu's */
|
||||
INLINE uint32_t readnu32(const uint8_t * p)
|
||||
{
|
||||
return (p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]);
|
||||
}
|
||||
#define READNU32(p) readnu32(p)
|
||||
INLINE uint16_t readnu16(const uint8_t * p)
|
||||
{
|
||||
return (p[0] << 8 | p[1]);
|
||||
}
|
||||
#define READNU16(p) readnu16(p)
|
||||
INLINE void writenu32(uint8_t * p, uint32_t n)
|
||||
{
|
||||
p[0] = (n & 0xff000000) >> 24;
|
||||
p[1] = (n & 0xff0000) >> 16;
|
||||
p[2] = (n & 0xff00) >> 8;
|
||||
p[3] = n & 0xff;
|
||||
}
|
||||
#define WRITENU32(p, n) writenu32(p, n)
|
||||
INLINE void writenu16(uint8_t * p, uint16_t n)
|
||||
{
|
||||
p[0] = (n & 0xff00) >> 8;
|
||||
p[1] = n & 0xff;
|
||||
}
|
||||
#define WRITENU16(p, n) writenu16(p, n)
|
||||
|
||||
int OpenAndConfNATPMPSocket(in_addr_t addr)
|
||||
{
|
||||
|
@ -132,9 +162,63 @@ static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr
|
|||
*/
|
||||
int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr * senderaddr,
|
||||
socklen_t * senderaddrlen,
|
||||
struct sockaddr_in6 * receiveraddr,
|
||||
unsigned char * msg_buff, size_t msg_buff_size)
|
||||
{
|
||||
#if IPV6_PKTINFO
|
||||
struct iovec iov;
|
||||
uint8_t c[1000];
|
||||
struct msghdr msg;
|
||||
int n;
|
||||
struct cmsghdr *h;
|
||||
|
||||
iov.iov_base = msg_buff;
|
||||
iov.iov_len = msg_buff_size;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_name = senderaddr;
|
||||
msg.msg_namelen = *senderaddrlen;
|
||||
msg.msg_control = c;
|
||||
msg.msg_controllen = sizeof(c);
|
||||
|
||||
n = recvmsg(s, &msg, 0);
|
||||
if(n < 0) {
|
||||
/* EAGAIN, EWOULDBLOCK and EINTR : silently ignore (retry next time)
|
||||
* other errors : log to LOG_ERR */
|
||||
if(errno != EAGAIN &&
|
||||
errno != EWOULDBLOCK &&
|
||||
errno != EINTR) {
|
||||
syslog(LOG_ERR, "recvmsg(natpmp): %m");
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
if(receiveraddr) {
|
||||
memset(receiveraddr, 0, sizeof(struct sockaddr_in6));
|
||||
}
|
||||
if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC)) {
|
||||
syslog(LOG_WARNING, "%s: truncated message",
|
||||
"ReceiveNATPMPOrPCPPacket");
|
||||
}
|
||||
for(h = CMSG_FIRSTHDR(&msg); h;
|
||||
h = CMSG_NXTHDR(&msg, h)) {
|
||||
if(h->cmsg_level == IPPROTO_IPV6 && h->cmsg_type == IPV6_PKTINFO) {
|
||||
char tmp[INET6_ADDRSTRLEN];
|
||||
struct in6_pktinfo *ipi6 = (struct in6_pktinfo *)CMSG_DATA(h);
|
||||
syslog(LOG_DEBUG, "%s: packet destination: %s scope_id=%u",
|
||||
"ReceiveNATPMPOrPCPPacket",
|
||||
inet_ntop(AF_INET6, &ipi6->ipi6_addr, tmp, sizeof(tmp)),
|
||||
ipi6->ipi6_ifindex);
|
||||
if(receiveraddr) {
|
||||
receiveraddr->sin6_addr = ipi6->ipi6_addr;
|
||||
receiveraddr->sin6_scope_id = ipi6->ipi6_ifindex;
|
||||
receiveraddr->sin6_family = AF_INET6;
|
||||
receiveraddr->sin6_port = htons(NATPMP_PORT);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
int n;
|
||||
|
||||
n = recvfrom(s, msg_buff, msg_buff_size, 0,
|
||||
|
@ -150,6 +234,7 @@ int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr * senderaddr,
|
|||
}
|
||||
return n;
|
||||
}
|
||||
#endif
|
||||
|
||||
return n;
|
||||
}
|
||||
|
@ -189,7 +274,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
|
|||
/* setting response TIME STAMP :
|
||||
* time elapsed since its port mapping table was initialized on
|
||||
* startup or reset for any other reason */
|
||||
*((uint32_t *)(resp+4)) = htonl(time(NULL) - startup_time);
|
||||
WRITENU32(resp+4, time(NULL) - startup_time);
|
||||
if(req[0] > 0) {
|
||||
/* invalid version */
|
||||
syslog(LOG_WARNING, "unsupported NAT-PMP version : %u",
|
||||
|
@ -213,68 +298,65 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
|
|||
unsigned short iport_old;
|
||||
unsigned int timestamp;
|
||||
|
||||
iport = ntohs(*((uint16_t *)(req+4)));
|
||||
eport = ntohs(*((uint16_t *)(req+6)));
|
||||
lifetime = ntohl(*((uint32_t *)(req+8)));
|
||||
iport = READNU16(req+4);
|
||||
eport = READNU16(req+6);
|
||||
lifetime = READNU32(req+8);
|
||||
proto = (req[1]==1)?IPPROTO_UDP:IPPROTO_TCP;
|
||||
syslog(LOG_INFO, "NAT-PMP port mapping request : "
|
||||
"%hu->%s:%hu %s lifetime=%us",
|
||||
eport, senderaddrstr, iport,
|
||||
(req[1]==1)?"udp":"tcp", lifetime);
|
||||
if(eport==0)
|
||||
eport = iport;
|
||||
/* TODO: accept port mapping if iport ok but eport not ok
|
||||
* (and set eport correctly) */
|
||||
if(lifetime == 0) {
|
||||
/* remove the mapping */
|
||||
if(iport == 0) {
|
||||
/* remove all the mappings for this client */
|
||||
int index = 0;
|
||||
unsigned short eport2, iport2;
|
||||
char iaddr2[16];
|
||||
int proto2;
|
||||
char desc[64];
|
||||
while(get_redirect_rule_by_index(index, 0,
|
||||
&eport2, iaddr2, sizeof(iaddr2),
|
||||
&iport2, &proto2,
|
||||
desc, sizeof(desc),
|
||||
0, 0, ×tamp, 0, 0) >= 0) {
|
||||
syslog(LOG_DEBUG, "%d %d %hu->'%s':%hu '%s'",
|
||||
index, proto2, eport2, iaddr2, iport2, desc);
|
||||
if(0 == strcmp(iaddr2, senderaddrstr)
|
||||
&& 0 == memcmp(desc, "NAT-PMP", 7)) {
|
||||
/* RFC6886 :
|
||||
* A client MAY also send an explicit packet to request deletion of a
|
||||
* mapping that is no longer needed. A client requests explicit
|
||||
* deletion of a mapping by sending a message to the NAT gateway
|
||||
* requesting the mapping, with the Requested Lifetime in Seconds set to
|
||||
* zero. The Suggested External Port MUST be set to zero by the client
|
||||
* on sending, and MUST be ignored by the gateway on reception. */
|
||||
int index = 0;
|
||||
unsigned short eport2, iport2;
|
||||
char iaddr2[16];
|
||||
int proto2;
|
||||
char desc[64];
|
||||
eport = 0; /* to indicate correct removing of port mapping */
|
||||
while(get_redirect_rule_by_index(index, 0,
|
||||
&eport2, iaddr2, sizeof(iaddr2),
|
||||
&iport2, &proto2,
|
||||
desc, sizeof(desc),
|
||||
0, 0, ×tamp, 0, 0) >= 0) {
|
||||
syslog(LOG_DEBUG, "%d %d %hu->'%s':%hu '%s'",
|
||||
index, proto2, eport2, iaddr2, iport2, desc);
|
||||
if(0 == strcmp(iaddr2, senderaddrstr)
|
||||
&& 0 == memcmp(desc, "NAT-PMP", 7)) {
|
||||
/* (iport == 0) => remove all the mappings for this client */
|
||||
if((iport == 0) || ((iport == iport2) && (proto == proto2))) {
|
||||
r = _upnp_delete_redir(eport2, proto2);
|
||||
/* TODO : check return value */
|
||||
if(r<0) {
|
||||
syslog(LOG_ERR, "failed to remove port mapping");
|
||||
index++;
|
||||
if(r < 0) {
|
||||
syslog(LOG_ERR, "Failed to remove NAT-PMP mapping eport %hu, protocol %s",
|
||||
eport2, (proto2==IPPROTO_TCP)?"TCP":"UDP");
|
||||
resp[3] = 2; /* Not Authorized/Refused */
|
||||
break;
|
||||
} else {
|
||||
syslog(LOG_INFO, "NAT-PMP %s port %hu mapping removed",
|
||||
proto2==IPPROTO_TCP?"TCP":"UDP", eport2);
|
||||
index--;
|
||||
}
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* To improve the interworking between nat-pmp and
|
||||
* UPnP, we should check that we remove only NAT-PMP
|
||||
* mappings */
|
||||
r = _upnp_delete_redir(eport, proto);
|
||||
/*syslog(LOG_DEBUG, "%hu %d r=%d", eport, proto, r);*/
|
||||
if(r<0) {
|
||||
syslog(LOG_ERR, "Failed to remove NAT-PMP mapping eport %hu, protocol %s",
|
||||
eport, (proto==IPPROTO_TCP)?"TCP":"UDP");
|
||||
resp[3] = 2; /* Not Authorized/Refused */
|
||||
}
|
||||
index++;
|
||||
}
|
||||
eport = 0; /* to indicate correct removing of port mapping */
|
||||
} else if(iport==0) {
|
||||
resp[3] = 2; /* Not Authorized/Refused */
|
||||
} else { /* iport > 0 && lifetime > 0 */
|
||||
unsigned short eport_first = 0;
|
||||
int any_eport_allowed = 0;
|
||||
char desc[64];
|
||||
if(eport==0) /* if no suggested external port, use same a internal port */
|
||||
eport = iport;
|
||||
while(resp[3] == 0) {
|
||||
if(eport_first == 0) { /* first time in loop */
|
||||
eport_first = eport;
|
||||
|
@ -347,9 +429,9 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
|
|||
break;
|
||||
}
|
||||
}
|
||||
*((uint16_t *)(resp+8)) = htons(iport); /* private port */
|
||||
*((uint16_t *)(resp+10)) = htons(eport); /* public port */
|
||||
*((uint32_t *)(resp+12)) = htonl(lifetime); /* Port Mapping lifetime */
|
||||
WRITENU16(resp+8, iport); /* private port */
|
||||
WRITENU16(resp+10, eport); /* public port */
|
||||
WRITENU32(resp+12, lifetime); /* Port Mapping lifetime */
|
||||
}
|
||||
resplen = 16;
|
||||
break;
|
||||
|
@ -381,7 +463,7 @@ void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets)
|
|||
/* seconds since "start of epoch" :
|
||||
* time elapsed since the port mapping table was initialized on
|
||||
* startup or reset for any other reason */
|
||||
*((uint32_t *)(notif+4)) = htonl(time(NULL) - startup_time);
|
||||
WRITENU32(notif+4, time(NULL) - startup_time);
|
||||
#ifndef MULTIPLE_EXTERNAL_IP
|
||||
FillPublicAddressResponse(notif, 0);
|
||||
if(notif[3])
|
||||
|
|
|
@ -20,8 +20,10 @@
|
|||
|
||||
int OpenAndConfNATPMPSockets(int * sockets);
|
||||
|
||||
/* receiveraddr is only used with IPV6 sockets */
|
||||
int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr * senderaddr,
|
||||
socklen_t * senderaddrlen,
|
||||
struct sockaddr_in6 * receiveraddr,
|
||||
unsigned char * msg_buff, size_t msg_buff_size);
|
||||
|
||||
void ProcessIncomingNATPMPPacket(int s, unsigned char * msg_buff, int len,
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
#! /bin/sh
|
||||
# $Id: iptables_init.sh,v 1.5 2011/05/16 12:11:37 nanard Exp $
|
||||
IPTABLES=/sbin/iptables
|
||||
IPTABLES="`which iptables`" || exit 1
|
||||
IP="`which ip`" || exit 1
|
||||
|
||||
#change this parameters :
|
||||
EXTIF=eth0
|
||||
EXTIP="`LC_ALL=C /sbin/ifconfig $EXTIF | grep 'inet ' | awk '{print $2}' | sed -e 's/.*://'`"
|
||||
#EXTIF=eth0
|
||||
EXTIF="`LC_ALL=C $IP -4 route | grep 'default' | sed -e 's/.*dev[[:space:]]*//' -e 's/[[:space:]].*//'`" || exit 1
|
||||
EXTIP="`LC_ALL=C $IP -4 addr show $EXTIF | awk '/inet/ { print $2 }' | cut -d "/" -f 1`"
|
||||
|
||||
echo "External IP = $EXTIP"
|
||||
|
||||
#adding the MINIUPNPD chain for nat
|
||||
|
|
|
@ -3,11 +3,15 @@
|
|||
# Improved Miniupnpd iptables init script.
|
||||
# Checks for state of filter before doing anything..
|
||||
|
||||
EXTIF=eth0
|
||||
IPTABLES=/sbin/iptables
|
||||
EXTIP="`LC_ALL=C /sbin/ifconfig $EXTIF | grep 'inet ' | awk '{print $2}' | sed -e 's/.*://'`"
|
||||
NDIRTY="`LC_ALL=C /sbin/iptables -t nat -L -n | grep 'MINIUPNPD' | awk '{printf $1}'`"
|
||||
FDIRTY="`LC_ALL=C /sbin/iptables -t filter -L -n | grep 'MINIUPNPD' | awk '{printf $1}'`"
|
||||
IPTABLES="`which iptables`" || exit 1
|
||||
IP="`which ip`" || exit 1
|
||||
|
||||
#EXTIF=eth0
|
||||
EXTIF="`LC_ALL=C $IP -4 route | grep 'default' | sed -e 's/.*dev[[:space:]]*//' -e 's/[[:space:]].*//'`" || exit 1
|
||||
EXTIP="`LC_ALL=C $IP -4 addr show $EXTIF | awk '/inet/ { print $2 }' | cut -d "/" -f 1`"
|
||||
|
||||
NDIRTY="`LC_ALL=C $IPTABLES -t nat -L -n | awk '/MINIUPNPD/ {printf $1}'`"
|
||||
FDIRTY="`LC_ALL=C $IPTABLES -t filter -L -n | awk '/MINIUPNPD/ {printf $1}'`"
|
||||
echo "External IP = $EXTIP"
|
||||
|
||||
if [[ $NDIRTY = "MINIUPNPDChain" ]]; then
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#! /bin/sh
|
||||
# $Id: iptables_removeall.sh,v 1.5 2011/05/16 12:11:37 nanard Exp $
|
||||
IPTABLES=/sbin/iptables
|
||||
IPTABLES="`which iptables`" || exit 1
|
||||
IP="`which ip`" || exit 1
|
||||
|
||||
#change this parameters :
|
||||
EXTIF=eth0
|
||||
EXTIP="`LC_ALL=C /sbin/ifconfig $EXTIF | grep 'inet ' | awk '{print $2}' | sed -e 's/.*://'`"
|
||||
#EXTIF=eth0
|
||||
EXTIF="`LC_ALL=C $IP -4 route | grep 'default' | sed -e 's/.*dev[[:space:]]*//' -e 's/[[:space:]].*//'`" || exit 1
|
||||
EXTIP="`LC_ALL=C $IP -4 addr show $EXTIF | awk '/inet/ { print $2 }' | cut -d "/" -f 1`"
|
||||
|
||||
#removing the MINIUPNPD chain for nat
|
||||
$IPTABLES -t nat -F MINIUPNPD
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "iptpinhole.h"
|
||||
#include "../upnpglobalvars.h"
|
||||
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
#ifdef ENABLE_UPNPPINHOLE
|
||||
|
||||
#include <xtables.h>
|
||||
#include <libiptc/libip6tc.h>
|
||||
|
@ -40,6 +40,7 @@ struct pinhole_t {
|
|||
unsigned short dport;
|
||||
unsigned short uid;
|
||||
unsigned char proto;
|
||||
char desc[];
|
||||
};
|
||||
|
||||
void init_iptpinhole(void)
|
||||
|
@ -56,15 +57,16 @@ void shutdown_iptpinhole(void)
|
|||
static int
|
||||
add_to_pinhole_list(struct in6_addr * saddr, unsigned short sport,
|
||||
struct in6_addr * daddr, unsigned short dport,
|
||||
int proto, unsigned int timestamp)
|
||||
int proto, const char *desc, unsigned int timestamp)
|
||||
{
|
||||
struct pinhole_t * p;
|
||||
|
||||
p = calloc(1, sizeof(struct pinhole_t));
|
||||
p = calloc(1, sizeof(struct pinhole_t) + strlen(desc) + 1);
|
||||
if(!p) {
|
||||
syslog(LOG_ERR, "add_to_pinhole_list calloc() error");
|
||||
return -1;
|
||||
}
|
||||
strcpy(p->desc, desc);
|
||||
memcpy(&p->saddr, saddr, sizeof(struct in6_addr));
|
||||
p->sport = sport;
|
||||
memcpy(&p->daddr, daddr, sizeof(struct in6_addr));
|
||||
|
@ -195,7 +197,7 @@ ip6tables -t raw -I PREROUTING %d -p %s -i %s --sport %hu -d %s --dport %hu -j T
|
|||
int add_pinhole(const char * ifname,
|
||||
const char * rem_host, unsigned short rem_port,
|
||||
const char * int_client, unsigned short int_port,
|
||||
int proto, unsigned int timestamp)
|
||||
int proto, const char * desc, unsigned int timestamp)
|
||||
{
|
||||
int uid;
|
||||
struct ip6t_entry * e;
|
||||
|
@ -204,6 +206,8 @@ int add_pinhole(const char * ifname,
|
|||
|
||||
e = calloc(1, sizeof(struct ip6t_entry));
|
||||
e->ipv6.proto = proto;
|
||||
if (proto)
|
||||
e->ipv6.flags |= IP6T_F_PROTO;
|
||||
|
||||
if(ifname)
|
||||
strncpy(e->ipv6.iniface, ifname, IFNAMSIZ);
|
||||
|
@ -238,7 +242,7 @@ int add_pinhole(const char * ifname,
|
|||
}
|
||||
uid = add_to_pinhole_list(&e->ipv6.src, rem_port,
|
||||
&e->ipv6.dst, int_port,
|
||||
proto, timestamp);
|
||||
proto, desc, timestamp);
|
||||
free(e);
|
||||
return uid;
|
||||
}
|
||||
|
@ -318,9 +322,12 @@ update_pinhole(unsigned short uid, unsigned int timestamp)
|
|||
|
||||
int
|
||||
get_pinhole_info(unsigned short uid,
|
||||
char * rem_host, int rem_hostlen, unsigned short * rem_port,
|
||||
char * int_client, int int_clientlen, unsigned short * int_port,
|
||||
int * proto, unsigned int * timestamp,
|
||||
char * rem_host, int rem_hostlen,
|
||||
unsigned short * rem_port,
|
||||
char * int_client, int int_clientlen,
|
||||
unsigned short * int_port,
|
||||
int * proto, char * desc, int desclen,
|
||||
unsigned int * timestamp,
|
||||
u_int64_t * packets, u_int64_t * bytes)
|
||||
{
|
||||
struct pinhole_t * p;
|
||||
|
@ -344,6 +351,8 @@ get_pinhole_info(unsigned short uid,
|
|||
*proto = p->proto;
|
||||
if(timestamp)
|
||||
*timestamp = p->timestamp;
|
||||
if (desc)
|
||||
strncpy(desc, p->desc, desclen);
|
||||
if(packets || bytes) {
|
||||
/* theses informations need to be read from netfilter */
|
||||
IP6TC_HANDLE h;
|
||||
|
@ -377,6 +386,16 @@ get_pinhole_info(unsigned short uid,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int get_pinhole_uid_by_index(int index)
|
||||
{
|
||||
struct pinhole_t * p;
|
||||
|
||||
for(p = pinhole_list.lh_first; p != NULL; p = p->entries.le_next)
|
||||
if (!index--)
|
||||
return p->uid;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
clean_pinhole_list(unsigned int * next_timestamp)
|
||||
{
|
||||
|
@ -407,5 +426,4 @@ clean_pinhole_list(unsigned int * next_timestamp)
|
|||
return n;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* ENABLE_UPNPPINHOLE */
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
#ifndef IPTPINHOLE_H_INCLUDED
|
||||
#define IPTPINHOLE_H_INCLUDED
|
||||
|
||||
#ifdef ENABLE_6FC_SERVICE
|
||||
#ifdef ENABLE_UPNPPINHOLE
|
||||
#include <sys/types.h>
|
||||
|
||||
int add_pinhole(const char * ifname,
|
||||
const char * rem_host, unsigned short rem_port,
|
||||
const char * int_client, unsigned short int_port,
|
||||
int proto, unsigned int timestamp);
|
||||
int proto, const char *desc, unsigned int timestamp);
|
||||
|
||||
int update_pinhole(unsigned short uid, unsigned int timestamp);
|
||||
|
||||
|
@ -20,12 +22,16 @@ int delete_pinhole(unsigned short uid);
|
|||
int
|
||||
get_pinhole_info(unsigned short uid,
|
||||
char * rem_host, int rem_hostlen, unsigned short * rem_port,
|
||||
char * int_client, int int_clientlen, unsigned short * int_port,
|
||||
int * proto, unsigned int * timestamp,
|
||||
char * int_client, int int_clientlen,
|
||||
unsigned short * int_port,
|
||||
int * proto, char * desc, int desclen,
|
||||
unsigned int * timestamp,
|
||||
u_int64_t * packets, u_int64_t * bytes);
|
||||
|
||||
int get_pinhole_uid_by_index(int index);
|
||||
|
||||
int clean_pinhole_list(unsigned int * next_timestamp);
|
||||
|
||||
#endif
|
||||
#endif /* ENABLE_UPNPPINHOLE */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* author: Ryan Wagoner
|
||||
* (c) 2006-2013 Thomas Bernard
|
||||
* (c) 2006-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
|
@ -31,7 +31,14 @@ static const struct {
|
|||
{ UPNPEXT_IFNAME, "ext_ifname" },
|
||||
{ UPNPEXT_IP, "ext_ip" },
|
||||
{ UPNPLISTENING_IP, "listening_ip" },
|
||||
#ifdef ENABLE_IPV6
|
||||
{ UPNPIPV6_LISTENING_IP, "ipv6_listening_ip" },
|
||||
#endif /* ENABLE_IPV6 */
|
||||
{ UPNPPORT, "port" },
|
||||
{ UPNPPORT, "http_port" }, /* "port" and "http_port" are synonims */
|
||||
#ifdef ENABLE_HTTPS
|
||||
{ UPNPHTTPSPORT, "https_port" },
|
||||
#endif /* ENABLE_HTTPS */
|
||||
{ UPNPBITRATE_UP, "bitrate_up" },
|
||||
{ UPNPBITRATE_DOWN, "bitrate_down" },
|
||||
{ UPNPPRESENTATIONURL, "presentation_url" },
|
||||
|
@ -61,6 +68,7 @@ static const struct {
|
|||
#ifdef ENABLE_PCP
|
||||
{ UPNPPCPMINLIFETIME, "min_lifetime"},
|
||||
{ UPNPPCPMAXLIFETIME, "max_lifetime"},
|
||||
{ UPNPPCPALLOWTHIRDPARTY, "pcp_allow_thirdparty"},
|
||||
#endif
|
||||
{ UPNPENABLE, "enable_upnp"},
|
||||
#ifdef USE_PF
|
||||
|
@ -136,8 +144,10 @@ readoptionsfile(const char * fname)
|
|||
/* check for comments or empty lines */
|
||||
if(name[0] == '#' || name[0] == '\0') continue;
|
||||
|
||||
len = strlen(name); /* length of the whole line excluding leading
|
||||
* and ending white spaces */
|
||||
/* check for UPnP permissions rule */
|
||||
if(0 == memcmp(name, "allow", 5) || 0 == memcmp(name, "deny", 4))
|
||||
if((len > 6) && (0 == memcmp(name, "allow", 5) || 0 == memcmp(name, "deny", 4)))
|
||||
{
|
||||
tmp = realloc(upnppermlist, sizeof(struct upnpperm) * (num_upnpperm+1));
|
||||
if(tmp == NULL)
|
||||
|
@ -163,7 +173,7 @@ readoptionsfile(const char * fname)
|
|||
}
|
||||
#ifdef PCP_SADSCP
|
||||
/* check for DSCP values configuration */
|
||||
if(0 == memcmp(name, "set_learn_dscp", sizeof("set_learn_dscp")-1) )
|
||||
if((len > 15) && 0 == memcmp(name, "set_learn_dscp", sizeof("set_learn_dscp")-1) )
|
||||
{
|
||||
tmp = realloc(dscp_values_list, sizeof(struct dscp_values) * (num_dscp_values+1));
|
||||
if(tmp == NULL)
|
||||
|
@ -307,4 +317,3 @@ freeoptions(void)
|
|||
}
|
||||
|
||||
#endif /* DISABLE_CONFIG_FILE */
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* author: Ryan Wagoner
|
||||
* (c) 2006-2013 Thomas Bernard
|
||||
* (c) 2006-2014 Thomas Bernard
|
||||
* This software is subject to the conditions detailed
|
||||
* in the LICENCE file provided within the distribution */
|
||||
|
||||
|
@ -18,7 +18,13 @@ enum upnpconfigoptions {
|
|||
UPNPEXT_IFNAME = 1, /* ext_ifname */
|
||||
UPNPEXT_IP, /* ext_ip */
|
||||
UPNPLISTENING_IP, /* listening_ip */
|
||||
UPNPPORT, /* "port" */
|
||||
#ifdef ENABLE_IPV6
|
||||
UPNPIPV6_LISTENING_IP, /* listening address for IPv6 */
|
||||
#endif /* ENABLE_IPV6 */
|
||||
UPNPPORT, /* "port" / "http_port" */
|
||||
#ifdef ENABLE_HTTPS
|
||||
UPNPHTTPSPORT, /* "https_port" */
|
||||
#endif
|
||||
UPNPBITRATE_UP, /* "bitrate_up" */
|
||||
UPNPBITRATE_DOWN, /* "bitrate_down" */
|
||||
UPNPPRESENTATIONURL, /* presentation_url */
|
||||
|
@ -41,6 +47,7 @@ enum upnpconfigoptions {
|
|||
UPNPENABLENATPMP, /* enable_natpmp */
|
||||
UPNPPCPMINLIFETIME, /* minimum lifetime for PCP mapping */
|
||||
UPNPPCPMAXLIFETIME, /* maximum lifetime for PCP mapping */
|
||||
UPNPPCPALLOWTHIRDPARTY, /* allow third-party requests */
|
||||
#ifdef USE_NETFILTER
|
||||
UPNPFORWARDCHAIN,
|
||||
UPNPNATCHAIN,
|
||||
|
|
|
@ -135,10 +135,10 @@ typedef enum pcp_options {
|
|||
} pcp_options_t;
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable:4200)
|
||||
#endif /* WIN32 */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
|
@ -285,6 +285,6 @@ typedef struct pcp_filter_option {
|
|||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
#pragma warning (pop)
|
||||
#endif /* WIN32 */
|
||||
#endif /* _WIN32 */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue