From edf519a67a28f9acb61af6d442d94f1aa43df688 Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
Date: Tue, 16 May 2017 16:59:08 +0200
Subject: Update 3rdParty/LibMiniUPnPc to miniupnpc-2.0.20170509

Test-Information:

Builds on macOS 10.12.5 with Qt 5.4.2 and all unit and
integration tests pass.

Change-Id: I491c0f78bf8773056feb3825d21989d6c7a2aeab

diff --git a/3rdParty/LibMiniUPnPc/SConscript b/3rdParty/LibMiniUPnPc/SConscript
index 3c2e29d..a995941 100644
--- a/3rdParty/LibMiniUPnPc/SConscript
+++ b/3rdParty/LibMiniUPnPc/SConscript
@@ -12,7 +12,7 @@ if env.get("LIBMINIUPNPC_BUNDLED", False) :
         env["HAVE_LIBMINIUPNPC"] = True
         env["LIBMINIUPNPC_FLAGS"] = {
                 "LIBPATH": [Dir(".")],
-                "INTERNAL_CPPDEFINES": ["STATICLIB"],
+                "INTERNAL_CPPDEFINES": ["MINIUPNP_STATICLIB"],
             }
         if os.path.basename(env["CC"]) in ("clang", "gcc") :
             env["LIBMINIUPNPC_FLAGS"].update({"CPPFLAGS": ["-isystem" "3rdParty/LibMiniUPnPc/src/miniupnpc"]})
@@ -34,7 +34,7 @@ if env.get("LIBMINIUPNPC_BUNDLED", False) :
         # Remove warn flags
         myenv.Replace(CCFLAGS = [flag for flag in env["CCFLAGS"] if flag not in ["-W", "-Wall"]])
 
-        myenv.Append(CCFLAGS = ["-DNDEBUG", "-DSTATICLIB"])
+        myenv.Append(CCFLAGS = ["-DNDEBUG", "-DMINIUPNP_STATICLIB"])
 
         if myenv["PLATFORM"] != "win32":
             myenv.Append(CCFLAGS = ["-DMINIUPNPC_SET_SOCKET_TIMEOUT"])
@@ -54,31 +54,37 @@ if env.get("LIBMINIUPNPC_BUNDLED", False) :
 
         myenv.WriteVal("src/miniupnpc/miniupnpcstrings.h", myenv.Value(
 """
-#ifndef __MINIUPNPCSTRINGS_H__
-#define __MINIUPNPCSTRINGS_H__
+#ifndef MINIUPNPCSTRINGS_H_INCLUDED
+#define MINIUPNPCSTRINGS_H_INCLUDED
 
 #define OS_STRING "$OS_STRING"
 #define MINIUPNPC_VERSION_STRING "1.9"
 
+#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
 """.replace("$OS_STRING", myenv["PLATFORM"])))
 
         miniupnpc_objects = [
+            "src/miniupnpc/connecthostport.c",
             "src/miniupnpc/igd_desc_parse.c",
-            "src/miniupnpc/miniupnpc.c",
-            "src/miniupnpc/minixml.c",
             "src/miniupnpc/minisoap.c",
+            "src/miniupnpc/minissdpc.c",
+            "src/miniupnpc/miniupnpc.c",
             "src/miniupnpc/miniwget.c",
-            #"src/miniupnpc/upnpc.c",
+            "src/miniupnpc/minixml.c",
+            "src/miniupnpc/portlistingparse.c",
+            "src/miniupnpc/receivedata.c",
             "src/miniupnpc/upnpcommands.c",
-            "src/miniupnpc/upnpreplyparse.c",
+            "src/miniupnpc/upnpdev.c",
             "src/miniupnpc/upnperrors.c",
-            "src/miniupnpc/connecthostport.c",
-            "src/miniupnpc/portlistingparse.c",
-            "src/miniupnpc/receivedata.c"
+            "src/miniupnpc/upnpreplyparse.c",
             ]
 
-        if myenv["PLATFORM"] != "win32":
-            miniupnpc_objects.append("src/miniupnpc/minissdpc.c")
-
         env["LIBMINIUPNPC_OBJECTS"] = myenv.SwiftenObject(miniupnpc_objects)            
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE b/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE
index ac89a75..0816733 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE
@@ -1,5 +1,5 @@
 MiniUPnPc
-Copyright (c) 2005-2011, Thomas BERNARD
+Copyright (c) 2005-2016, Thomas BERNARD
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h
index d342bd1..f5f8e30 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h
@@ -1,7 +1,7 @@
-/* $Id: codelength.h,v 1.4 2012/09/27 15:40:29 nanard Exp $ */
+/* $Id: codelength.h,v 1.5 2015/07/09 12:40:18 nanard Exp $ */
 /* Project : miniupnp
  * Author : Thomas BERNARD
- * copyright (c) 2005-2011 Thomas Bernard
+ * copyright (c) 2005-2015 Thomas Bernard
  * This software is subjet to the conditions detailed in the
  * provided LICENCE file. */
 #ifndef CODELENGTH_H_INCLUDED
@@ -10,10 +10,30 @@
 /* Encode length by using 7bit per Byte :
  * Most significant bit of each byte specifies that the
  * following byte is part of the code */
+
+/* n : unsigned
+ * p : unsigned char *
+ */
 #define DECODELENGTH(n, p) n = 0; \
                            do { n = (n << 7) | (*p & 0x7f); } \
                            while((*(p++)&0x80) && (n<(1<<25)));
 
+/* n :    unsigned
+ * READ : function/macro to read one byte (unsigned char)
+ */
+#define DECODELENGTH_READ(n, READ) \
+	n = 0; \
+	do { \
+		unsigned char c; \
+		READ(c); \
+		n = (n << 7) | (c & 0x07f); \
+		if(!(c&0x80)) break; \
+	} while(n<(1<<25));
+
+/* n :       unsigned
+ * p :       unsigned char *
+ * p_limit : unsigned char *
+ */
 #define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
 	n = 0; \
 	do { \
@@ -21,11 +41,14 @@
 		n = (n << 7) | (*(p) & 0x7f); \
 	} while((*((p)++)&0x80) && (n<(1<<25)));
 
+
+/* n : unsigned
+ * p : unsigned char *
+ */
 #define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
                          if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
                          if(n>=16384) *(p++) = (n >> 14) | 0x80; \
                          if(n>=128) *(p++) = (n >> 7) | 0x80; \
                          *(p++) = n & 0x7f;
 
-#endif
-
+#endif /* CODELENGTH_H_INCLUDED */
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c
index aabc7a6..aed62c7 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c
@@ -1,7 +1,7 @@
-/* $Id: connecthostport.c,v 1.11 2013/08/01 21:21:25 nanard Exp $ */
+/* $Id: connecthostport.c,v 1.17 2017/04/21 09:58:30 nanard Exp $ */
 /* Project : miniupnp
  * Author : Thomas Bernard
- * Copyright (c) 2010-2013 Thomas Bernard
+ * Copyright (c) 2010-2017 Thomas Bernard
  * This software is subject to the conditions detailed in the
  * LICENCE file provided in this distribution. */
 
@@ -23,6 +23,10 @@
 #define socklen_t int
 #else /* #ifdef _WIN32 */
 #include <unistd.h>
+#include <sys/types.h>
+#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
+#include <sys/time.h>
+#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
 #include <sys/param.h>
 #include <sys/select.h>
 #include <errno.h>
@@ -32,15 +36,13 @@
 /* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
  * during the connect() call */
 #define MINIUPNPC_IGNORE_EINTR
-#ifndef USE_GETHOSTBYNAME
-#include <sys/types.h>
 #include <sys/socket.h>
-#endif /* #ifndef USE_GETHOSTBYNAME */
+#include <sys/select.h>
 #endif /* #else _WIN32 */
 
 /* definition of PRINT_SOCKET_ERROR */
 #ifdef _WIN32
-#define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, WSAGetLastError());
+#define PRINT_SOCKET_ERROR(x)    fprintf(stderr, "Socket error: %s, %d\n", x, WSAGetLastError());
 #else
 #define PRINT_SOCKET_ERROR(x) perror(x)
 #endif
@@ -96,20 +98,23 @@ int connecthostport(const char * host, unsigned short port,
 	timeout.tv_usec = 0;
 	if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
 	{
-		PRINT_SOCKET_ERROR("setsockopt");
+		PRINT_SOCKET_ERROR("setsockopt SO_RCVTIMEO");
 	}
 	timeout.tv_sec = 3;
 	timeout.tv_usec = 0;
 	if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
 	{
-		PRINT_SOCKET_ERROR("setsockopt");
+		PRINT_SOCKET_ERROR("setsockopt SO_SNDTIMEO");
 	}
 #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
 	dest.sin_family = AF_INET;
 	dest.sin_port = htons(port);
 	n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
 #ifdef MINIUPNPC_IGNORE_EINTR
-	while(n < 0 && errno == EINTR)
+	/* EINTR The system call was interrupted by a signal that was caught
+	 * EINPROGRESS The socket is nonblocking and the connection cannot
+	 *             be completed immediately. */
+	while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
 	{
 		socklen_t len;
 		fd_set wset;
@@ -203,7 +208,10 @@ int connecthostport(const char * host, unsigned short port,
 #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
 		n = connect(s, p->ai_addr, p->ai_addrlen);
 #ifdef MINIUPNPC_IGNORE_EINTR
-		while(n < 0 && errno == EINTR)
+		/* EINTR The system call was interrupted by a signal that was caught
+		 * EINPROGRESS The socket is nonblocking and the connection cannot
+		 *             be completed immediately. */
+		while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
 		{
 			socklen_t len;
 			fd_set wset;
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.c
index 6c3e656..d2999ad 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.c
@@ -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.17 2015/09/15 13:30:04 nanard Exp $ */
 /* Project : miniupnp
  * http://miniupnp.free.fr/
  * Author : Thomas Bernard
- * Copyright (c) 2005-2010 Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
  * This software is subject to the conditions detailed in the
  * LICENCE file provided in this distribution. */
 
@@ -15,7 +15,9 @@
 void IGDstartelt(void * d, const char * name, int l)
 {
 	struct IGDdatas * datas = (struct IGDdatas *)d;
-	memcpy( datas->cureltname, name, l);
+	if(l >= MINIUPNPC_URL_MAXSIZE)
+		l = MINIUPNPC_URL_MAXSIZE-1;
+	memcpy(datas->cureltname, name, l);
 	datas->cureltname[l] = '\0';
 	datas->level++;
 	if( (l==7) && !memcmp(name, "service", l) ) {
@@ -26,6 +28,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 +40,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 {
@@ -93,6 +90,7 @@ void IGDdata(void * d, const char * data, int l)
 	}
 }
 
+#ifdef DEBUG
 void printIGD(struct IGDdatas * d)
 {
 	printf("urlbase = '%s'\n", d->urlbase);
@@ -121,5 +119,5 @@ void printIGD(struct IGDdatas * d)
 	printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl);
 	printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl);
 }
-
+#endif /* DEBUG */
 
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h
index 0a49b01..0de546b 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h
@@ -1,8 +1,8 @@
-/* $Id: igd_desc_parse.h,v 1.11 2012/10/16 16:49:02 nanard Exp $ */
+/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 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.
  * */
@@ -42,7 +42,8 @@ struct IGDdatas {
 void IGDstartelt(void *, const char *, int);
 void IGDendelt(void *, const char *, int);
 void IGDdata(void *, const char *, int);
+#ifdef DEBUG
 void printIGD(struct IGDdatas *);
+#endif /* DEBUG */
 
-#endif
-
+#endif /* IGD_DESC_PARSE_H_INCLUDED */
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c
index e45a481..0b4de30 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c
@@ -1,7 +1,7 @@
-/* $Id: minisoap.c,v 1.22 2012/01/21 13:30:31 nanard Exp $ */
+/* $Id: minisoap.c,v 1.25 2017/04/21 10:03:24 nanard Exp $ */
 /* Project : miniupnp
  * Author : Thomas Bernard
- * Copyright (c) 2005-2012 Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
  * This software is subject to the conditions detailed in the
  * LICENCE file provided in this distribution.
  *
@@ -25,7 +25,7 @@
 #include <stdlib.h>
 
 #ifdef _WIN32
-#define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, WSAGetLastError());
+#define PRINT_SOCKET_ERROR(x)    fprintf(stderr, "Socket error: %s, %d\n", x, WSAGetLastError());
 #else
 #define PRINT_SOCKET_ERROR(x) perror(x)
 #endif
@@ -43,10 +43,10 @@ httpWrite(int fd, const char * body, int bodysize,
 	/* Note : my old linksys router only took into account
 	 * soap request that are sent into only one packet */
 	char * p;
-	/* TODO: AVOID MALLOC */
+	/* TODO: AVOID MALLOC, we could use writev() for that */
 	p = malloc(headerssize+bodysize);
 	if(!p)
-	  return 0;
+	  return -1;
 	memcpy(p, headers, headerssize);
 	memcpy(p+headerssize, body, bodysize);
 	/*n = write(fd, p, headerssize+bodysize);*/
@@ -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"
@@ -105,6 +105,8 @@ int soapPostSubmit(int fd,
 					   "Pragma: no-cache\r\n"
 					   "\r\n",
 					   url, httpversion, host, portstr, bodysize, action);
+	if ((unsigned int)headerssize >= sizeof(headerbuf))
+		return -1;
 #ifdef DEBUG
 	/*printf("SOAP request : headersize=%d bodysize=%d\n",
 	       headerssize, bodysize);
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c
index c4913fb..3a81939 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c
@@ -1,67 +1,207 @@
-/* $Id: minissdpc.c,v 1.16 2012/03/05 19:42:46 nanard Exp $ */
-/* Project : miniupnp
+/* $Id: minissdpc.c,v 1.34 2017/04/21 10:06:38 nanard Exp $ */
+/* vim: tabstop=4 shiftwidth=4 noexpandtab
+ * Project : miniupnp
  * Web : http://miniupnp.free.fr/
  * Author : Thomas BERNARD
- * copyright (c) 2005-2012 Thomas Bernard
+ * copyright (c) 2005-2017 Thomas Bernard
  * This software is subjet to the conditions detailed in the
  * provided LICENCE file. */
 /*#include <syslog.h>*/
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <sys/types.h>
+#if defined (__NetBSD__)
+#include <net/if.h>
+#endif
 #if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)
 #ifdef _WIN32
 #include <winsock2.h>
 #include <ws2tcpip.h>
 #include <io.h>
+#include <iphlpapi.h>
 #include <winsock.h>
+#define snprintf _snprintf
+#if !defined(_MSC_VER)
 #include <stdint.h>
-#endif
+#else /* !defined(_MSC_VER) */
+typedef unsigned short uint16_t;
+#endif /* !defined(_MSC_VER) */
+#ifndef strncasecmp
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define strncasecmp _memicmp
+#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
+#define strncasecmp memicmp
+#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
+#endif /* #ifndef strncasecmp */
+#endif /* _WIN32 */
 #if defined(__amigaos__) || defined(__amigaos4__)
 #include <sys/socket.h>
-#endif
+#endif /* defined(__amigaos__) || defined(__amigaos4__) */
 #if defined(__amigaos__)
 #define uint16_t unsigned short
-#endif
+#endif /* defined(__amigaos__) */
 /* Hack */
 #define UNIX_PATH_LEN   108
 struct sockaddr_un {
   uint16_t sun_family;
   char     sun_path[UNIX_PATH_LEN];
 };
-#else
+#else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */
+#include <strings.h>
+#include <unistd.h>
 #include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
 #include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <net/if.h>
+#define closesocket close
+#endif
+
+#ifdef _WIN32
+#define PRINT_SOCKET_ERROR(x)    fprintf(stderr, "Socket error: %s, %d\n", x, WSAGetLastError());
+#else
+#define PRINT_SOCKET_ERROR(x) perror(x)
+#endif
+
+#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
+
+#if !defined(HAS_IP_MREQN) && !defined(_WIN32)
+#include <sys/ioctl.h>
+#if defined(__sun)
+#include <sys/sockio.h>
+#endif
+#endif
+
+#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN)
+/* Several versions of glibc don't define this structure,
+ * define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */
+struct ip_mreqn
+{
+	struct in_addr	imr_multiaddr;		/* IP multicast address of group */
+	struct in_addr	imr_address;		/* local IP address of interface */
+	int		imr_ifindex;		/* Interface index */
+};
+#endif
+
+#if defined(__amigaos__) || defined(__amigaos4__)
+/* Amiga OS specific stuff */
+#define TIMEVAL struct timeval
 #endif
 
 #include "minissdpc.h"
 #include "miniupnpc.h"
+#include "receivedata.h"
+
+#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
 
 #include "codelength.h"
 
 struct UPNPDev *
-getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
+getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error)
 {
-	struct UPNPDev * tmp;
 	struct UPNPDev * devlist = NULL;
-	unsigned char buffer[2048];
-	ssize_t n;
-	unsigned char * p;
-	unsigned char * url;
-	unsigned int i;
-	unsigned int urlsize, stsize, usnsize, l;
+	int s;
+	int res;
+
+	s = connectToMiniSSDPD(socketpath);
+	if (s < 0) {
+		if (error)
+			*error = s;
+		return NULL;
+	}
+	res = requestDevicesFromMiniSSDPD(s, devtype);
+	if (res < 0) {
+		if (error)
+			*error = res;
+	} else {
+		devlist = receiveDevicesFromMiniSSDPD(s, error);
+	}
+	disconnectFromMiniSSDPD(s);
+	return devlist;
+}
+
+/* macros used to read from unix socket */
+#define READ_BYTE_BUFFER(c) \
+	if((int)bufferindex >= n) { \
+		n = read(s, buffer, sizeof(buffer)); \
+		if(n<=0) break; \
+		bufferindex = 0; \
+	} \
+	c = buffer[bufferindex++];
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif /* MIN */
+
+#define READ_COPY_BUFFER(dst, len) \
+	for(l = len, p = (unsigned char *)dst; l > 0; ) { \
+		unsigned int lcopy; \
+		if((int)bufferindex >= n) { \
+			n = read(s, buffer, sizeof(buffer)); \
+			if(n<=0) break; \
+			bufferindex = 0; \
+		} \
+		lcopy = MIN(l, (n - bufferindex)); \
+		memcpy(p, buffer + bufferindex, lcopy); \
+		l -= lcopy; \
+		p += lcopy; \
+		bufferindex += lcopy; \
+	}
+
+#define READ_DISCARD_BUFFER(len) \
+	for(l = len; l > 0; ) { \
+		unsigned int lcopy; \
+		if(bufferindex >= n) { \
+			n = read(s, buffer, sizeof(buffer)); \
+			if(n<=0) break; \
+			bufferindex = 0; \
+		} \
+		lcopy = MIN(l, (n - bufferindex)); \
+		l -= lcopy; \
+		bufferindex += lcopy; \
+	}
+
+int
+connectToMiniSSDPD(const char * socketpath)
+{
 	int s;
 	struct sockaddr_un addr;
+#if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun)
+	struct timeval timeout;
+#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
 
 	s = socket(AF_UNIX, SOCK_STREAM, 0);
 	if(s < 0)
 	{
 		/*syslog(LOG_ERR, "socket(unix): %m");*/
 		perror("socket(unix)");
-		return NULL;
+		return MINISSDPC_SOCKET_ERROR;
 	}
+#if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun)
+	/* setting a 3 seconds timeout */
+	/* not supported for AF_UNIX sockets under Solaris */
+	timeout.tv_sec = 3;
+	timeout.tv_usec = 0;
+	if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
+	{
+		perror("setsockopt SO_RCVTIMEO unix");
+	}
+	timeout.tv_sec = 3;
+	timeout.tv_usec = 0;
+	if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
+	{
+		perror("setsockopt SO_SNDTIMEO unix");
+	}
+#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
+	if(!socketpath)
+		socketpath = "/var/run/minissdpd.sock";
+	memset(&addr, 0, sizeof(addr));
 	addr.sun_family = AF_UNIX;
 	strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path));
 	/* TODO : check if we need to handle the EINTR */
@@ -69,17 +209,45 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
 	{
 		/*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/
 		close(s);
-		return NULL;
+		return MINISSDPC_SOCKET_ERROR;
 	}
+	return s;
+}
+
+int
+disconnectFromMiniSSDPD(int s)
+{
+	if (close(s) < 0)
+		return MINISSDPC_SOCKET_ERROR;
+	return MINISSDPC_SUCCESS;
+}
+
+int
+requestDevicesFromMiniSSDPD(int s, const char * devtype)
+{
+	unsigned char buffer[256];
+	unsigned char * p;
+	unsigned int stsize, l;
+
 	stsize = strlen(devtype);
-	buffer[0] = 1; /* request type 1 : request devices/services by type */
+	if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8))
+	{
+		buffer[0] = 3;	/* request type 3 : everything */
+	}
+	else
+	{
+		buffer[0] = 1; /* request type 1 : request devices/services by type */
+	}
 	p = buffer + 1;
 	l = stsize;	CODELENGTH(l, p);
 	if(p + stsize > buffer + sizeof(buffer))
 	{
 		/* devtype is too long ! */
-		close(s);
-		return NULL;
+#ifdef DEBUG
+		fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n",
+		        stsize, (unsigned)sizeof(buffer));
+#endif /* DEBUG */
+		return MINISSDPC_INVALID_INPUT;
 	}
 	memcpy(p, devtype, stsize);
 	p += stsize;
@@ -87,47 +255,634 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
 	{
 		/*syslog(LOG_ERR, "write(): %m");*/
 		perror("minissdpc.c: write()");
-		close(s);
-		return NULL;
+		return MINISSDPC_SOCKET_ERROR;
 	}
+	return MINISSDPC_SUCCESS;
+}
+
+struct UPNPDev *
+receiveDevicesFromMiniSSDPD(int s, int * error)
+{
+	struct UPNPDev * tmp;
+	struct UPNPDev * devlist = NULL;
+	unsigned char buffer[256];
+	ssize_t n;
+	unsigned char * p;
+	unsigned char * url;
+	unsigned char * st;
+	unsigned int bufferindex;
+	unsigned int i, ndev;
+	unsigned int urlsize, stsize, usnsize, l;
+
 	n = read(s, buffer, sizeof(buffer));
 	if(n<=0)
 	{
 		perror("minissdpc.c: read()");
-		close(s);
+		if (error)
+			*error = MINISSDPC_SOCKET_ERROR;
 		return NULL;
 	}
-	p = buffer + 1;
-	for(i = 0; i < buffer[0]; i++)
+	ndev = buffer[0];
+	bufferindex = 1;
+	for(i = 0; i < ndev; i++)
 	{
-		if(p+2>=buffer+sizeof(buffer))
-			break;
-		DECODELENGTH(urlsize, p);
-		if(p+urlsize+2>=buffer+sizeof(buffer))
-			break;
-		url = p;
-		p += urlsize;
-		DECODELENGTH(stsize, p);
-		if(p+stsize+2>=buffer+sizeof(buffer))
-			break;
-		tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
+		DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER);
+		if(n<=0) {
+			if (error)
+				*error = MINISSDPC_INVALID_SERVER_REPLY;
+			return devlist;
+		}
+#ifdef DEBUG
+		printf("  urlsize=%u", urlsize);
+#endif /* DEBUG */
+		url = malloc(urlsize);
+		if(url == NULL) {
+			if (error)
+				*error = MINISSDPC_MEMORY_ERROR;
+			return devlist;
+		}
+		READ_COPY_BUFFER(url, urlsize);
+		if(n<=0) {
+			if (error)
+				*error = MINISSDPC_INVALID_SERVER_REPLY;
+			goto free_url_and_return;
+		}
+		DECODELENGTH_READ(stsize, READ_BYTE_BUFFER);
+		if(n<=0) {
+			if (error)
+				*error = MINISSDPC_INVALID_SERVER_REPLY;
+			goto free_url_and_return;
+		}
+#ifdef DEBUG
+		printf("   stsize=%u", stsize);
+#endif /* DEBUG */
+		st = malloc(stsize);
+		if (st == NULL) {
+			if (error)
+				*error = MINISSDPC_MEMORY_ERROR;
+			goto free_url_and_return;
+		}
+		READ_COPY_BUFFER(st, stsize);
+		if(n<=0) {
+			if (error)
+				*error = MINISSDPC_INVALID_SERVER_REPLY;
+			goto free_url_and_st_and_return;
+		}
+		DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER);
+		if(n<=0) {
+			if (error)
+				*error = MINISSDPC_INVALID_SERVER_REPLY;
+			goto free_url_and_st_and_return;
+		}
+#ifdef DEBUG
+		printf("   usnsize=%u\n", usnsize);
+#endif /* DEBUG */
+		tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
+		if(tmp == NULL) {
+			if (error)
+				*error = MINISSDPC_MEMORY_ERROR;
+			goto free_url_and_st_and_return;
+		}
 		tmp->pNext = devlist;
 		tmp->descURL = tmp->buffer;
 		tmp->st = tmp->buffer + 1 + urlsize;
 		memcpy(tmp->buffer, url, urlsize);
 		tmp->buffer[urlsize] = '\0';
-		memcpy(tmp->buffer + urlsize + 1, p, stsize);
-		p += stsize;
+		memcpy(tmp->st, st, stsize);
 		tmp->buffer[urlsize+1+stsize] = '\0';
+		free(url);
+		free(st);
+		url = NULL;
+		st = NULL;
+		tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize;
+		READ_COPY_BUFFER(tmp->usn, usnsize);
+		if(n<=0) {
+			if (error)
+				*error = MINISSDPC_INVALID_SERVER_REPLY;
+			goto free_tmp_and_return;
+		}
+		tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
+		tmp->scope_id = 0;	/* default value. scope_id is not available with MiniSSDPd */
 		devlist = tmp;
-		/* added for compatibility with recent versions of MiniSSDPd
-		 * >= 2007/12/19 */
-		DECODELENGTH(usnsize, p);
-		p += usnsize;
-		if(p>buffer + sizeof(buffer))
+	}
+	if (error)
+		*error = MINISSDPC_SUCCESS;
+	return devlist;
+
+free_url_and_st_and_return:
+	free(st);
+free_url_and_return:
+	free(url);
+	return devlist;
+
+free_tmp_and_return:
+	free(tmp);
+	return devlist;
+}
+
+#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
+
+/* 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 */
+static void
+parseMSEARCHReply(const char * reply, int size,
+                  const char * * location, int * locationsize,
+			      const char * * st, int * stsize,
+			      const char * * usn, int * usnsize)
+{
+	int a, b, i;
+	i = 0;
+	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" */
+					/*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');*/
+					/* skip the colon and white spaces */
+					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;
+					}
+					else if(0==strncasecmp(reply+a, "usn", 3))
+					{
+						*usn = reply+b;
+						*usnsize = i-b;
+					}
+					b = 0;
+				}
+				a = i+1;
+				break;
+		default:
+				break;
+		}
+		i++;
+	}
+}
+
+/* port upnp discover : SSDP protocol */
+#define SSDP_PORT 1900
+#define XSTR(s) STR(s)
+#define STR(s) #s
+#define UPNP_MCAST_ADDR "239.255.255.250"
+/* for IPv6 */
+#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
+#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
+
+/* direct discovery if minissdpd responses are not sufficient */
+/* ssdpDiscoverDevices() :
+ * return a chained list of all devices found or NULL if
+ * no devices was found.
+ * It is up to the caller to free the chained list
+ * delay is in millisecond (poll).
+ * UDA v1.1 says :
+ *   The TTL for the IP packet SHOULD default to 2 and
+ *   SHOULD be configurable. */
+struct UPNPDev *
+ssdpDiscoverDevices(const char * const deviceTypes[],
+                    int delay, const char * multicastif,
+                    int localport,
+                    int ipv6, unsigned char ttl,
+                    int * error,
+                    int searchalltypes)
+{
+	struct UPNPDev * tmp;
+	struct UPNPDev * devlist = 0;
+	unsigned int scope_id = 0;
+	int opt = 1;
+	static const char MSearchMsgFmt[] =
+	"M-SEARCH * HTTP/1.1\r\n"
+	"HOST: %s:" XSTR(SSDP_PORT) "\r\n"
+	"ST: %s\r\n"
+	"MAN: \"ssdp:discover\"\r\n"
+	"MX: %u\r\n"
+	"\r\n";
+	int deviceIndex;
+	char bufr[1536];	/* reception and emission buffer */
+	int sudp;
+	int n;
+	struct sockaddr_storage sockudp_r;
+	unsigned int mx;
+#ifdef NO_GETADDRINFO
+	struct sockaddr_storage sockudp_w;
+#else
+	int rv;
+	struct addrinfo hints, *servinfo, *p;
+#endif
+#ifdef _WIN32
+	MIB_IPFORWARDROW ip_forward;
+	unsigned long _ttl = (unsigned long)ttl;
+#endif
+	int linklocal = 1;
+	int sentok;
+
+	if(error)
+		*error = MINISSDPC_UNKNOWN_ERROR;
+
+	if(localport==UPNP_LOCAL_PORT_SAME)
+		localport = SSDP_PORT;
+
+#ifdef _WIN32
+	sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+#else
+	sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
+#endif
+	if(sudp < 0)
+	{
+		if(error)
+			*error = MINISSDPC_SOCKET_ERROR;
+		PRINT_SOCKET_ERROR("socket");
+		return NULL;
+	}
+	/* reception */
+	memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
+	if(ipv6) {
+		struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
+		p->sin6_family = AF_INET6;
+		if(localport > 0 && localport < 65536)
+			p->sin6_port = htons((unsigned short)localport);
+		p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
+	} else {
+		struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
+		p->sin_family = AF_INET;
+		if(localport > 0 && localport < 65536)
+			p->sin_port = htons((unsigned short)localport);
+		p->sin_addr.s_addr = INADDR_ANY;
+	}
+#ifdef _WIN32
+/* This code could help us to use the right Network interface for
+ * SSDP multicast traffic */
+/* Get IP associated with the index given in the ip_forward struct
+ * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
+	if(!ipv6
+	   && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
+		DWORD dwRetVal = 0;
+		PMIB_IPADDRTABLE pIPAddrTable;
+		DWORD dwSize = 0;
+#ifdef DEBUG
+		IN_ADDR IPAddr;
+#endif
+		int i;
+#ifdef DEBUG
+		printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop);
+#endif
+		pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE));
+		if(pIPAddrTable) {
+			if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
+				free(pIPAddrTable);
+				pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
+			}
+		}
+		if(pIPAddrTable) {
+			dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
+			if (dwRetVal == NO_ERROR) {
+#ifdef DEBUG
+				printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
+#endif
+				for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
+#ifdef DEBUG
+					printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
+					IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
+					printf("\tIP Address[%d]:     \t%s\n", i, inet_ntoa(IPAddr) );
+					IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
+					printf("\tSubnet Mask[%d]:    \t%s\n", i, inet_ntoa(IPAddr) );
+					IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
+					printf("\tBroadCast[%d]:      \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
+					printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
+					printf("\tType and State[%d]:", i);
+					printf("\n");
+#endif
+					if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) {
+						/* Set the address of this interface to be used */
+						struct in_addr mc_if;
+						memset(&mc_if, 0, sizeof(mc_if));
+						mc_if.s_addr = pIPAddrTable->table[i].dwAddr;
+						if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
+							PRINT_SOCKET_ERROR("setsockopt");
+						}
+						((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
+#ifndef DEBUG
+						break;
+#endif
+					}
+				}
+			}
+			free(pIPAddrTable);
+			pIPAddrTable = NULL;
+		}
+	}
+#endif	/* _WIN32 */
+
+#ifdef _WIN32
+	if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
+#else
+	if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
+#endif
+	{
+		if(error)
+			*error = MINISSDPC_SOCKET_ERROR;
+		PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)");
+		return NULL;
+	}
+
+	if(ipv6) {
+		int mcastHops = ttl;
+		if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastHops, sizeof(mcastHops)) < 0)
+		{
+			PRINT_SOCKET_ERROR("setsockopt(IPV6_MULTICAST_HOPS,...)");
+		}
+	} else {
+#ifdef _WIN32
+		if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0)
+#else  /* _WIN32 */
+		if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
+#endif /* _WIN32 */
+		{
+			/* not a fatal error */
+			PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)");
+		}
+	}
+
+	if(multicastif)
+	{
+		if(ipv6) {
+#if !defined(_WIN32)
+			/* according to MSDN, if_nametoindex() is supported since
+			 * MS Windows Vista and MS Windows Server 2008.
+			 * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
+			unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
+			if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0)
+			{
+				PRINT_SOCKET_ERROR("setsockopt IPV6_MULTICAST_IF");
+			}
+#else
+#ifdef DEBUG
+			printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
+#endif
+#endif
+		} else {
+			struct in_addr mc_if;
+			mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
+			if(mc_if.s_addr != INADDR_NONE)
+			{
+				((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
+				if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
+				{
+					PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
+				}
+			} else {
+#ifdef HAS_IP_MREQN
+				/* was not an ip address, try with an interface name */
+				struct ip_mreqn reqn;	/* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
+				memset(&reqn, 0, sizeof(struct ip_mreqn));
+				reqn.imr_ifindex = if_nametoindex(multicastif);
+				if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
+				{
+					PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
+				}
+#elif !defined(_WIN32)
+				struct ifreq ifr;
+				int ifrlen = sizeof(ifr);
+				strncpy(ifr.ifr_name, multicastif, IFNAMSIZ);
+				ifr.ifr_name[IFNAMSIZ-1] = '\0';
+				if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0)
+				{
+					PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)");
+				}
+				mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+				if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
+				{
+					PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF");
+				}
+#else /* _WIN32 */
+#ifdef DEBUG
+				printf("Setting of multicast interface not supported with interface name.\n");
+#endif
+#endif /* #ifdef HAS_IP_MREQN / !defined(_WIN32) */
+			}
+		}
+	}
+
+	/* Before sending the packed, we first "bind" in order to be able
+	 * to receive the response */
+	if (bind(sudp, (const struct sockaddr *)&sockudp_r,
+	         ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
+	{
+		if(error)
+			*error = MINISSDPC_SOCKET_ERROR;
+		PRINT_SOCKET_ERROR("bind");
+		closesocket(sudp);
+		return NULL;
+	}
+
+	if(error)
+		*error = MINISSDPC_SUCCESS;
+	/* Calculating maximum response time in seconds */
+	mx = ((unsigned int)delay) / 1000u;
+	if(mx == 0) {
+		mx = 1;
+		delay = 1000;
+	}
+	/* receiving SSDP response packet */
+	for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
+		sentok = 0;
+		/* sending the SSDP M-SEARCH packet */
+		n = snprintf(bufr, sizeof(bufr),
+		             MSearchMsgFmt,
+		             ipv6 ?
+		             (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" :  "[" UPNP_MCAST_SL_ADDR "]")
+		             : UPNP_MCAST_ADDR,
+		             deviceTypes[deviceIndex], mx);
+		if ((unsigned int)n >= sizeof(bufr)) {
+			if(error)
+				*error = MINISSDPC_MEMORY_ERROR;
+			goto error;
+		}
+#ifdef DEBUG
+		/*printf("Sending %s", bufr);*/
+		printf("Sending M-SEARCH request to %s with ST: %s\n",
+		       ipv6 ?
+		       (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" :  "[" UPNP_MCAST_SL_ADDR "]")
+		       : UPNP_MCAST_ADDR,
+		       deviceTypes[deviceIndex]);
+#endif
+#ifdef NO_GETADDRINFO
+		/* the following code is not using getaddrinfo */
+		/* emission */
+		memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
+		if(ipv6) {
+			struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
+			p->sin6_family = AF_INET6;
+			p->sin6_port = htons(SSDP_PORT);
+			inet_pton(AF_INET6,
+			          linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
+			          &(p->sin6_addr));
+		} else {
+			struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
+			p->sin_family = AF_INET;
+			p->sin_port = htons(SSDP_PORT);
+			p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
+		}
+		n = sendto(sudp, bufr, n, 0, &sockudp_w,
+		           ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
+		if (n < 0) {
+			if(error)
+				*error = MINISSDPC_SOCKET_ERROR;
+			PRINT_SOCKET_ERROR("sendto");
+		} else {
+			sentok = 1;
+		}
+#else /* #ifdef NO_GETADDRINFO */
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */
+		hints.ai_socktype = SOCK_DGRAM;
+		/*hints.ai_flags = */
+		if ((rv = getaddrinfo(ipv6
+		                      ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
+		                      : UPNP_MCAST_ADDR,
+		                      XSTR(SSDP_PORT), &hints, &servinfo)) != 0) {
+			if(error)
+				*error = MINISSDPC_SOCKET_ERROR;
+#ifdef _WIN32
+			fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
+#else
+			fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
+#endif
 			break;
+		}
+		for(p = servinfo; p; p = p->ai_next) {
+			n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen);
+			if (n < 0) {
+#ifdef DEBUG
+				char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
+				if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
+				                sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
+					fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
+				}
+#endif
+				PRINT_SOCKET_ERROR("sendto");
+				continue;
+			} else {
+				sentok = 1;
+			}
+		}
+		freeaddrinfo(servinfo);
+		if(!sentok) {
+			if(error)
+				*error = MINISSDPC_SOCKET_ERROR;
+		}
+#endif /* #ifdef NO_GETADDRINFO */
+		/* Waiting for SSDP REPLY packet to M-SEARCH
+		 * if searchalltypes is set, enter the loop only
+		 * when the last deviceType is reached */
+		if((sentok && !searchalltypes) || !deviceTypes[deviceIndex + 1]) do {
+			n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
+			if (n < 0) {
+				/* error */
+				if(error)
+					*error = MINISSDPC_SOCKET_ERROR;
+				goto error;
+			} else if (n == 0) {
+				/* no data or Time Out */
+#ifdef DEBUG
+				printf("NODATA or TIMEOUT\n");
+#endif /* DEBUG */
+				if (devlist && !searchalltypes) {
+					/* found some devices, stop now*/
+					if(error)
+						*error = MINISSDPC_SUCCESS;
+					goto error;
+				}
+			} else {
+				const char * descURL=NULL;
+				int urlsize=0;
+				const char * st=NULL;
+				int stsize=0;
+				const char * usn=NULL;
+				int usnsize=0;
+				parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
+				if(st&&descURL) {
+#ifdef DEBUG
+					printf("M-SEARCH Reply:\n  ST: %.*s\n  USN: %.*s\n  Location: %.*s\n",
+					       stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
+#endif /* DEBUG */
+					for(tmp=devlist; tmp; tmp = tmp->pNext) {
+						if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
+						   tmp->descURL[urlsize] == '\0' &&
+						   memcmp(tmp->st, st, stsize) == 0 &&
+						   tmp->st[stsize] == '\0' &&
+						   (usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) &&
+						   tmp->usn[usnsize] == '\0')
+							break;
+					}
+					/* at the exit of the loop above, tmp is null if
+					 * no duplicate device was found */
+					if(tmp)
+						continue;
+					tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
+					if(!tmp) {
+						/* memory allocation error */
+						if(error)
+							*error = MINISSDPC_MEMORY_ERROR;
+						goto error;
+					}
+					tmp->pNext = devlist;
+					tmp->descURL = tmp->buffer;
+					tmp->st = tmp->buffer + 1 + urlsize;
+					tmp->usn = tmp->st + 1 + stsize;
+					memcpy(tmp->buffer, descURL, urlsize);
+					tmp->buffer[urlsize] = '\0';
+					memcpy(tmp->st, st, stsize);
+					tmp->buffer[urlsize+1+stsize] = '\0';
+					if(usn != NULL)
+						memcpy(tmp->usn, usn, usnsize);
+					tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
+					tmp->scope_id = scope_id;
+					devlist = tmp;
+				}
+			}
+		} while(n > 0);
+		if(ipv6) {
+			/* switch linklocal flag */
+			if(linklocal) {
+				linklocal = 0;
+				--deviceIndex;
+			} else {
+				linklocal = 1;
+			}
+		}
 	}
-	close(s);
+error:
+	closesocket(sudp);
 	return devlist;
 }
 
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h
index 915b002..a5c622b 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h
@@ -1,15 +1,58 @@
-/* $Id: minissdpc.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */
+/* $Id: minissdpc.h,v 1.7 2015/10/08 16:15:47 nanard Exp $ */
 /* Project: miniupnp
  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
  * Author: Thomas Bernard
- * Copyright (c) 2005-2007 Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
  * This software is subjects to the conditions detailed
  * in the LICENCE file provided within this distribution */
 #ifndef MINISSDPC_H_INCLUDED
 #define MINISSDPC_H_INCLUDED
 
-struct UPNPDev *
-getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath);
+#include "miniupnpc_declspec.h"
+#include "upnpdev.h"
+
+/* error codes : */
+#define MINISSDPC_SUCCESS (0)
+#define MINISSDPC_UNKNOWN_ERROR (-1)
+#define MINISSDPC_SOCKET_ERROR (-101)
+#define MINISSDPC_MEMORY_ERROR (-102)
+#define MINISSDPC_INVALID_INPUT (-103)
+#define MINISSDPC_INVALID_SERVER_REPLY (-104)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
+
+MINIUPNP_LIBSPEC struct UPNPDev *
+getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error);
+
+MINIUPNP_LIBSPEC int
+connectToMiniSSDPD(const char * socketpath);
+
+MINIUPNP_LIBSPEC int
+disconnectFromMiniSSDPD(int fd);
+
+MINIUPNP_LIBSPEC int
+requestDevicesFromMiniSSDPD(int fd, const char * devtype);
+
+MINIUPNP_LIBSPEC struct UPNPDev *
+receiveDevicesFromMiniSSDPD(int fd, int * error);
+
+#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
+
+MINIUPNP_LIBSPEC struct UPNPDev *
+ssdpDiscoverDevices(const char * const deviceTypes[],
+                    int delay, const char * multicastif,
+                    int localport,
+                    int ipv6, unsigned char ttl,
+                    int * error,
+                    int searchalltypes);
+
+#ifdef __cplusplus
+}
+#endif
 
 #endif
 
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c
index a8a21f4..2dc5c95 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c
@@ -1,26 +1,11 @@
-/* $Id: miniupnpc.c,v 1.115 2013/12/13 12:02:24 nanard Exp $ */
-/* Project : miniupnp
+/* $Id: miniupnpc.c,v 1.149 2016/02/09 09:50:46 nanard Exp $ */
+/* vim: tabstop=4 shiftwidth=4 noexpandtab
+ * Project : miniupnp
  * Web : http://miniupnp.free.fr/
  * Author : Thomas BERNARD
- * copyright (c) 2005-2013 Thomas Bernard
+ * copyright (c) 2005-2016 Thomas Bernard
  * This software is subjet to the conditions detailed in the
  * provided LICENSE file. */
-#define __EXTENSIONS__ 1
-#if !defined(MACOSX) && !defined(__sun)
-#if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__)
-#ifndef __cplusplus
-#define _XOPEN_SOURCE 600
-#endif
-#endif
-#ifndef __BSD_VISIBLE
-#define __BSD_VISIBLE 1
-#endif
-#endif
-
-#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(MACOSX) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun)
-#define HAS_IP_MREQN
-#endif
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -63,25 +48,11 @@
 #include <errno.h>
 #define closesocket close
 #endif /* #else _WIN32 */
-#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
-#include <sys/time.h>
-#endif
-#if defined(__amigaos__) || defined(__amigaos4__)
-/* Amiga OS specific stuff */
-#define TIMEVAL struct timeval
+#ifdef __GNU__
+#define MAXHOSTNAMELEN 64
 #endif
 
 
-#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN)
-/* Several versions of glibc don't define this structure, define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */
-struct ip_mreqn
-{
-	struct in_addr	imr_multiaddr;		/* IP multicast address of group */
-	struct in_addr	imr_address;		/* local IP address of interface */
-	int		imr_ifindex;		/* Interface index */
-};
-#endif
-
 #include "miniupnpc.h"
 #include "minissdpc.h"
 #include "miniwget.h"
@@ -89,13 +60,9 @@ struct ip_mreqn
 #include "minixml.h"
 #include "upnpcommands.h"
 #include "connecthostport.h"
-#include "receivedata.h"
 
-#ifdef _WIN32
-#define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, WSAGetLastError());
-#else
-#define PRINT_SOCKET_ERROR(x) perror(x)
-#endif
+/* compare the begining of a string with a constant string */
+#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
 
 #ifndef MAXHOSTNAMELEN
 #define MAXHOSTNAMELEN 64
@@ -105,8 +72,27 @@ struct ip_mreqn
 #define SERVICEPREFIX "u"
 #define SERVICEPREFIX2 'u'
 
+/* check if an ip address is a private (LAN) address
+ * see https://tools.ietf.org/html/rfc1918 */
+static int is_rfc1918addr(const char * addr)
+{
+	/* 192.168.0.0     -   192.168.255.255 (192.168/16 prefix) */
+	if(COMPARE(addr, "192.168."))
+		return 1;
+	/* 10.0.0.0        -   10.255.255.255  (10/8 prefix) */
+	if(COMPARE(addr, "10."))
+		return 1;
+	/* 172.16.0.0      -   172.31.255.255  (172.16/12 prefix) */
+	if(COMPARE(addr, "172.")) {
+		int i = atoi(addr + 4);
+		if((16 <= i) && (i <= 31))
+			return 1;
+	}
+	return 0;
+}
+
 /* 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 */
@@ -137,73 +123,94 @@ char * simpleUPnPcommand2(int s, const char * url, const char * service,
 	char * path;
 	char soapact[128];
 	char soapbody[2048];
+	int soapbodylen;
 	char * buf;
-    int n;
+	int n;
+	int status_code;
 
 	*bufsize = 0;
 	snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
 	if(args==NULL)
 	{
-		/*soapbodylen = */snprintf(soapbody, sizeof(soapbody),
-						"<?xml version=\"1.0\"?>\r\n"
-	    	              "<" SOAPPREFIX ":Envelope "
+		soapbodylen = snprintf(soapbody, sizeof(soapbody),
+						  "<?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\">"
 						  "</" SERVICEPREFIX ":%s>"
 						  "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
-					 	  "\r\n", action, service, action);
+						  "\r\n", action, service, action);
+		if ((unsigned int)soapbodylen >= sizeof(soapbody))
+			return NULL;
 	}
 	else
 	{
 		char * p;
 		const char * pe, * pv;
-		int soapbodylen;
+		const char * const pend = soapbody + sizeof(soapbody);
 		soapbodylen = snprintf(soapbody, sizeof(soapbody),
 						"<?xml version=\"1.0\"?>\r\n"
-	    	            "<" SOAPPREFIX ":Envelope "
+						"<" 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\">",
 						action, service);
+		if ((unsigned int)soapbodylen >= sizeof(soapbody))
+			return NULL;
 		p = soapbody + soapbodylen;
 		while(args->elt)
 		{
-			/* check that we are never overflowing the string... */
-			if(soapbody + sizeof(soapbody) <= p + 100)
-			{
-				/* we keep a margin of at least 100 bytes */
+			if(p >= pend) /* check for space to write next byte */
 				return NULL;
-			}
 			*(p++) = '<';
+
 			pe = args->elt;
-			while(*pe)
+			while(p < pend && *pe)
 				*(p++) = *(pe++);
+
+			if(p >= pend) /* check for space to write next byte */
+				return NULL;
 			*(p++) = '>';
+
 			if((pv = args->val))
 			{
-				while(*pv)
+				while(p < pend && *pv)
 					*(p++) = *(pv++);
 			}
+
+			if((p+2) > pend) /* check for space to write next 2 bytes */
+				return NULL;
 			*(p++) = '<';
 			*(p++) = '/';
+
 			pe = args->elt;
-			while(*pe)
+			while(p < pend && *pe)
 				*(p++) = *(pe++);
+
+			if(p >= pend) /* check for space to write next byte */
+				return NULL;
 			*(p++) = '>';
+
 			args++;
 		}
+		if((p+4) > pend) /* check for space to write next 4 bytes */
+			return NULL;
 		*(p++) = '<';
 		*(p++) = '/';
 		*(p++) = SERVICEPREFIX2;
 		*(p++) = ':';
+
 		pe = action;
-		while(*pe)
+		while(p < pend && *pe)
 			*(p++) = *(pe++);
+
 		strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
-		        soapbody + sizeof(soapbody) - p);
+		        pend - p);
+		if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */
+			return NULL;
 	}
 	if(!parseURL(url, hostname, &port, &path, NULL)) return NULL;
 	if(s < 0) {
@@ -223,11 +230,15 @@ char * simpleUPnPcommand2(int s, const char * url, const char * service,
 		return NULL;
 	}
 
-	buf = getHTTPResponse(s, bufsize);
+	buf = getHTTPResponse(s, bufsize, &status_code);
 #ifdef DEBUG
 	if(*bufsize > 0 && buf)
 	{
-		printf("SOAP Response :\n%.*s\n", *bufsize, buf);
+		printf("HTTP %d SOAP Response :\n%.*s\n", status_code, *bufsize, buf);
+	}
+	else
+	{
+		printf("HTTP %d, empty SOAP response. size=%d\n", status_code, *bufsize);
 	}
 #endif
 	closesocket(s);
@@ -260,125 +271,27 @@ char * simpleUPnPcommand(int s, const char * url, const char * service,
 	return buf;
 }
 
-/* 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 */
-static 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;	/* end of the "header" (position of the colon) */
-	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');*/
-					/* skip the colon and white spaces */
-					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++;
-	}
-}
-
-/* port upnp discover : SSDP protocol */
-#define PORT 1900
-#define XSTR(s) STR(s)
-#define STR(s) #s
-#define UPNP_MCAST_ADDR "239.255.255.250"
-/* for IPv6 */
-#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
-#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
-
-/* upnpDiscover() :
+/* upnpDiscoverDevices() :
  * return a chained list of all devices found or NULL if
  * no devices was found.
  * It is up to the caller to free the chained list
- * delay is in millisecond (poll) */
-LIBSPEC struct UPNPDev *
-upnpDiscover(int delay, const char * multicastif,
-             const char * minissdpdsock, int sameport,
-             int ipv6,
-             int * error)
+ * delay is in millisecond (poll).
+ * UDA v1.1 says :
+ *   The TTL for the IP packet SHOULD default to 2 and
+ *   SHOULD be configurable. */
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscoverDevices(const char * const deviceTypes[],
+                    int delay, const char * multicastif,
+                    const char * minissdpdsock, int localport,
+                    int ipv6, unsigned char ttl,
+                    int * error,
+                    int searchalltypes)
 {
 	struct UPNPDev * tmp;
 	struct UPNPDev * devlist = 0;
-	unsigned int scope_id = 0;
-	int opt = 1;
-	static const char MSearchMsgFmt[] =
-	"M-SEARCH * HTTP/1.1\r\n"
-	"HOST: %s:" XSTR(PORT) "\r\n"
-	"ST: %s\r\n"
-	"MAN: \"ssdp:discover\"\r\n"
-	"MX: %u\r\n"
-	"\r\n";
-	static const char * const deviceList[] = {
-#if 0
-		"urn:schemas-upnp-org:device:InternetGatewayDevice:2",
-		"urn:schemas-upnp-org:service:WANIPConnection:2",
-#endif
-		"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 deviceIndex = 0;
-	char bufr[1536];	/* reception and emission buffer */
-	int sudp;
-	int n;
-	struct sockaddr_storage sockudp_r;
-	unsigned int mx;
-#ifdef NO_GETADDRINFO
-	struct sockaddr_storage sockudp_w;
-#else
-	int rv;
-	struct addrinfo hints, *servinfo, *p;
-#endif
-#ifdef _WIN32
-	MIB_IPFORWARDROW ip_forward;
-#endif
-	int linklocal = 1;
+#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
+	int deviceIndex;
+#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
 
 	if(error)
 		*error = UPNPDISCOVER_UNKNOWN_ERROR;
@@ -386,464 +299,214 @@ upnpDiscover(int delay, const char * multicastif,
 	/* first try to get infos from minissdpd ! */
 	if(!minissdpdsock)
 		minissdpdsock = "/var/run/minissdpd.sock";
-	while(!devlist && deviceList[deviceIndex]) {
-		devlist = getDevicesFromMiniSSDPD(deviceList[deviceIndex],
-		                                  minissdpdsock);
-		/* We return what we have found if it was not only a rootdevice */
-		if(devlist && !strstr(deviceList[deviceIndex], "rootdevice")) {
-			if(error)
-				*error = UPNPDISCOVER_SUCCESS;
-			return devlist;
-		}
-		deviceIndex++;
-	}
-	deviceIndex = 0;
-#endif
-	/* fallback to direct discovery */
-#ifdef _WIN32
-	sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
-#else
-	sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
-#endif
-	if(sudp < 0)
-	{
-		if(error)
-			*error = UPNPDISCOVER_SOCKET_ERROR;
-		PRINT_SOCKET_ERROR("socket");
-		return NULL;
-	}
-	/* reception */
-	memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
-	if(ipv6) {
-		struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
-		p->sin6_family = AF_INET6;
-		if(sameport)
-			p->sin6_port = htons(PORT);
-		p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
-	} else {
-		struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
-		p->sin_family = AF_INET;
-		if(sameport)
-			p->sin_port = htons(PORT);
-		p->sin_addr.s_addr = INADDR_ANY;
-	}
-#ifdef _WIN32
-/* This code could help us to use the right Network interface for
- * SSDP multicast traffic */
-/* Get IP associated with the index given in the ip_forward struct
- * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
-	if(!ipv6
-	   && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
-		DWORD dwRetVal = 0;
-		PMIB_IPADDRTABLE pIPAddrTable;
-		DWORD dwSize = 0;
+	for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
+		struct UPNPDev * minissdpd_devlist;
+		int only_rootdevice = 1;
+		minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
+		                                            minissdpdsock, 0);
+		if(minissdpd_devlist) {
 #ifdef DEBUG
-		IN_ADDR IPAddr;
-#endif
-		int i;
-#ifdef DEBUG
-		printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop);
-#endif
-		pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE));
-		if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
-			free(pIPAddrTable);
-			pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
-		}
-		if(pIPAddrTable) {
-			dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
+			printf("returned by MiniSSDPD: %s\t%s\n",
+			       minissdpd_devlist->st, minissdpd_devlist->descURL);
+#endif /* DEBUG */
+			if(!strstr(minissdpd_devlist->st, "rootdevice"))
+				only_rootdevice = 0;
+			for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) {
 #ifdef DEBUG
-			printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
-#endif
-			for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
-#ifdef DEBUG
-				printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
-				IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
-				printf("\tIP Address[%d]:     \t%s\n", i, inet_ntoa(IPAddr) );
-				IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
-				printf("\tSubnet Mask[%d]:    \t%s\n", i, inet_ntoa(IPAddr) );
-				IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
-				printf("\tBroadCast[%d]:      \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
-				printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
-				printf("\tType and State[%d]:", i);
-				printf("\n");
-#endif
-				if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) {
-					/* Set the address of this interface to be used */
-					struct in_addr mc_if;
-					memset(&mc_if, 0, sizeof(mc_if));
-					mc_if.s_addr = pIPAddrTable->table[i].dwAddr;
-					if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
-						PRINT_SOCKET_ERROR("setsockopt");
-					}
-					((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
-#ifndef DEBUG
-					break;
-#endif
-				}
+				printf("returned by MiniSSDPD: %s\t%s\n",
+				       tmp->pNext->st, tmp->pNext->descURL);
+#endif /* DEBUG */
+				if(!strstr(tmp->st, "rootdevice"))
+					only_rootdevice = 0;
 			}
-			free(pIPAddrTable);
-			pIPAddrTable = NULL;
+			tmp->pNext = devlist;
+			devlist = minissdpd_devlist;
+			if(!searchalltypes && !only_rootdevice)
+				break;
 		}
 	}
-#endif
-
-#ifdef _WIN32
-	if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
-#else
-	if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
-#endif
-	{
-		if(error)
-			*error = UPNPDISCOVER_SOCKET_ERROR;
-		PRINT_SOCKET_ERROR("setsockopt");
-		return NULL;
-	}
-
-	if(multicastif)
-	{
-		if(ipv6) {
-#if !defined(_WIN32)
-			/* according to MSDN, if_nametoindex() is supported since
-			 * MS Windows Vista and MS Windows Server 2008.
-			 * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
-			unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
-			if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(&ifindex)) < 0)
-			{
-				PRINT_SOCKET_ERROR("setsockopt");
-			}
-#else
-#ifdef DEBUG
-			printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
-#endif
-#endif
-		} else {
-			struct in_addr mc_if;
-			mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
-			if(mc_if.s_addr != INADDR_NONE)
-			{
-				((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
-				if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
-				{
-					PRINT_SOCKET_ERROR("setsockopt");
-				}
-			} else {
-#ifdef HAS_IP_MREQN
-				/* was not an ip address, try with an interface name */
-				struct ip_mreqn reqn;	/* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
-				memset(&reqn, 0, sizeof(struct ip_mreqn));
-				reqn.imr_ifindex = if_nametoindex(multicastif);
-				if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
-				{
-					PRINT_SOCKET_ERROR("setsockopt");
-				}
-#else
-#ifdef DEBUG
-				printf("Setting of multicast interface not supported with interface name.\n");
-#endif
-#endif
-			}
+	for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) {
+		/* We return what we have found if it was not only a rootdevice */
+		if(!strstr(tmp->st, "rootdevice")) {
+			if(error)
+				*error = UPNPDISCOVER_SUCCESS;
+			return devlist;
 		}
 	}
+#endif	/* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
 
-	/* Avant d'envoyer le paquet on bind pour recevoir la reponse */
-    if (bind(sudp, (const struct sockaddr *)&sockudp_r,
-	         ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
+	/* direct discovery if minissdpd responses are not sufficient */
 	{
-		if(error)
-			*error = UPNPDISCOVER_SOCKET_ERROR;
-        PRINT_SOCKET_ERROR("bind");
-		closesocket(sudp);
-		return NULL;
-    }
-
-	if(error)
-		*error = UPNPDISCOVER_SUCCESS;
-	/* Calculating maximum response time in seconds */
-	mx = ((unsigned int)delay) / 1000u;
-	if(mx == 0) {
-		mx = 1;
-		delay = 1000;
-	}
-	/* receiving SSDP response packet */
-	for(n = 0; deviceList[deviceIndex]; deviceIndex++)
-	{
-	if(n == 0)
-	{
-		/* sending the SSDP M-SEARCH packet */
-		n = snprintf(bufr, sizeof(bufr),
-		             MSearchMsgFmt,
-		             ipv6 ?
-		             (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" :  "[" UPNP_MCAST_SL_ADDR "]")
-		             : UPNP_MCAST_ADDR,
-		             deviceList[deviceIndex], mx);
-#ifdef DEBUG
-		printf("Sending %s", bufr);
-#endif
-#ifdef NO_GETADDRINFO
-		/* the following code is not using getaddrinfo */
-		/* emission */
-		memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
-		if(ipv6) {
-			struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
-			p->sin6_family = AF_INET6;
-			p->sin6_port = htons(PORT);
-			inet_pton(AF_INET6,
-			          linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
-			          &(p->sin6_addr));
-		} else {
-			struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
-			p->sin_family = AF_INET;
-			p->sin_port = htons(PORT);
-			p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
-		}
-		n = sendto(sudp, bufr, n, 0,
-		           &sockudp_w,
-		           ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
-		if (n < 0) {
-			if(error)
-				*error = UPNPDISCOVER_SOCKET_ERROR;
-			PRINT_SOCKET_ERROR("sendto");
-			break;
-		}
-#else /* #ifdef NO_GETADDRINFO */
-		memset(&hints, 0, sizeof(hints));
-		hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */
-		hints.ai_socktype = SOCK_DGRAM;
-		/*hints.ai_flags = */
-		if ((rv = getaddrinfo(ipv6
-		                      ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
-		                      : UPNP_MCAST_ADDR,
-		                      XSTR(PORT), &hints, &servinfo)) != 0) {
-			if(error)
-				*error = UPNPDISCOVER_SOCKET_ERROR;
-#ifdef _WIN32
-		    fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
-#else
-		    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
-#endif
-			break;
-		}
-		for(p = servinfo; p; p = p->ai_next) {
-			n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen);
-			if (n < 0) {
-#ifdef DEBUG
-				char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
-				if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
-						sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
-					fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
-				}
-#endif
-				PRINT_SOCKET_ERROR("sendto");
-				continue;
-			}
-		}
-		freeaddrinfo(servinfo);
-		if(n < 0) {
-			if(error)
-				*error = UPNPDISCOVER_SOCKET_ERROR;
-			break;
-		}
-#endif /* #ifdef NO_GETADDRINFO */
-	}
-	/* Waiting for SSDP REPLY packet to M-SEARCH */
-	n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
-	if (n < 0) {
-		/* error */
-		if(error)
-			*error = UPNPDISCOVER_SOCKET_ERROR;
-		break;
-	} else if (n == 0) {
-		/* no data or Time Out */
-		if (devlist) {
-			/* no more device type to look for... */
-			if(error)
-				*error = UPNPDISCOVER_SUCCESS;
-			break;
-		}
-		if(ipv6) {
-			if(linklocal) {
-				linklocal = 0;
-				--deviceIndex;
-			} else {
-				linklocal = 1;
-			}
-		}
-	} else {
-		const char * descURL=NULL;
-		int urlsize=0;
-		const char * st=NULL;
-		int stsize=0;
-        /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
-		parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
-		if(st&&descURL)
-		{
-#ifdef DEBUG
-			printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
-			       stsize, st, urlsize, descURL);
-#endif
-			for(tmp=devlist; tmp; tmp = tmp->pNext) {
-				if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
-				   tmp->descURL[urlsize] == '\0' &&
-				   memcmp(tmp->st, st, stsize) == 0 &&
-				   tmp->st[stsize] == '\0')
-					break;
-			}
-			/* at the exit of the loop above, tmp is null if
-			 * no duplicate device was found */
-			if(tmp)
-				continue;
-			tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
-			if(!tmp) {
-				/* memory allocation error */
-				if(error)
-					*error = UPNPDISCOVER_MEMORY_ERROR;
-				break;
-			}
-			tmp->pNext = devlist;
-			tmp->descURL = tmp->buffer;
-			tmp->st = tmp->buffer + 1 + urlsize;
-			memcpy(tmp->buffer, descURL, urlsize);
-			tmp->buffer[urlsize] = '\0';
-			memcpy(tmp->buffer + urlsize + 1, st, stsize);
-			tmp->buffer[urlsize+1+stsize] = '\0';
-			tmp->scope_id = scope_id;
-			devlist = tmp;
+		struct UPNPDev * discovered_devlist;
+		discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport,
+		                                         ipv6, ttl, error, searchalltypes);
+		if(devlist == NULL)
+			devlist = discovered_devlist;
+		else {
+			for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext);
+			tmp->pNext = discovered_devlist;
 		}
 	}
-	}
-	closesocket(sudp);
 	return devlist;
 }
 
-/* freeUPNPDevlist() should be used to
- * free the chained list returned by upnpDiscover() */
-LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist)
+/* upnpDiscover() Discover IGD device */
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscover(int delay, const char * multicastif,
+             const char * minissdpdsock, int localport,
+             int ipv6, unsigned char ttl,
+             int * error)
 {
-	struct UPNPDev * next;
-	while(devlist)
-	{
-		next = devlist->pNext;
-		free(devlist);
-		devlist = next;
-	}
+	static const char * const deviceList[] = {
+#if 0
+		"urn:schemas-upnp-org:device:InternetGatewayDevice:2",
+		"urn:schemas-upnp-org:service:WANIPConnection:2",
+#endif
+		"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
+		"urn:schemas-upnp-org:service:WANIPConnection:1",
+		"urn:schemas-upnp-org:service:WANPPPConnection:1",
+		"upnp:rootdevice",
+		/*"ssdp:all",*/
+		0
+	};
+	return upnpDiscoverDevices(deviceList,
+	                           delay, multicastif, minissdpdsock, localport,
+	                           ipv6, ttl, error, 0);
 }
 
-static void
-url_cpy_or_cat(char * dst, const char * src, int n)
+/* upnpDiscoverAll() Discover all UPnP devices */
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscoverAll(int delay, const char * multicastif,
+                const char * minissdpdsock, int localport,
+                int ipv6, unsigned char ttl,
+                int * error)
 {
-	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);
-	}
+	static const char * const deviceList[] = {
+		/*"upnp:rootdevice",*/
+		"ssdp:all",
+		0
+	};
+	return upnpDiscoverDevices(deviceList,
+	                           delay, multicastif, minissdpdsock, localport,
+	                           ipv6, ttl, error, 0);
 }
 
-/* Prepare the Urls for usage...
- */
-LIBSPEC void
-GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
-            const char * descURL, unsigned int scope_id)
+/* upnpDiscoverDevice() Discover a specific device */
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
+                const char * minissdpdsock, int localport,
+                int ipv6, unsigned char ttl,
+                int * error)
 {
+	const char * const deviceList[] = {
+		device,
+		0
+	};
+	return upnpDiscoverDevices(deviceList,
+	                           delay, multicastif, minissdpdsock, localport,
+	                           ipv6, ttl, error, 0);
+}
+
+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
+#if defined(IF_NAMESIZE) && !defined(_WIN32)
 	char ifname[IF_NAMESIZE];
-#else
+#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
 	char scope_str[8];
-#endif
-
-	n1 = strlen(data->urlbase);
-	if(n1==0)
-		n1 = strlen(descURL);
+#endif	/* defined(IF_NAMESIZE) && !defined(_WIN32) */
+
+	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 defined(IF_NAMESIZE) && !defined(_WIN32)
 		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);
-#endif
+#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
+		/* under windows, scope is numerical */
+		l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
+#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
 	}
-	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
+#if defined(IF_NAMESIZE) && !defined(_WIN32)
 				memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
 				memcpy(p, "%25", 3);
 				memcpy(p + 3, ifname, strlen(ifname));
-#else
+				n += 3 + strlen(ifname);
+#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
 				memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
 				memcpy(p, "%25", 3);
 				memcpy(p + 3, scope_str, strlen(scope_str));
-#endif
+				n += 3 + strlen(scope_str);
+#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
 			}
 		}
 	}
-	strncpy(urls->controlURL, urls->ipcondescURL, n2);
-	strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3);
-	strncpy(urls->controlURL_6FC, urls->ipcondescURL, n4);
-
-	url_cpy_or_cat(urls->ipcondescURL, data->first.scpdurl, n1);
-
-	url_cpy_or_cat(urls->controlURL, data->first.controlurl, n2);
+	if(url[0] != '/')
+		s[n++] = '/';
+	memcpy(s + n, url, l - n);
+	return s;
+}
 
-	url_cpy_or_cat(urls->controlURL_CIF, data->CIF.controlurl, n3);
+/* 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_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)
@@ -869,9 +532,9 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
 	UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
 	                   status, &uptime, NULL);
 	if(0 == strcmp("Connected", status))
-	{
 		return 1;
-	}
+	else if(0 == strcmp("Up", status))	/* Also accept "Up" */
+		return 1;
 	else
 		return 0;
 }
@@ -887,10 +550,10 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
  *     3 = an UPnP device has been found but was not recognized as an IGD
  *
  * In any positive non zero return case, the urls and data structures
- * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
+ * passed as parameters are set. Dont 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,
@@ -907,6 +570,9 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
 	int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
 	int n_igd = 0;
 	char extIpAddr[16];
+	char myLanAddr[40];
+	int status_code = -1;
+
 	if(!devlist)
 	{
 #ifdef DEBUG
@@ -929,8 +595,8 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
 		/* we should choose an internet gateway device.
 		 * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
 		desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size),
-		                               lanaddr, lanaddrlen,
-		                               dev->scope_id);
+		                               myLanAddr, sizeof(myLanAddr),
+		                               dev->scope_id, &status_code);
 #ifdef DEBUG
 		if(!desc[i].xml)
 		{
@@ -942,11 +608,13 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
 			memset(data, 0, sizeof(struct IGDdatas));
 			memset(urls, 0, sizeof(struct UPNPUrls));
 			parserootdesc(desc[i].xml, desc[i].size, data);
-			if(0==strcmp(data->CIF.servicetype,
-			   "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"))
+			if(COMPARE(data->CIF.servicetype,
+			           "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:"))
 			{
 				desc[i].is_igd = 1;
 				n_igd++;
+				if(lanaddr)
+					strncpy(lanaddr, myLanAddr, lanaddrlen);
 			}
 		}
 	}
@@ -962,20 +630,25 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
 				parserootdesc(desc[i].xml, desc[i].size, data);
 				if(desc[i].is_igd || state >= 3 )
 				{
+				  int is_connected;
+
 				  GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
 
 				  /* in state 2 and 3 we dont test if device is connected ! */
 				  if(state >= 2)
 				    goto free_and_return;
+				  is_connected = UPNPIGD_IsConnected(urls, data);
 #ifdef DEBUG
 				  printf("UPNPIGD_IsConnected(%s) = %d\n",
-				     urls->controlURL,
-			         UPNPIGD_IsConnected(urls, data));
+				     urls->controlURL, is_connected);
 #endif
 				  /* checks that status is connected AND there is a external IP address assigned */
-				  if(UPNPIGD_IsConnected(urls, data)
-				     && (UPNP_GetExternalIPAddress(urls->controlURL,  data->first.servicetype, extIpAddr) == 0))
-					goto free_and_return;
+				  if(is_connected &&
+				     (UPNP_GetExternalIPAddress(urls->controlURL,  data->first.servicetype, extIpAddr) == 0)) {
+					if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0')
+					   && (0 != strcmp(extIpAddr, "0.0.0.0")))
+					  goto free_and_return;
+				  }
 				  FreeUPNPUrls(urls);
 				  if(data->second.servicetype[0] != '\0') {
 #ifdef DEBUG
@@ -987,14 +660,17 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
 				    memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service));
 				    memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service));
 				    GetUPNPUrls(urls, data, dev->descURL, dev->scope_id);
+				    is_connected = UPNPIGD_IsConnected(urls, data);
 #ifdef DEBUG
 				    printf("UPNPIGD_IsConnected(%s) = %d\n",
-				       urls->controlURL,
-			           UPNPIGD_IsConnected(urls, data));
-#endif
-				    if(UPNPIGD_IsConnected(urls, data)
-				       && (UPNP_GetExternalIPAddress(urls->controlURL,  data->first.servicetype, extIpAddr) == 0))
-					  goto free_and_return;
+				       urls->controlURL, is_connected);
+#endif
+				    if(is_connected &&
+				       (UPNP_GetExternalIPAddress(urls->controlURL,  data->first.servicetype, extIpAddr) == 0)) {
+					  if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0')
+					     && (0 != strcmp(extIpAddr, "0.0.0.0")))
+					    goto free_and_return;
+				    }
 				    FreeUPNPUrls(urls);
 				  }
 				}
@@ -1028,8 +704,9 @@ UPNP_GetIGDFromUrl(const char * rootdescurl,
 {
 	char * descXML;
 	int descXMLsize = 0;
+
 	descXML = miniwget_getaddr(rootdescurl, &descXMLsize,
-	   	                       lanaddr, lanaddrlen, 0);
+	                           lanaddr, lanaddrlen, 0, NULL);
 	if(descXML) {
 		memset(data, 0, sizeof(struct IGDdatas));
 		memset(urls, 0, sizeof(struct UPNPUrls));
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h
index b0d5d7f..51aaf5b 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h
@@ -1,15 +1,16 @@
-/* $Id: miniupnpc.h,v 1.35 2014/01/31 13:26:34 nanard Exp $ */
+/* $Id: miniupnpc.h,v 1.50 2016/04/19 21:06:21 nanard Exp $ */
 /* Project: miniupnp
  * http://miniupnp.free.fr/
  * Author: Thomas Bernard
- * Copyright (c) 2005-2012 Thomas Bernard
+ * Copyright (c) 2005-2016 Thomas Bernard
  * This software is subjects to the conditions detailed
  * in the LICENCE file provided within this distribution */
 #ifndef MINIUPNPC_H_INCLUDED
 #define MINIUPNPC_H_INCLUDED
 
-#include "declspec.h"
+#include "miniupnpc_declspec.h"
 #include "igd_desc_parse.h"
+#include "upnpdev.h"
 
 /* error codes : */
 #define UPNPDISCOVER_SUCCESS (0)
@@ -18,8 +19,14 @@
 #define UPNPDISCOVER_MEMORY_ERROR (-102)
 
 /* versions : */
-#define MINIUPNPC_VERSION	"1.9"
-#define MINIUPNPC_API_VERSION	10
+#define MINIUPNPC_VERSION	"2.0.20170509"
+#define MINIUPNPC_API_VERSION	16
+
+/* Source port:
+   Using "1" as an alias for 1900 for backwards compatability
+   (presuming one would have used that for the "sameport" parameter) */
+#define UPNP_LOCAL_PORT_ANY     0
+#define UPNP_LOCAL_PORT_SAME    1
 
 #ifdef __cplusplus
 extern "C" {
@@ -33,14 +40,6 @@ simpleUPnPcommand(int, const char *, const char *,
                   const char *, struct UPNParg *,
                   int *);
 
-struct UPNPDev {
-	struct UPNPDev * pNext;
-	char * descURL;
-	char * st;
-	unsigned int scope_id;
-	char buffer[2];
-};
-
 /* upnpDiscover()
  * discover UPnP devices on the network.
  * The discovered devices are returned as a chained list.
@@ -52,21 +51,43 @@ struct UPNPDev {
  * is NULL.
  * If multicastif is not NULL, it will be used instead of the default
  * 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 *
+ * If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent
+ * from the source port 1900 (same as destination port), if set to
+ * UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will
+ * be attempted as the source port.
+ * "searchalltypes" parameter is useful when searching several types,
+ * if 0, the discovery will stop with the first type returning results.
+ * TTL should default to 2. */
+MINIUPNP_LIBSPEC struct UPNPDev *
 upnpDiscover(int delay, const char * multicastif,
-             const char * minissdpdsock, int sameport,
-             int ipv6,
+             const char * minissdpdsock, int localport,
+             int ipv6, unsigned char ttl,
              int * error);
-/* freeUPNPDevlist()
- * free list returned by upnpDiscover() */
-LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
+
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscoverAll(int delay, const char * multicastif,
+                const char * minissdpdsock, int localport,
+                int ipv6, unsigned char ttl,
+                int * error);
+
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
+                const char * minissdpdsock, int localport,
+                int ipv6, unsigned char ttl,
+                int * error);
+
+MINIUPNP_LIBSPEC struct UPNPDev *
+upnpDiscoverDevices(const char * const deviceTypes[],
+                    int delay, const char * multicastif,
+                    const char * minissdpdsock, int localport,
+                    int ipv6, unsigned char ttl,
+                    int * error,
+                    int searchalltypes);
 
 /* 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
@@ -94,7 +115,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,
@@ -102,24 +123,25 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
 
 /* UPNP_GetIGDFromUrl()
  * Used when skipping the discovery process.
+ * When succeding, urls, data, and lanaddr arguments are set.
  * 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
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc_declspec.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc_declspec.h
new file mode 100644
index 0000000..40adb92
--- /dev/null
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc_declspec.h
@@ -0,0 +1,21 @@
+#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED
+#define MINIUPNPC_DECLSPEC_H_INCLUDED
+
+#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB)
+	/* for windows dll */
+	#ifdef MINIUPNP_EXPORTS
+		#define MINIUPNP_LIBSPEC __declspec(dllexport)
+	#else
+		#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 MINIUPNP_LIBSPEC __attribute__ ((visibility ("default")))
+	#else
+		#define MINIUPNP_LIBSPEC
+	#endif
+#endif
+
+#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */
+
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c
index a75f55b..e5099db 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c
@@ -1,8 +1,8 @@
-/* $Id: miniwget.c,v 1.60 2013/10/07 10:03:16 nanard Exp $ */
+/* $Id: miniwget.c,v 1.77 2017/05/09 10:04:57 nanard Exp $ */
 /* Project : miniupnp
  * Website : http://miniupnp.free.fr/
  * Author : Thomas Bernard
- * Copyright (c) 2005-2013 Thomas Bernard
+ * Copyright (c) 2005-2017 Thomas Bernard
  * This software is subject to the conditions detailed in the
  * LICENCE file provided in this distribution. */
 
@@ -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
@@ -39,13 +38,16 @@
 #include <net/if.h>
 #include <netdb.h>
 #define closesocket close
-/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
- * during the connect() call */
-#define MINIUPNPC_IGNORE_EINTR
+#include <strings.h>
 #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"
@@ -63,7 +65,7 @@
  * to the length parameter.
  */
 void *
-getHTTPResponse(int s, int * size)
+getHTTPResponse(int s, int * size, int * status_code)
 {
 	char buf[2048];
 	int n;
@@ -81,13 +83,35 @@ getHTTPResponse(int s, int * size)
 	unsigned int content_buf_used = 0;
 	char chunksize_buf[32];
 	unsigned int chunksize_buf_index;
+#ifdef DEBUG
+	char * reason_phrase = NULL;
+	int reason_phrase_len = 0;
+#endif
 
+	if(status_code) *status_code = -1;
 	header_buf = malloc(header_buf_len);
+	if(header_buf == NULL)
+	{
+#ifdef DEBUG
+		fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
+#endif /* DEBUG */
+		*size = -1;
+		return NULL;
+	}
 	content_buf = malloc(content_buf_len);
+	if(content_buf == NULL)
+	{
+		free(header_buf);
+#ifdef DEBUG
+		fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
+#endif /* DEBUG */
+		*size = -1;
+		return NULL;
+	}
 	chunksize_buf[0] = '\0';
 	chunksize_buf_index = 0;
 
-	while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0)
+	while((n = receivedata(s, buf, sizeof(buf), 5000, NULL)) > 0)
 	{
 		if(endofheaders == 0)
 		{
@@ -96,7 +120,15 @@ getHTTPResponse(int s, int * size)
 			int colon=0;
 			int valuestart=0;
 			if(header_buf_used + n > header_buf_len) {
-				header_buf = realloc(header_buf, header_buf_used + n);
+				char * tmp = realloc(header_buf, header_buf_used + n);
+				if(tmp == NULL) {
+					/* memory allocation error */
+					free(header_buf);
+					free(content_buf);
+					*size = -1;
+					return NULL;
+				}
+				header_buf = tmp;
 				header_buf_len = header_buf_used + n;
 			}
 			memcpy(header_buf + header_buf_used, buf, n);
@@ -128,7 +160,7 @@ getHTTPResponse(int s, int * size)
 				continue;
 			/* parse header lines */
 			for(i = 0; i < endofheaders - 1; i++) {
-				if(colon <= linestart && header_buf[i]==':')
+				if(linestart > 0 && colon <= linestart && header_buf[i]==':')
 				{
 					colon = i;
 					while(i < (endofheaders-1)
@@ -139,7 +171,31 @@ getHTTPResponse(int s, int * size)
 				/* detecting end of line */
 				else if(header_buf[i]=='\r' || header_buf[i]=='\n')
 				{
-					if(colon > linestart && valuestart > colon)
+					if(linestart == 0 && status_code)
+					{
+						/* Status line
+						 * HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
+						int sp;
+						for(sp = 0; sp < i; sp++)
+							if(header_buf[sp] == ' ')
+							{
+								if(*status_code < 0)
+									*status_code = atoi(header_buf + sp + 1);
+								else
+								{
+#ifdef DEBUG
+									reason_phrase = header_buf + sp + 1;
+									reason_phrase_len = i - sp - 1;
+#endif
+									break;
+								}
+							}
+#ifdef DEBUG
+						printf("HTTP status code = %d, Reason phrase = %.*s\n",
+						       *status_code, reason_phrase_len, reason_phrase);
+#endif
+					}
+					else if(colon > linestart && valuestart > colon)
 					{
 #ifdef DEBUG
 						printf("header='%.*s', value='%.*s'\n",
@@ -228,16 +284,25 @@ getHTTPResponse(int s, int * size)
 							goto end_of_stream;
 						}
 					}
-					bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i);
+					/* it is guaranteed that (n >= i) */
+					bytestocopy = (chunksize < (unsigned int)(n - i))?chunksize:(unsigned int)(n - i);
 					if((content_buf_used + bytestocopy) > content_buf_len)
 					{
-						if(content_length >= (int)(content_buf_used + bytestocopy)) {
+						char * tmp;
+						if((content_length >= 0) && ((unsigned int)content_length >= (content_buf_used + bytestocopy))) {
 							content_buf_len = content_length;
 						} else {
 							content_buf_len = content_buf_used + bytestocopy;
 						}
-						content_buf = (char *)realloc((void *)content_buf,
-						                              content_buf_len);
+						tmp = realloc(content_buf, content_buf_len);
+						if(tmp == NULL) {
+							/* memory allocation error */
+							free(content_buf);
+							free(header_buf);
+							*size = -1;
+							return NULL;
+						}
+						content_buf = tmp;
 					}
 					memcpy(content_buf + content_buf_used, buf + i, bytestocopy);
 					content_buf_used += bytestocopy;
@@ -249,26 +314,35 @@ getHTTPResponse(int s, int * size)
 			{
 				/* not chunked */
 				if(content_length > 0
-				   && (int)(content_buf_used + n) > content_length) {
+				   && (content_buf_used + n) > (unsigned int)content_length) {
 					/* skipping additional bytes */
 					n = content_length - content_buf_used;
 				}
 				if(content_buf_used + n > content_buf_len)
 				{
-					if(content_length >= (int)(content_buf_used + n)) {
+					char * tmp;
+					if(content_length >= 0
+					   && (unsigned int)content_length >= (content_buf_used + n)) {
 						content_buf_len = content_length;
 					} else {
 						content_buf_len = content_buf_used + n;
 					}
-					content_buf = (char *)realloc((void *)content_buf,
-					                              content_buf_len);
+					tmp = realloc(content_buf, content_buf_len);
+					if(tmp == NULL) {
+						/* memory allocation error */
+						free(content_buf);
+						free(header_buf);
+						*size = -1;
+						return NULL;
+					}
+					content_buf = tmp;
 				}
 				memcpy(content_buf + content_buf_used, buf, n);
 				content_buf_used += n;
 			}
 		}
 		/* use the Content-Length header value if available */
-		if(content_length > 0 && (int)content_buf_used >= content_length)
+		if(content_length > 0 && content_buf_used >= (unsigned int)content_length)
 		{
 #ifdef DEBUG
 			printf("End of HTTP content\n");
@@ -294,7 +368,8 @@ static void *
 miniwget3(const char * host,
           unsigned short port, const char * path,
           int * size, char * addr_str, int addr_str_len,
-          const char * httpversion, unsigned int scope_id)
+          const char * httpversion, unsigned int scope_id,
+          int * status_code)
 {
 	char buf[2048];
     int s;
@@ -367,10 +442,15 @@ 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);
+	if ((unsigned int)len >= sizeof(buf))
+	{
+		closesocket(s);
+		return NULL;
+	}
 	sent = 0;
 	/* sending the HTTP request */
 	while(sent < len)
@@ -387,7 +467,7 @@ miniwget3(const char * host,
 			sent += n;
 		}
 	}
-	content = getHTTPResponse(s, size);
+	content = getHTTPResponse(s, size, status_code);
 	closesocket(s);
 	return content;
 }
@@ -396,18 +476,20 @@ miniwget3(const char * host,
  * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */
 static void *
 miniwget2(const char * host,
-		  unsigned short port, const char * path,
-		  int * size, char * addr_str, int addr_str_len,
-          unsigned int scope_id)
+          unsigned short port, const char * path,
+          int * size, char * addr_str, int addr_str_len,
+          unsigned int scope_id, int * status_code)
 {
 	char * respbuffer;
 
 #if 1
 	respbuffer = miniwget3(host, port, path, size,
-	                       addr_str, addr_str_len, "1.1", scope_id);
+	                       addr_str, addr_str_len, "1.1",
+	                       scope_id, status_code);
 #else
 	respbuffer = miniwget3(host, port, path, size,
-	                       addr_str, addr_str_len, "1.0", scope_id);
+	                       addr_str, addr_str_len, "1.0",
+	                       scope_id, status_code);
 	if (*size == 0)
 	{
 #ifdef DEBUG
@@ -415,7 +497,8 @@ miniwget2(const char * host,
 #endif
 		free(respbuffer);
 		respbuffer = miniwget3(host, port, path, size,
-		                       addr_str, addr_str_len, "1.1", scope_id);
+		                       addr_str, addr_str_len, "1.1",
+		                       scope_id, status_code);
 	}
 #endif
 	return respbuffer;
@@ -540,7 +623,8 @@ parseURL(const char * url,
 }
 
 void *
-miniwget(const char * url, int * size, unsigned int scope_id)
+miniwget(const char * url, int * size,
+         unsigned int scope_id, int * status_code)
 {
 	unsigned short port;
 	char * path;
@@ -553,12 +637,13 @@ miniwget(const char * url, int * size, unsigned int scope_id)
 	printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
 	       hostname, port, path, scope_id);
 #endif
-	return miniwget2(hostname, port, path, size, 0, 0, scope_id);
+	return miniwget2(hostname, port, path, size, 0, 0, scope_id, status_code);
 }
 
 void *
 miniwget_getaddr(const char * url, int * size,
-                 char * addr, int addrlen, unsigned int scope_id)
+                 char * addr, int addrlen, unsigned int scope_id,
+                 int * status_code)
 {
 	unsigned short port;
 	char * path;
@@ -573,6 +658,6 @@ miniwget_getaddr(const char * url, int * size,
 	printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
 	       hostname, port, path, scope_id);
 #endif
-	return miniwget2(hostname, port, path, size, addr, addrlen, scope_id);
+	return miniwget2(hostname, port, path, size, addr, addrlen, scope_id, status_code);
 }
 
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h
index 31bcea3..0701494 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h
@@ -1,24 +1,24 @@
-/* $Id: miniwget.h,v 1.8 2012/09/27 15:42:10 nanard Exp $ */
+/* $Id: miniwget.h,v 1.12 2016/01/24 17:24:36 nanard Exp $ */
 /* Project : miniupnp
  * Author : Thomas Bernard
- * Copyright (c) 2005-2012 Thomas Bernard
+ * Copyright (c) 2005-2016 Thomas Bernard
  * This software is subject to the conditions detailed in the
  * LICENCE file provided in this distribution.
  * */
 #ifndef MINIWGET_H_INCLUDED
 #define MINIWGET_H_INCLUDED
 
-#include "declspec.h"
+#include "miniupnpc_declspec.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-LIBSPEC void * getHTTPResponse(int s, int * size);
+MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size, int * status_code);
 
-LIBSPEC void * miniwget(const char *, int *, unsigned int);
+MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int, 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 *);
 
 int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *);
 
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c
index eb4d7d9..3e201ec 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c
@@ -1,10 +1,10 @@
-/* $Id: minixml.c,v 1.10 2012/03/05 19:42:47 nanard Exp $ */
+/* $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-2011, Thomas BERNARD
+Copyright (c) 2005-2014, Thomas BERNARD
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -113,7 +113,20 @@ static void parseelt(struct xmlparser * p)
 	const char * elementname;
 	while(p->xml < (p->xmlend - 1))
 	{
-		if((p->xml)[0]=='<' && (p->xml)[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)
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c
index 0a112bf..dad1488 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c
@@ -1,4 +1,4 @@
-/* $Id: minixmlvalid.c,v 1.6 2012/05/01 16:24:07 nanard Exp $ */
+/* $Id: minixmlvalid.c,v 1.7 2015/07/15 12:41:15 nanard Exp $ */
 /* MiniUPnP Project
  * http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
  * minixmlvalid.c :
@@ -128,6 +128,11 @@ int testxmlparser(const char * xml, int size)
 	struct xmlparser parser;
 	evtlist.n = 0;
 	evtlist.events = malloc(sizeof(struct event)*100);
+	if(evtlist.events == NULL)
+	{
+		fprintf(stderr, "Memory allocation error.\n");
+		return -1;
+	}
 	memset(&parser, 0, sizeof(parser));
 	parser.xmlstart = xml;
 	parser.xmlsize = size;
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c
index 19e3054..d1954f5 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c
@@ -1,11 +1,14 @@
-/* $Id: portlistingparse.c,v 1.6 2012/05/29 10:26:51 nanard Exp $ */
+/* $Id: portlistingparse.c,v 1.10 2016/12/16 08:53:21 nanard Exp $ */
 /* MiniUPnP project
  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
- * (c) 2011 Thomas Bernard
+ * (c) 2011-2016 Thomas Bernard
  * This software is subject to the conditions detailed
  * in the LICENCE file provided within the distribution */
 #include <string.h>
 #include <stdlib.h>
+#ifdef DEBUG
+#include <stdio.h>
+#endif /* DEBUG */
 #include "portlistingparse.h"
 #include "minixml.h"
 
@@ -52,7 +55,7 @@ startelt(void * d, const char * name, int l)
 	pdata->curelt = PortMappingEltNone;
 	for(i = 0; elements[i].str; i++)
 	{
-		if(memcmp(name, elements[i].str, l) == 0)
+		if(strlen(elements[i].str) == (size_t)l && memcmp(name, elements[i].str, l) == 0)
 		{
 			pdata->curelt = elements[i].code;
 			break;
@@ -62,7 +65,17 @@ startelt(void * d, const char * name, int l)
 	{
 		struct PortMapping * pm;
 		pm = calloc(1, sizeof(struct PortMapping));
-		LIST_INSERT_HEAD( &(pdata->head), pm, entries);
+		if(pm == NULL)
+		{
+			/* malloc error */
+#ifdef DEBUG
+			fprintf(stderr, "%s: error allocating memory",
+			        "startelt");
+#endif /* DEBUG */
+			return;
+		}
+		pm->l_next = pdata->l_head;	/* insert in list */
+		pdata->l_head = pm;
 	}
 }
 
@@ -82,7 +95,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 +147,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 +162,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);
 	}
 }
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h
index bafa2a4..661ad1f 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h
@@ -1,22 +1,16 @@
-/* $Id: portlistingparse.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */
+/* $Id: portlistingparse.h,v 1.11 2015/07/21 13:16:55 nanard Exp $ */
 /* MiniUPnP project
  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
- * (c) 2011-2012 Thomas Bernard
+ * (c) 2011-2015 Thomas Bernard
  * This software is subject to the conditions detailed
  * in the LICENCE file provided within the distribution */
 #ifndef PORTLISTINGPARSE_H_INCLUDED
 #define PORTLISTINGPARSE_H_INCLUDED
 
-#include "declspec.h"
+#include "miniupnpc_declspec.h"
 /* 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
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c
index ffbfbea..5dbd227 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c
@@ -1,16 +1,17 @@
-/* $Id: receivedata.c,v 1.5 2013/10/07 09:48:36 nanard Exp $ */
+/* $Id: receivedata.c,v 1.8 2017/04/21 10:16:45 nanard Exp $ */
 /* Project : miniupnp
  * Website : http://miniupnp.free.fr/
  * Author : Thomas Bernard
- * Copyright (c) 2011-2012 Thomas Bernard
+ * Copyright (c) 2011-2014 Thomas Bernard
  * This software is subject to the conditions detailed in the
  * LICENCE file provided in this distribution. */
 
 #include <stdio.h>
+#include <string.h>
 #ifdef _WIN32
 #include <winsock2.h>
 #include <ws2tcpip.h>
-#else
+#else /* _WIN32 */
 #include <unistd.h>
 #if defined(__amigaos__) && !defined(__amigaos4__)
 #define socklen_t int
@@ -21,13 +22,13 @@
 #include <netinet/in.h>
 #if !defined(__amigaos__) && !defined(__amigaos4__)
 #include <poll.h>
-#endif
+#endif	/* !defined(__amigaos__) && !defined(__amigaos4__) */
 #include <errno.h>
 #define MINIUPNPC_IGNORE_EINTR
-#endif
+#endif /* _WIN32 */
 
 #ifdef _WIN32
-#define PRINT_SOCKET_ERROR(x)    printf("Socket error: %s, %d\n", x, WSAGetLastError());
+#define PRINT_SOCKET_ERROR(x)    fprintf(stderr, "Socket error: %s, %d\n", x, WSAGetLastError());
 #else
 #define PRINT_SOCKET_ERROR(x) perror(x)
 #endif
@@ -39,28 +40,23 @@ receivedata(int socket,
             char * data, int length,
             int timeout, unsigned int * scope_id)
 {
-#if MINIUPNPC_GET_SRC_ADDR
-#ifdef DEBUG
-	/* to shut up valgrind about uninit value */
-	struct sockaddr_storage src_addr = {0};
-#else
+#ifdef MINIUPNPC_GET_SRC_ADDR
 	struct sockaddr_storage src_addr;
-#endif
 	socklen_t src_addr_len = sizeof(src_addr);
-#endif
+#endif	/* MINIUPNPC_GET_SRC_ADDR */
     int n;
 #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
 	/* using poll */
     struct pollfd fds[1]; /* for the poll */
 #ifdef MINIUPNPC_IGNORE_EINTR
     do {
-#endif
+#endif	/* MINIUPNPC_IGNORE_EINTR */
         fds[0].fd = socket;
         fds[0].events = POLLIN;
         n = poll(fds, 1, timeout);
 #ifdef MINIUPNPC_IGNORE_EINTR
     } while(n < 0 && errno == EINTR);
-#endif
+#endif	/* MINIUPNPC_IGNORE_EINTR */
     if(n < 0) {
         PRINT_SOCKET_ERROR("poll");
         return -1;
@@ -68,7 +64,7 @@ receivedata(int socket,
 		/* timeout */
         return 0;
     }
-#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
+#else	/* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
 	/* using select under _WIN32 and amigaos */
     fd_set socketSet;
     TIMEVAL timeval;
@@ -83,27 +79,27 @@ receivedata(int socket,
     } else if(n == 0) {
         return 0;
     }
-#endif
-#if MINIUPNPC_GET_SRC_ADDR
+#endif	/* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
+#ifdef MINIUPNPC_GET_SRC_ADDR
+	memset(&src_addr, 0, sizeof(src_addr));
 	n = recvfrom(socket, data, length, 0,
 	             (struct sockaddr *)&src_addr, &src_addr_len);
-#else
+#else	/* MINIUPNPC_GET_SRC_ADDR */
 	n = recv(socket, data, length, 0);
-#endif
+#endif	/* MINIUPNPC_GET_SRC_ADDR */
 	if(n<0) {
 		PRINT_SOCKET_ERROR("recv");
 	}
-#if MINIUPNPC_GET_SRC_ADDR
+#ifdef MINIUPNPC_GET_SRC_ADDR
 	if (src_addr.ss_family == AF_INET6) {
 		const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr;
 #ifdef DEBUG
 		printf("scope_id=%u\n", src_addr6->sin6_scope_id);
-#endif
+#endif	/* DEBUG */
 		if(scope_id)
 			*scope_id = src_addr6->sin6_scope_id;
 	}
-#endif
+#endif	/* MINIUPNPC_GET_SRC_ADDR */
 	return n;
 }
 
-
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c
index 9c9979a..1cf1ca2 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c
@@ -1,7 +1,7 @@
-/* $Id: upnpc.c,v 1.101 2014/01/31 13:18:25 nanard Exp $ */
+/* $Id: upnpc.c,v 1.116 2017/04/21 10:20:50 nanard Exp $ */
 /* Project : miniupnp
  * Author : Thomas Bernard
- * Copyright (c) 2005-2013 Thomas Bernard
+ * Copyright (c) 2005-2016 Thomas Bernard
  * This software is subject to the conditions detailed in the
  * LICENCE file provided in this distribution. */
 
@@ -16,10 +16,12 @@
 /* for IPPROTO_TCP / IPPROTO_UDP */
 #include <netinet/in.h>
 #endif
+#include <ctype.h>
 #include "miniwget.h"
 #include "miniupnpc.h"
 #include "upnpcommands.h"
 #include "upnperrors.h"
+#include "miniupnpcstrings.h"
 
 /* protofix() checks if protocol is "UDP" or "TCP"
  * returns NULL if not */
@@ -41,6 +43,22 @@ const char * protofix(const char * proto)
 	return 0;
 }
 
+/* is_int() checks if parameter is an integer or not
+ * 1 for integer
+ * 0 for not an integer */
+int is_int(char const* s)
+{
+	if(s == NULL)
+		return 0;
+	while(*s) {
+		/* #define isdigit(c) ((c) >= '0' && (c) <= '9') */
+		if(!isdigit(*s))
+			return 0;
+		s++;
+	}
+	return 1;
+}
+
 static void DisplayInfos(struct UPNPUrls * urls,
                          struct IGDdatas * data)
 {
@@ -48,7 +66,7 @@ static void DisplayInfos(struct UPNPUrls * urls,
 	char connectionType[64];
 	char status[64];
 	char lastconnerr[64];
-	unsigned int uptime;
+	unsigned int uptime = 0;
 	unsigned int brUp, brDown;
 	time_t timenow, timestarted;
 	int r;
@@ -64,9 +82,11 @@ static void DisplayInfos(struct UPNPUrls * urls,
 	else
 		printf("Status : %s, uptime=%us, LastConnectionError : %s\n",
 		       status, uptime, lastconnerr);
-	timenow = time(NULL);
-	timestarted = timenow - uptime;
-	printf("  Time started : %s", ctime(&timestarted));
+	if(uptime > 0) {
+		timenow = time(NULL);
+		timestarted = timenow - uptime;
+		printf("  Time started : %s", ctime(&timestarted));
+	}
 	if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype,
 	                                &brDown, &brUp) != UPNPCOMMAND_SUCCESS) {
 		printf("GetLinkLayerMaxBitRates failed.\n");
@@ -174,7 +194,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 +219,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,
@@ -222,84 +242,139 @@ static void NewListRedirections(struct UPNPUrls * urls,
  * 2 - get extenal ip address
  * 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)
+static int 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,
+			       int addAny)
 {
 	char externalIPAddress[40];
 	char intClient[40];
 	char intPort[6];
+	char reservedPort[6];
 	char duration[16];
 	int r;
 
 	if(!iaddr || !iport || !eport || !proto)
 	{
 		fprintf(stderr, "Wrong arguments\n");
-		return;
+		return -1;
 	}
 	proto = protofix(proto);
 	if(!proto)
 	{
 		fprintf(stderr, "invalid protocol\n");
-		return;
+		return -1;
 	}
 
-	UPNP_GetExternalIPAddress(urls->controlURL,
-	                          data->first.servicetype,
-							  externalIPAddress);
-	if(externalIPAddress[0])
-		printf("ExternalIPAddress = %s\n", externalIPAddress);
-	else
+	r = UPNP_GetExternalIPAddress(urls->controlURL,
+				      data->first.servicetype,
+				      externalIPAddress);
+	if(r!=UPNPCOMMAND_SUCCESS)
 		printf("GetExternalIPAddress failed.\n");
+	else
+		printf("ExternalIPAddress = %s\n", externalIPAddress);
 
-	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));
+	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));
+			return -2;
+	}
+	}
 
 	r = UPNP_GetSpecificPortMappingEntry(urls->controlURL,
-	                                 data->first.servicetype,
-    	                             eport, proto, NULL/*remoteHost*/,
-									 intClient, intPort, NULL/*desc*/,
-	                                 NULL/*enabled*/, duration);
-	if(r!=UPNPCOMMAND_SUCCESS)
+					     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]) {
+		return -2;
+	} 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);
 	}
+	return 0;
 }
 
-static void
+static int
 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)
 	{
 		fprintf(stderr, "invalid arguments\n");
-		return;
+		return -1;
 	}
 	proto = protofix(proto);
 	if(!proto)
 	{
 		fprintf(stderr, "protocol invalid\n");
-		return;
+		return -1;
+	}
+	r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, remoteHost);
+	if(r!=UPNPCOMMAND_SUCCESS) {
+		printf("UPNP_DeletePortMapping() failed with code : %d\n", r);
+		return -2;
+	}else {
+		printf("UPNP_DeletePortMapping() returned : %d\n", r);
 	}
-	r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, 0);
-	printf("UPNP_DeletePortMapping() returned : %d\n", r);
+	return 0;
+}
+
+static int
+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 -1;
+	}
+	proto = protofix(proto);
+	if(!proto)
+	{
+		fprintf(stderr, "protocol invalid\n");
+		return -1;
+	}
+	r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage);
+	if(r!=UPNPCOMMAND_SUCCESS) {
+		printf("UPNP_DeletePortMappingRange() failed with code : %d\n", r);
+		return -2;
+	}else {
+		printf("UPNP_DeletePortMappingRange() returned : %d\n", r);
+	}
+	return 0;
 }
 
 /* IGD:2, functions for service WANIPv6FirewallControl:1 */
@@ -481,14 +556,16 @@ int main(int argc, char ** argv)
 	char ** commandargv = 0;
 	int commandargc = 0;
 	struct UPNPDev * devlist = 0;
-	char lanaddr[64];	/* my ip address on the LAN */
+	char lanaddr[64] = "unset";	/* my ip address on the LAN */
 	int i;
 	const char * rootdescurl = 0;
 	const char * multicastif = 0;
 	const char * minissdpdpath = 0;
+	int localport = UPNP_LOCAL_PORT_ANY;
 	int retcode = 0;
 	int error = 0;
 	int ipv6 = 0;
+	unsigned char ttl = 2;	/* defaulting to 2 */
 	const char * description = 0;
 
 #ifdef _WIN32
@@ -500,7 +577,8 @@ int main(int argc, char ** argv)
 		return -1;
 	}
 #endif
-    printf("upnpc : miniupnpc library test client. (c) 2005-2013 Thomas Bernard\n");
+    printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
+	printf(" (c) 2005-2016 Thomas Bernard.\n");
     printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n"
 	       "for more information.\n");
 	/* command line processing */
@@ -517,12 +595,26 @@ int main(int argc, char ** argv)
 				rootdescurl = argv[++i];
 			else if(argv[i][1] == 'm')
 				multicastif = argv[++i];
+			else if(argv[i][1] == 'z')
+			{
+				char junk;
+				if(sscanf(argv[++i], "%d%c", &localport, &junk)!=1 ||
+					localport<0 || localport>65535 ||
+				   (localport >1 && localport < 1024))
+				{
+					fprintf(stderr, "Invalid localport '%s'\n", argv[i]);
+					localport = UPNP_LOCAL_PORT_ANY;
+					break;
+				}
+			}
 			else if(argv[i][1] == 'p')
 				minissdpdpath = argv[++i];
 			else if(argv[i][1] == '6')
 				ipv6 = 1;
 			else if(argv[i][1] == 'e')
 				description = argv[++i];
+			else if(argv[i][1] == 't')
+				ttl = (unsigned char)atoi(argv[++i]);
 			else
 			{
 				command = argv[i][1];
@@ -538,7 +630,8 @@ int main(int argc, char ** argv)
 		}
 	}
 
-	if(!command || (command == 'a' && commandargc<4)
+	if(!command
+	   || (command == 'a' && commandargc<4)
 	   || (command == 'd' && argc<2)
 	   || (command == 'r' && argc<2)
 	   || (command == 'A' && commandargc<6)
@@ -546,11 +639,13 @@ 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] -r port1 protocol1 [port2 protocol2] [...]\n\t\tAdd all redirections to the current host\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 [external_port1] protocol1 [port2 [external_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]);
 		fprintf(stderr, "       \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]);
@@ -565,13 +660,15 @@ int main(int argc, char ** argv)
 		fprintf(stderr, "  -6 : use ip v6 instead of ip v4.\n");
 		fprintf(stderr, "  -u url : bypass discovery process by providing the XML root description url.\n");
 		fprintf(stderr, "  -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n");
+		fprintf(stderr, "  -z localport : SSDP packets local (source) port (1024-65535).\n");
 		fprintf(stderr, "  -p path : use this path for MiniSSDPd socket.\n");
+		fprintf(stderr, "  -t ttl : set multicast TTL. Default value is 2.\n");
 		return 1;
 	}
 
 	if( rootdescurl
 	  || (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
-	                             0/*sameport*/, ipv6, &error)))
+	                             localport, ipv6, ttl, &error)))
 	{
 		struct UPNPDev * device;
 		struct UPNPUrls urls;
@@ -585,7 +682,7 @@ int main(int argc, char ** argv)
 					   device->descURL, device->st);
 			}
 		}
-		else
+		else if(!rootdescurl)
 		{
 			printf("upnpDiscover() error code=%d\n", error);
 		}
@@ -630,29 +727,63 @@ int main(int argc, char ** argv)
 				NewListRedirections(&urls, &data);
 				break;
 			case 'a':
-				SetRedirectAndTest(&urls, &data,
-				                   commandargv[0], commandargv[1],
-				                   commandargv[2], commandargv[3],
-				                   (commandargc > 4)?commandargv[4]:"0",
-				                   description);
+				if (SetRedirectAndTest(&urls, &data,
+						   commandargv[0], commandargv[1],
+						   commandargv[2], commandargv[3],
+						   (commandargc > 4)?commandargv[4]:"0",
+						   description, 0) < 0)
+					retcode = 2;
 				break;
 			case 'd':
-				for(i=0; i<commandargc; i+=2)
-				{
-					RemoveRedirect(&urls, &data, commandargv[i], commandargv[i+1]);
-				}
+				if (RemoveRedirect(&urls, &data, commandargv[0], commandargv[1],
+				               commandargc > 2 ? commandargv[2] : NULL) < 0)
+					retcode = 2;
+				break;
+			case 'n':	/* aNy */
+				if (SetRedirectAndTest(&urls, &data,
+						   commandargv[0], commandargv[1],
+						   commandargv[2], commandargv[3],
+						   (commandargc > 4)?commandargv[4]:"0",
+						   description, 1) < 0)
+					retcode = 2;
+				break;
+			case 'N':
+				if (commandargc < 3)
+					fprintf(stderr, "too few arguments\n");
+
+				if (RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2],
+						    commandargc > 3 ? commandargv[3] : NULL) < 0)
+					retcode = 2;
 				break;
 			case 's':
 				GetConnectionStatus(&urls, &data);
 				break;
 			case 'r':
-				for(i=0; i<commandargc; i+=2)
+				i = 0;
+				while(i<commandargc)
 				{
-					/*printf("port %s protocol %s\n", argv[i], argv[i+1]);*/
-					SetRedirectAndTest(&urls, &data,
-					                   lanaddr, commandargv[i],
-									   commandargv[i], commandargv[i+1], "0",
-					                   description);
+					if(!is_int(commandargv[i])) {
+						/* 1st parameter not an integer : error */
+						fprintf(stderr, "command -r : %s is not an port number\n", commandargv[i]);
+						retcode = 1;
+						break;
+					} else if(is_int(commandargv[i+1])){
+						/* 2nd parameter is an integer : <port> <external_port> <protocol> */
+						if (SetRedirectAndTest(&urls, &data,
+								   lanaddr, commandargv[i],
+								   commandargv[i+1], commandargv[i+2], "0",
+								   description, 0) < 0)
+							retcode = 2;
+						i+=3;	/* 3 parameters parsed */
+					} else {
+						/* 2nd parameter not an integer : <port> <protocol> */
+						if (SetRedirectAndTest(&urls, &data,
+								   lanaddr, commandargv[i],
+								   commandargv[i], commandargv[i+1], "0",
+								   description, 0) < 0)
+							retcode = 2;
+						i+=2;	/* 2 parameters parsed */
+					}
 				}
 				break;
 			case 'A':
@@ -715,6 +846,12 @@ int main(int argc, char ** argv)
 		fprintf(stderr, "No IGD UPnP Device found on the network !\n");
 		retcode = 1;
 	}
+#ifdef _WIN32
+	nResult = WSACleanup();
+	if(nResult != NO_ERROR) {
+		fprintf(stderr, "WSACleanup() failed.\n");
+	}
+#endif /* _WIN32 */
 	return retcode;
 }
 
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c
index ad69781..d786e53 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c
@@ -1,7 +1,8 @@
-/* $Id: upnpcommands.c,v 1.42 2014/01/31 13:18:25 nanard Exp $ */
-/* Project : miniupnp
+/* $Id: upnpcommands.c,v 1.48 2017/04/21 10:22:40 nanard Exp $ */
+/* vim: tabstop=4 shiftwidth=4 noexpandtab
+ * Project : miniupnp
  * Author : Thomas Bernard
- * Copyright (c) 2005-2012 Thomas Bernard
+ * Copyright (c) 2005-2017 Thomas Bernard
  * This software is subject to the conditions detailed in the
  * LICENCE file provided in this distribution.
  * */
@@ -20,7 +21,7 @@ my_atoui(const char * s)
 
 /*
  * */
-LIBSPEC UNSIGNED_INTEGER
+MINIUPNP_LIBSPEC UNSIGNED_INTEGER
 UPNP_GetTotalBytesSent(const char * controlURL,
 					const char * servicetype)
 {
@@ -44,7 +45,7 @@ UPNP_GetTotalBytesSent(const char * controlURL,
 
 /*
  * */
-LIBSPEC UNSIGNED_INTEGER
+MINIUPNP_LIBSPEC UNSIGNED_INTEGER
 UPNP_GetTotalBytesReceived(const char * controlURL,
 						const char * servicetype)
 {
@@ -68,7 +69,7 @@ UPNP_GetTotalBytesReceived(const char * controlURL,
 
 /*
  * */
-LIBSPEC UNSIGNED_INTEGER
+MINIUPNP_LIBSPEC UNSIGNED_INTEGER
 UPNP_GetTotalPacketsSent(const char * controlURL,
 						const char * servicetype)
 {
@@ -92,7 +93,7 @@ UPNP_GetTotalPacketsSent(const char * controlURL,
 
 /*
  * */
-LIBSPEC UNSIGNED_INTEGER
+MINIUPNP_LIBSPEC UNSIGNED_INTEGER
 UPNP_GetTotalPacketsReceived(const char * controlURL,
 						const char * servicetype)
 {
@@ -116,7 +117,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,
@@ -159,7 +160,7 @@ UPNP_GetStatusInfo(const char * controlURL,
 		if(up)
 			sscanf(up,"%u",uptime);
 		else
-			uptime = 0;
+			*uptime = 0;
 	}
 
 	if(lastconnerror) {
@@ -181,7 +182,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 +225,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 +294,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 +334,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;
@@ -354,6 +355,8 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
 		return UPNPCOMMAND_INVALID_ARGS;
 
 	AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
+	if(AddPortMappingArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
 	AddPortMappingArgs[0].elt = "NewRemoteHost";
 	AddPortMappingArgs[0].val = remoteHost;
 	AddPortMappingArgs[1].elt = "NewExternalPort";
@@ -370,10 +373,11 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
 	AddPortMappingArgs[6].val = desc?desc:"libminiupnpc";
 	AddPortMappingArgs[7].elt = "NewLeaseDuration";
 	AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0";
-	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
-	                                "AddPortMapping", AddPortMappingArgs,
-	                                &bufsize))) {
-		free(AddPortMappingArgs);
+	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+	                           "AddPortMapping", AddPortMappingArgs,
+	                           &bufsize);
+	free(AddPortMappingArgs);
+	if(!buffer) {
 		return UPNPCOMMAND_HTTP_ERROR;
 	}
 	/*DisplayNameValueList(buffer, bufsize);*/
@@ -390,11 +394,79 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
 		ret = UPNPCOMMAND_SUCCESS;
 	}
 	ClearNameValueList(&pdata);
+	return ret;
+}
+
+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));
+	if(AddPortMappingArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
+	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";
+	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+	                           "AddAnyPortMapping", AddPortMappingArgs,
+	                           &bufsize);
 	free(AddPortMappingArgs);
+	if(!buffer) {
+		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);
 	return ret;
 }
 
-LIBSPEC int
+MINIUPNP_LIBSPEC int
 UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
                        const char * extPort, const char * proto,
                        const char * remoteHost)
@@ -411,16 +483,19 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
 		return UPNPCOMMAND_INVALID_ARGS;
 
 	DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg));
+	if(DeletePortMappingArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
 	DeletePortMappingArgs[0].elt = "NewRemoteHost";
 	DeletePortMappingArgs[0].val = remoteHost;
 	DeletePortMappingArgs[1].elt = "NewExternalPort";
 	DeletePortMappingArgs[1].val = extPort;
 	DeletePortMappingArgs[2].elt = "NewProtocol";
 	DeletePortMappingArgs[2].val = proto;
-	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
-	                               "DeletePortMapping",
-	                               DeletePortMappingArgs, &bufsize))) {
-		free(DeletePortMappingArgs);
+	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+	                          "DeletePortMapping",
+	                          DeletePortMappingArgs, &bufsize);
+	free(DeletePortMappingArgs);
+	if(!buffer) {
 		return UPNPCOMMAND_HTTP_ERROR;
 	}
 	/*DisplayNameValueList(buffer, bufsize);*/
@@ -434,11 +509,58 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
 		ret = UPNPCOMMAND_SUCCESS;
 	}
 	ClearNameValueList(&pdata);
+	return ret;
+}
+
+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));
+	if(DeletePortMappingArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
+	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;
+
+	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+	                           "DeletePortMappingRange",
+	                           DeletePortMappingArgs, &bufsize);
 	free(DeletePortMappingArgs);
+	if(!buffer) {
+		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);
 	return ret;
 }
 
-LIBSPEC int
+MINIUPNP_LIBSPEC int
 UPNP_GetGenericPortMappingEntry(const char * controlURL,
                                 const char * servicetype,
 							 const char * index,
@@ -462,12 +584,15 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
 	intClient[0] = '\0';
 	intPort[0] = '\0';
 	GetPortMappingArgs = calloc(2, sizeof(struct UPNParg));
+	if(GetPortMappingArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
 	GetPortMappingArgs[0].elt = "NewPortMappingIndex";
 	GetPortMappingArgs[0].val = index;
-	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
-	                               "GetGenericPortMappingEntry",
-	                               GetPortMappingArgs, &bufsize))) {
-		free(GetPortMappingArgs);
+	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+	                           "GetGenericPortMappingEntry",
+	                           GetPortMappingArgs, &bufsize);
+	free(GetPortMappingArgs);
+	if(!buffer) {
 		return UPNPCOMMAND_HTTP_ERROR;
 	}
 	ParseNameValue(buffer, bufsize, &pdata);
@@ -493,14 +618,14 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
 		protocol[3] = '\0';
 	}
 	p = GetValueFromNameValueList(&pdata, "NewInternalClient");
-	if(p && intClient)
+	if(p)
 	{
 		strncpy(intClient, p, 16);
 		intClient[15] = '\0';
 		r = 0;
 	}
 	p = GetValueFromNameValueList(&pdata, "NewInternalPort");
-	if(p && intPort)
+	if(p)
 	{
 		strncpy(intPort, p, 6);
 		intPort[5] = '\0';
@@ -529,11 +654,10 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
 		sscanf(p, "%d", &r);
 	}
 	ClearNameValueList(&pdata);
-	free(GetPortMappingArgs);
 	return r;
 }
 
-LIBSPEC int
+MINIUPNP_LIBSPEC int
 UPNP_GetPortMappingNumberOfEntries(const char * controlURL,
                                    const char * servicetype,
                                    unsigned int * numEntries)
@@ -574,7 +698,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,
@@ -597,16 +721,19 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
 		return UPNPCOMMAND_INVALID_ARGS;
 
 	GetPortMappingArgs = calloc(4, sizeof(struct UPNParg));
+	if(GetPortMappingArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
 	GetPortMappingArgs[0].elt = "NewRemoteHost";
 	GetPortMappingArgs[0].val = remoteHost;
 	GetPortMappingArgs[1].elt = "NewExternalPort";
 	GetPortMappingArgs[1].val = extPort;
 	GetPortMappingArgs[2].elt = "NewProtocol";
 	GetPortMappingArgs[2].val = proto;
-	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
-	                                "GetSpecificPortMappingEntry",
-	                                GetPortMappingArgs, &bufsize))) {
-		free(GetPortMappingArgs);
+	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+	                           "GetSpecificPortMappingEntry",
+	                           GetPortMappingArgs, &bufsize);
+	free(GetPortMappingArgs);
+	if(!buffer) {
 		return UPNPCOMMAND_HTTP_ERROR;
 	}
 	/*DisplayNameValueList(buffer, bufsize);*/
@@ -654,7 +781,6 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
 	}
 
 	ClearNameValueList(&pdata);
-	free(GetPortMappingArgs);
 	return ret;
 }
 
@@ -666,7 +792,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,
@@ -686,6 +812,8 @@ UPNP_GetListOfPortMappings(const char * controlURL,
 		return UPNPCOMMAND_INVALID_ARGS;
 
 	GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg));
+	if(GetListOfPortMappingsArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
 	GetListOfPortMappingsArgs[0].elt = "NewStartPort";
 	GetListOfPortMappingsArgs[0].val = startPort;
 	GetListOfPortMappingsArgs[1].elt = "NewEndPort";
@@ -697,13 +825,13 @@ UPNP_GetListOfPortMappings(const char * controlURL,
 	GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts";
 	GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000";
 
-	if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
-	                                "GetListOfPortMappings",
-	                                GetListOfPortMappingsArgs, &bufsize))) {
-		free(GetListOfPortMappingsArgs);
+	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
+	                           "GetListOfPortMappings",
+	                           GetListOfPortMappingsArgs, &bufsize);
+	free(GetListOfPortMappingsArgs);
+	if(!buffer) {
 		return UPNPCOMMAND_HTTP_ERROR;
 	}
-	free(GetListOfPortMappingsArgs);
 
 	/*DisplayNameValueList(buffer, bufsize);*/
 	ParseNameValue(buffer, bufsize, &pdata);
@@ -748,7 +876,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 +920,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,
@@ -813,6 +941,8 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
 		return UPNPCOMMAND_INVALID_ARGS;
 
 	GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg));
+	if(GetOutboundPinholeTimeoutArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
 	GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost";
 	GetOutboundPinholeTimeoutArgs[0].val = remoteHost;
 	GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort";
@@ -825,6 +955,7 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
 	GetOutboundPinholeTimeoutArgs[4].val = intClient;
 	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
 	                           "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize);
+	free(GetOutboundPinholeTimeoutArgs);
 	if(!buffer)
 		return UPNPCOMMAND_HTTP_ERROR;
 	ParseNameValue(buffer, bufsize, &pdata);
@@ -843,11 +974,10 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
 			*opTimeout = my_atoui(p);
 	}
 	ClearNameValueList(&pdata);
-	free(GetOutboundPinholeTimeoutArgs);
 	return ret;
 }
 
-LIBSPEC int
+MINIUPNP_LIBSPEC int
 UPNP_AddPinhole(const char * controlURL, const char * servicetype,
                     const char * remoteHost,
                     const char * remotePort,
@@ -869,6 +999,8 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
 		return UPNPCOMMAND_INVALID_ARGS;
 
 	AddPinholeArgs = calloc(7, sizeof(struct UPNParg));
+	if(AddPinholeArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
 	/* RemoteHost can be wilcarded */
 	if(strncmp(remoteHost, "empty", 5)==0)
 	{
@@ -900,6 +1032,7 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
 	AddPinholeArgs[5].val = leaseTime;
 	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
 	                           "AddPinhole", AddPinholeArgs, &bufsize);
+	free(AddPinholeArgs);
 	if(!buffer)
 		return UPNPCOMMAND_HTTP_ERROR;
 	ParseNameValue(buffer, bufsize, &pdata);
@@ -922,11 +1055,10 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
 		ret = UPNPCOMMAND_SUCCESS;
 	}
 	ClearNameValueList(&pdata);
-	free(AddPinholeArgs);
 	return ret;
 }
 
-LIBSPEC int
+MINIUPNP_LIBSPEC int
 UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
                     const char * uniqueID,
                     const char * leaseTime)
@@ -942,12 +1074,15 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
 		return UPNPCOMMAND_INVALID_ARGS;
 
 	UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg));
+	if(UpdatePinholeArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
 	UpdatePinholeArgs[0].elt = "UniqueID";
 	UpdatePinholeArgs[0].val = uniqueID;
 	UpdatePinholeArgs[1].elt = "NewLeaseTime";
 	UpdatePinholeArgs[1].val = leaseTime;
 	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
 	                           "UpdatePinhole", UpdatePinholeArgs, &bufsize);
+	free(UpdatePinholeArgs);
 	if(!buffer)
 		return UPNPCOMMAND_HTTP_ERROR;
 	ParseNameValue(buffer, bufsize, &pdata);
@@ -964,11 +1099,10 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
 		ret = UPNPCOMMAND_SUCCESS;
 	}
 	ClearNameValueList(&pdata);
-	free(UpdatePinholeArgs);
 	return ret;
 }
 
-LIBSPEC int
+MINIUPNP_LIBSPEC int
 UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID)
 {
 	/*struct NameValueParserData pdata;*/
@@ -983,10 +1117,13 @@ UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char
 		return UPNPCOMMAND_INVALID_ARGS;
 
 	DeletePinholeArgs = calloc(2, sizeof(struct UPNParg));
+	if(DeletePinholeArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
 	DeletePinholeArgs[0].elt = "UniqueID";
 	DeletePinholeArgs[0].val = uniqueID;
 	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
 	                           "DeletePinhole", DeletePinholeArgs, &bufsize);
+	free(DeletePinholeArgs);
 	if(!buffer)
 		return UPNPCOMMAND_HTTP_ERROR;
 	/*DisplayNameValueList(buffer, bufsize);*/
@@ -1003,11 +1140,10 @@ UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char
 		ret = UPNPCOMMAND_SUCCESS;
 	}
 	ClearNameValueList(&pdata);
-	free(DeletePinholeArgs);
 	return ret;
 }
 
-LIBSPEC int
+MINIUPNP_LIBSPEC int
 UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
                                  const char * uniqueID, int * isWorking)
 {
@@ -1022,12 +1158,17 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
 		return UPNPCOMMAND_INVALID_ARGS;
 
 	CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg));
+	if(CheckPinholeWorkingArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
 	CheckPinholeWorkingArgs[0].elt = "UniqueID";
 	CheckPinholeWorkingArgs[0].val = uniqueID;
 	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
 	                           "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize);
+	free(CheckPinholeWorkingArgs);
 	if(!buffer)
+	{
 		return UPNPCOMMAND_HTTP_ERROR;
+	}
 	ParseNameValue(buffer, bufsize, &pdata);
 	free(buffer); buffer = NULL;
 
@@ -1048,11 +1189,10 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
 	}
 
 	ClearNameValueList(&pdata);
-	free(CheckPinholeWorkingArgs);
 	return ret;
 }
 
-LIBSPEC int
+MINIUPNP_LIBSPEC int
 UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
                                  const char * uniqueID, int * packets)
 {
@@ -1067,10 +1207,13 @@ UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
 		return UPNPCOMMAND_INVALID_ARGS;
 
 	GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg));
+	if(GetPinholePacketsArgs == NULL)
+		return UPNPCOMMAND_MEM_ALLOC_ERROR;
 	GetPinholePacketsArgs[0].elt = "UniqueID";
 	GetPinholePacketsArgs[0].val = uniqueID;
 	buffer = simpleUPnPcommand(-1, controlURL, servicetype,
 	                           "GetPinholePackets", GetPinholePacketsArgs, &bufsize);
+	free(GetPinholePacketsArgs);
 	if(!buffer)
 		return UPNPCOMMAND_HTTP_ERROR;
 	ParseNameValue(buffer, bufsize, &pdata);
@@ -1091,7 +1234,6 @@ UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
 	}
 
 	ClearNameValueList(&pdata);
-	free(GetPinholePacketsArgs);
 	return ret;
 }
 
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h
index dc3f23f..22eda5e 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h
@@ -1,7 +1,7 @@
-/* $Id: upnpcommands.h,v 1.26 2014/01/31 13:18:26 nanard Exp $ */
+/* $Id: upnpcommands.h,v 1.31 2015/07/21 13:16:55 nanard Exp $ */
 /* Miniupnp project : http://miniupnp.free.fr/
  * Author : Thomas Bernard
- * Copyright (c) 2005-2011 Thomas Bernard
+ * Copyright (c) 2005-2015 Thomas Bernard
  * This software is subject to the conditions detailed in the
  * LICENCE file provided within this distribution */
 #ifndef UPNPCOMMANDS_H_INCLUDED
@@ -9,7 +9,7 @@
 
 #include "upnpreplyparse.h"
 #include "portlistingparse.h"
-#include "declspec.h"
+#include "miniupnpc_declspec.h"
 #include "miniupnpctypes.h"
 
 /* MiniUPnPc return codes : */
@@ -17,24 +17,26 @@
 #define UPNPCOMMAND_UNKNOWN_ERROR (-1)
 #define UPNPCOMMAND_INVALID_ARGS (-2)
 #define UPNPCOMMAND_HTTP_ERROR (-3)
+#define UPNPCOMMAND_INVALID_RESPONSE (-4)
+#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5)
 
 #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 +45,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 +57,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 +73,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 +84,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,
@@ -100,6 +102,8 @@ UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
  * 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
@@ -112,16 +116,56 @@ UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
  * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard
  *                             and cannot be a specific IP address or DNS name
  * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and
- *                                        cannot be a specific port value */
-LIBSPEC int
+ *                                        cannot be a specific port value
+ * 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_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().
@@ -132,15 +176,36 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
  *
  * List of possible UPnP errors for DeletePortMapping :
  * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 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);
@@ -159,8 +224,16 @@ UPNP_GetPortMappingNumberOfEntries(const char* controlURL,
  *
  * return value :
  * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
- * or a UPnP Error Code. */
-LIBSPEC int
+ * or a UPnP Error Code.
+ *
+ * List of possible UPnP errors for _GetSpecificPortMappingEntry :
+ * 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.
+ * 714 NoSuchEntryInArray - The specified value does not exist in the array.
+ */
+MINIUPNP_LIBSPEC int
 UPNP_GetSpecificPortMappingEntry(const char * controlURL,
                                  const char * servicetype,
                                  const char * extPort,
@@ -190,9 +263,11 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
  *
  * Possible UPNP Error codes :
  * 402 Invalid Args - See UPnP Device Architecture section on Control.
+ * 606 Action not authorized - The action requested REQUIRES authorization
+ *                             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,
@@ -214,7 +289,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,
@@ -224,13 +299,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,
@@ -239,7 +314,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,
@@ -249,19 +324,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);
 
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpdev.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpdev.c
new file mode 100644
index 0000000..d89a993
--- /dev/null
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpdev.c
@@ -0,0 +1,23 @@
+/* $Id: upnpdev.c,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
+/* Project : miniupnp
+ * Web : http://miniupnp.free.fr/
+ * Author : Thomas BERNARD
+ * copyright (c) 2005-2015 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENSE file. */
+#include <stdlib.h>
+#include "upnpdev.h"
+
+/* freeUPNPDevlist() should be used to
+ * free the chained list returned by upnpDiscover() */
+void freeUPNPDevlist(struct UPNPDev * devlist)
+{
+	struct UPNPDev * next;
+	while(devlist)
+	{
+		next = devlist->pNext;
+		free(devlist);
+		devlist = next;
+	}
+}
+
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpdev.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpdev.h
new file mode 100644
index 0000000..f49fbe1
--- /dev/null
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpdev.h
@@ -0,0 +1,36 @@
+/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
+/* Project : miniupnp
+ * Web : http://miniupnp.free.fr/
+ * Author : Thomas BERNARD
+ * copyright (c) 2005-2015 Thomas Bernard
+ * This software is subjet to the conditions detailed in the
+ * provided LICENSE file. */
+#ifndef UPNPDEV_H_INCLUDED
+#define UPNPDEV_H_INCLUDED
+
+#include "miniupnpc_declspec.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct UPNPDev {
+	struct UPNPDev * pNext;
+	char * descURL;
+	char * st;
+	unsigned int scope_id;
+	char * usn;
+	char buffer[3];
+};
+
+/* freeUPNPDevlist()
+ * free list returned by upnpDiscover() */
+MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* UPNPDEV_H_INCLUDED */
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c
index 644098f..7ab8ee9 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c
@@ -1,4 +1,4 @@
-/* $Id: upnperrors.c,v 1.6 2012/03/15 01:02:03 nanard Exp $ */
+/* $Id: upnperrors.c,v 1.8 2014/06/10 09:41:48 nanard Exp $ */
 /* Project : miniupnp
  * Author : Thomas BERNARD
  * copyright (c) 2007 Thomas Bernard
@@ -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;
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h
index 077d693..3115aee 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h
@@ -1,5 +1,5 @@
-/* $Id: upnperrors.h,v 1.4 2012/09/27 15:42:11 nanard Exp $ */
-/* (c) 2007 Thomas Bernard
+/* $Id: upnperrors.h,v 1.6 2015/07/21 13:16:55 nanard Exp $ */
+/* (c) 2007-2015 Thomas Bernard
  * All rights reserved.
  * MiniUPnP Project.
  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@@ -8,7 +8,7 @@
 #ifndef UPNPERRORS_H_INCLUDED
 #define UPNPERRORS_H_INCLUDED
 
-#include "declspec.h"
+#include "miniupnpc_declspec.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -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
 }
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c
index dafa263..5de5796 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c
@@ -1,7 +1,7 @@
-/* $Id: upnpreplyparse.c,v 1.15 2013/06/06 21:36:40 nanard Exp $ */
+/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */
 /* MiniUPnP project
  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
- * (c) 2006-2013 Thomas Bernard
+ * (c) 2006-2015 Thomas Bernard
  * This software is subject to the conditions detailed
  * in the LICENCE file provided within the distribution */
 
@@ -40,6 +40,15 @@ NameValueParserEndElt(void * d, const char * name, int l)
 		/* standard case. Limited to n chars strings */
 		l = data->cdatalen;
 	    nv = malloc(sizeof(struct NameValue));
+		if(nv == NULL)
+		{
+			/* malloc error */
+#ifdef DEBUG
+			fprintf(stderr, "%s: error allocating memory",
+			        "NameValueParserEndElt");
+#endif /* DEBUG */
+			return;
+		}
 	    if(l>=(int)sizeof(nv->value))
 	        l = sizeof(nv->value) - 1;
 	    strncpy(nv->name, data->curelt, 64);
@@ -53,7 +62,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;
@@ -71,6 +81,10 @@ NameValueParserGetData(void * d, const char * datas, int l)
 		if(!data->portListing)
 		{
 			/* malloc error */
+#ifdef DEBUG
+			fprintf(stderr, "%s: error allocating memory",
+			        "NameValueParserGetData");
+#endif /* DEBUG */
 			return;
 		}
 		memcpy(data->portListing, datas, l);
@@ -89,19 +103,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 +128,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 +141,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,13 +185,13 @@ 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);
     }
     ClearNameValueList(&pdata);
 }
-#endif
+#endif /* DEBUG */
 
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h
index d4e3757..6badd15 100644
--- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h
+++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h
@@ -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;
-- 
cgit v0.10.2-6-g49f6