diff options
author | Tobias Markmann <tm@ayena.de> | 2017-05-16 14:59:08 (GMT) |
---|---|---|
committer | Tobias Markmann <tm@ayena.de> | 2017-05-17 06:36:48 (GMT) |
commit | edf519a67a28f9acb61af6d442d94f1aa43df688 (patch) | |
tree | 802269050d3db7c13c763550269f663172938b96 /3rdParty/LibMiniUPnPc | |
parent | 6644c207c879f33dac40c02ab6787a0c4184728d (diff) | |
download | swift-edf519a67a28f9acb61af6d442d94f1aa43df688.zip swift-edf519a67a28f9acb61af6d442d94f1aa43df688.tar.bz2 |
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
Diffstat (limited to '3rdParty/LibMiniUPnPc')
28 files changed, 2116 insertions, 1030 deletions
diff --git a/3rdParty/LibMiniUPnPc/SConscript b/3rdParty/LibMiniUPnPc/SConscript index 3c2e29d..a995941 100644 --- a/3rdParty/LibMiniUPnPc/SConscript +++ b/3rdParty/LibMiniUPnPc/SConscript @@ -1,84 +1,90 @@ Import(["env", "conf_env"]) import os if env.get("LIBMINIUPNPC_BUNDLED", False) : ################################################################################ # Module flags ################################################################################ if env["SCONS_STAGE"] == "flags" : 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"]}) else : env["LIBMINIUPNPC_FLAGS"].update({"CPPPATH": [Dir("src/miniupnpc")]}) #if env["PLATFORM"] == "win32" : # env["LIBIDN_FLAGS"]["CPPPATH"] += [Dir("stubs/win32")] # if env["MSVC_VERSION"][:3] == "9.0" : # env["LIBIDN_FLAGS"]["CPPPATH"] += [Dir("stubs/win32/VC2008")] ################################################################################ # Build ################################################################################ if env["SCONS_STAGE"] == "build" : myenv = env.Clone() myenv.Append(CPPPATH = ["src"]) # 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"]) myenv.Append(CCFLAGS = ["-D_BSD_SOURCE"]) if myenv["PLATFORM"] == "darwin": myenv.Append(CCFLAGS = ["-DMACOSX", "-D_DARWIN_C_SOURCE"]) if myenv["PLATFORM"] == "win32": myenv.Append(CCFLAGS = ["-DWIN32", "-D_WIN32_WINNT=0x0501"]) if myenv["PLATFORM"] != "win32" and myenv["PLATFORM"] != "darwin": conf = Configure(conf_env) if conf.CheckTypeSize("struct ip_mreqn", includes="#include <netinet/in.h>") == 0: myenv.Append(CCFLAGS = ["-DNEED_STRUCT_IP_MREQN"]) conf.Finish() 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,27 +1,27 @@ 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 modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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,31 +1,54 @@ -/* $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 #define CODELENGTH_H_INCLUDED /* 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 { \ if((p) >= (p_limit)) break; \ 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,142 +1,147 @@ -/* $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. */ /* use getaddrinfo() or gethostbyname() * uncomment the following line in order to use gethostbyname() */ #ifdef NO_GETADDRINFO #define USE_GETHOSTBYNAME #endif #include <string.h> #include <stdio.h> #ifdef _WIN32 #include <winsock2.h> #include <ws2tcpip.h> #include <io.h> #define MAXHOSTNAMELEN 64 #define snprintf _snprintf #define herror #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> #define closesocket close #include <netdb.h> #include <netinet/in.h> /* 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 #if defined(__amigaos__) || defined(__amigaos4__) #define herror(A) printf("%s\n", A) #endif #include "connecthostport.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif /* connecthostport() * return a socket connected (TCP) to the host and port * or -1 in case of error */ int connecthostport(const char * host, unsigned short port, unsigned int scope_id) { int s, n; #ifdef USE_GETHOSTBYNAME struct sockaddr_in dest; struct hostent *hp; #else /* #ifdef USE_GETHOSTBYNAME */ char tmp_host[MAXHOSTNAMELEN+1]; char port_str[8]; struct addrinfo *ai, *p; struct addrinfo hints; #endif /* #ifdef USE_GETHOSTBYNAME */ #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT struct timeval timeout; #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ #ifdef USE_GETHOSTBYNAME hp = gethostbyname(host); if(hp == NULL) { herror(host); return -1; } memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr)); memset(dest.sin_zero, 0, sizeof(dest.sin_zero)); s = socket(PF_INET, SOCK_STREAM, 0); if(s < 0) { PRINT_SOCKET_ERROR("socket"); return -1; } #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT /* setting a 3 seconds timeout for the connect() call */ timeout.tv_sec = 3; 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; int err; FD_ZERO(&wset); FD_SET(s, &wset); if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) continue; /*len = 0;*/ /*n = getpeername(s, NULL, &len);*/ len = sizeof(err); if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { PRINT_SOCKET_ERROR("getsockopt"); closesocket(s); return -1; } if(err != 0) { errno = err; n = -1; } } #endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ if(n<0) { PRINT_SOCKET_ERROR("connect"); closesocket(s); return -1; } #else /* #ifdef USE_GETHOSTBYNAME */ /* use getaddrinfo() instead of gethostbyname() */ @@ -176,61 +181,64 @@ int connecthostport(const char * host, unsigned short port, #endif return -1; } s = -1; for(p = ai; p; p = p->ai_next) { s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if(s < 0) continue; if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) { struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr; addr6->sin6_scope_id = scope_id; } #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT /* setting a 3 seconds timeout for the connect() call */ timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } #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; int err; FD_ZERO(&wset); FD_SET(s, &wset); if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) continue; /*len = 0;*/ /*n = getpeername(s, NULL, &len);*/ len = sizeof(err); if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { PRINT_SOCKET_ERROR("getsockopt"); closesocket(s); freeaddrinfo(ai); return -1; } if(err != 0) { errno = err; n = -1; } } #endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ if(n < 0) { closesocket(s); continue; } else { 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,125 +1,123 @@ -/* $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. */ #include "igd_desc_parse.h" #include <stdio.h> #include <string.h> /* Start element handler : * update nesting level counter and copy element name */ void IGDstartelt(void * d, const char * name, int l) { struct IGDdatas * datas = (struct IGDdatas *)d; - memcpy( datas->cureltname, name, l); + 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) ) { datas->tmp.controlurl[0] = '\0'; datas->tmp.eventsuburl[0] = '\0'; datas->tmp.scpdurl[0] = '\0'; datas->tmp.servicetype[0] = '\0'; } } +#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) + /* End element handler : * update nesting level counter and update parser state if * service element is parsed */ void IGDendelt(void * d, const char * name, int l) { struct IGDdatas * datas = (struct IGDdatas *)d; datas->level--; /*printf("endelt %2d %.*s\n", datas->level, l, name);*/ if( (l==7) && !memcmp(name, "service", l) ) { - /* - if( 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 { memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service)); } } } } /* Data handler : * copy data depending on the current element name and state */ void IGDdata(void * d, const char * data, int l) { struct IGDdatas * datas = (struct IGDdatas *)d; char * dstmember = 0; /*printf("%2d %s : %.*s\n", datas->level, datas->cureltname, l, data); */ if( !strcmp(datas->cureltname, "URLBase") ) dstmember = datas->urlbase; else if( !strcmp(datas->cureltname, "presentationURL") ) dstmember = datas->presentationurl; else if( !strcmp(datas->cureltname, "serviceType") ) dstmember = datas->tmp.servicetype; else if( !strcmp(datas->cureltname, "controlURL") ) dstmember = datas->tmp.controlurl; else if( !strcmp(datas->cureltname, "eventSubURL") ) dstmember = datas->tmp.eventsuburl; else if( !strcmp(datas->cureltname, "SCPDURL") ) dstmember = datas->tmp.scpdurl; /* else if( !strcmp(datas->cureltname, "deviceType") ) dstmember = datas->devicetype_tmp;*/ if(dstmember) { if(l>=MINIUPNPC_URL_MAXSIZE) l = MINIUPNPC_URL_MAXSIZE-1; memcpy(dstmember, data, l); dstmember[l] = '\0'; } } +#ifdef DEBUG void printIGD(struct IGDdatas * d) { printf("urlbase = '%s'\n", d->urlbase); printf("WAN Device (Common interface config) :\n"); /*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/ printf(" serviceType = '%s'\n", d->CIF.servicetype); printf(" controlURL = '%s'\n", d->CIF.controlurl); printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl); printf(" SCPDURL = '%s'\n", d->CIF.scpdurl); printf("primary WAN Connection Device (IP or PPP Connection):\n"); /*printf(" deviceType = '%s'\n", d->first.devicetype);*/ printf(" servicetype = '%s'\n", d->first.servicetype); printf(" controlURL = '%s'\n", d->first.controlurl); printf(" eventSubURL = '%s'\n", d->first.eventsuburl); printf(" SCPDURL = '%s'\n", d->first.scpdurl); printf("secondary WAN Connection Device (IP or PPP Connection):\n"); /*printf(" deviceType = '%s'\n", d->second.devicetype);*/ printf(" servicetype = '%s'\n", d->second.servicetype); printf(" controlURL = '%s'\n", d->second.controlurl); printf(" eventSubURL = '%s'\n", d->second.eventsuburl); printf(" SCPDURL = '%s'\n", d->second.scpdurl); printf("WAN IPv6 Firewall Control :\n"); /*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/ printf(" servicetype = '%s'\n", d->IPv6FC.servicetype); printf(" controlURL = '%s'\n", d->IPv6FC.controlurl); printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl); printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl); } - +#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,48 +1,49 @@ -/* $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. * */ #ifndef IGD_DESC_PARSE_H_INCLUDED #define IGD_DESC_PARSE_H_INCLUDED /* Structure to store the result of the parsing of UPnP * descriptions of Internet Gateway Devices */ #define MINIUPNPC_URL_MAXSIZE (128) struct IGDdatas_service { char controlurl[MINIUPNPC_URL_MAXSIZE]; char eventsuburl[MINIUPNPC_URL_MAXSIZE]; char scpdurl[MINIUPNPC_URL_MAXSIZE]; char servicetype[MINIUPNPC_URL_MAXSIZE]; /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ }; struct IGDdatas { char cureltname[MINIUPNPC_URL_MAXSIZE]; char urlbase[MINIUPNPC_URL_MAXSIZE]; char presentationurl[MINIUPNPC_URL_MAXSIZE]; int level; /*int state;*/ /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ struct IGDdatas_service CIF; /* "urn:schemas-upnp-org:service:WANIPConnection:1" * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ struct IGDdatas_service first; /* if both WANIPConnection and WANPPPConnection are present */ struct IGDdatas_service second; /* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ struct IGDdatas_service IPv6FC; /* tmp */ struct IGDdatas_service tmp; }; void IGDstartelt(void *, const char *, int); void IGDendelt(void *, const char *, int); void IGDdata(void *, const char *, int); +#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,121 +1,123 @@ -/* $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. * * Minimal SOAP implementation for UPnP protocol. */ #include <stdio.h> #include <string.h> #ifdef _WIN32 #include <io.h> #include <winsock2.h> #define snprintf _snprintf #else #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #endif #include "minisoap.h" #include "miniupnpcstrings.h" /* only for malloc */ #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 /* httpWrite sends the headers and the body to the socket * and returns the number of bytes sent */ static int httpWrite(int fd, const char * body, int bodysize, const char * headers, int headerssize) { int n = 0; /*n = write(fd, headers, headerssize);*/ /*if(bodysize>0) n += write(fd, body, 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);*/ n = send(fd, p, headerssize+bodysize, 0); if(n<0) { PRINT_SOCKET_ERROR("send"); } /* disable send on the socket */ /* draytek routers dont seems to like that... */ #if 0 #ifdef _WIN32 if(shutdown(fd, SD_SEND)<0) { #else if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/ #endif PRINT_SOCKET_ERROR("shutdown"); } #endif free(p); return n; } /* self explanatory */ int soapPostSubmit(int fd, const char * url, const char * host, unsigned short port, const char * action, const char * body, const char * httpversion) { int bodysize; char headerbuf[512]; int headerssize; char portstr[8]; bodysize = (int)strlen(body); /* We are not using keep-alive HTTP connections. * HTTP/1.1 needs the header Connection: close to do that. * This is the default with HTTP/1.0 * Using HTTP/1.1 means we need to support chunked transfer-encoding : * When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked * transfer encoding. */ /* Connection: Close is normally there only in HTTP/1.1 but who knows */ portstr[0] = '\0'; if(port != 80) snprintf(portstr, sizeof(portstr), ":%hu", port); 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" "Connection: Close\r\n" "Cache-Control: no-cache\r\n" /* ??? */ "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); */ printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n", url, httpversion, host, portstr); printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize); printf("Headers :\n%s", headerbuf); printf("Body :\n%s\n", body); #endif return httpWrite(fd, body, bodysize, headerbuf, headerssize); } 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,133 +1,888 @@ -/* $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 */ if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { /*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; if(write(s, buffer, p - buffer) < 0) { /*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,1045 +1,722 @@ -/* $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> #ifdef _WIN32 /* Win32 Specific includes and defines */ #include <winsock2.h> #include <ws2tcpip.h> #include <io.h> #include <iphlpapi.h> #define snprintf _snprintf #define strdup _strdup #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 */ #define MAXHOSTNAMELEN 64 #else /* #ifdef _WIN32 */ /* Standard POSIX includes */ #include <unistd.h> #if defined(__amigaos__) && !defined(__amigaos4__) /* Amiga OS 3 specific stuff */ #define socklen_t int #else #include <sys/select.h> #endif #include <sys/socket.h> #include <sys/types.h> #include <sys/param.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <net/if.h> #if !defined(__amigaos__) && !defined(__amigaos4__) #include <poll.h> #endif #include <strings.h> #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" #include "minisoap.h" #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 #endif #define SOAPPREFIX "s" #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 */ parser.xmlstart = buffer; parser.xmlsize = bufsize; parser.data = data; parser.starteltfunc = IGDstartelt; parser.endeltfunc = IGDendelt; parser.datafunc = IGDdata; parser.attfunc = 0; parsexml(&parser); #ifdef DEBUG printIGD(data); #endif } /* simpleUPnPcommand2 : * not so simple ! * return values : * pointer - OK * NULL - error */ char * simpleUPnPcommand2(int s, const char * url, const char * service, const char * action, struct UPNParg * args, int * bufsize, const char * httpversion) { char hostname[MAXHOSTNAMELEN+1]; unsigned short port = 0; 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) { s = connecthostport(hostname, port, 0); if(s < 0) { /* failed to connect */ return NULL; } } n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); if(n<=0) { #ifdef DEBUG printf("Error sending SOAP request\n"); #endif closesocket(s); 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); return buf; } /* simpleUPnPcommand : * not so simple ! * return values : * pointer - OK * NULL - error */ char * simpleUPnPcommand(int s, const char * url, const char * service, const char * action, struct UPNParg * args, int * bufsize) { char * buf; #if 1 buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); #else buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0"); if (!buf || *bufsize == 0) { #if DEBUG printf("Error or no result from SOAP request; retrying with HTTP/1.1\n"); #endif buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); } #endif 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; #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) /* 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) return; free(urls->controlURL); urls->controlURL = 0; free(urls->ipcondescURL); urls->ipcondescURL = 0; free(urls->controlURL_CIF); urls->controlURL_CIF = 0; free(urls->controlURL_6FC); urls->controlURL_6FC = 0; free(urls->rootdescURL); urls->rootdescURL = 0; } int UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) { char status[64]; unsigned int uptime; status[0] = '\0'; 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; } /* UPNP_GetValidIGD() : * return values : * -1 = Internal error * 0 = NO IGD found * 1 = A valid connected IGD has been found * 2 = A valid IGD has been found but it reported as * not connected * 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, char * lanaddr, int lanaddrlen) { struct xml_desc { char * xml; int size; int is_igd; } * desc = NULL; struct UPNPDev * dev; int ndev = 0; int i; 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 printf("Empty devlist\n"); #endif return 0; } /* counting total number of devices in the list */ for(dev = devlist; dev; dev = dev->pNext) ndev++; if(ndev > 0) { desc = calloc(ndev, sizeof(struct xml_desc)); if(!desc) return -1; /* memory allocation error */ } /* Step 1 : downloading descriptions and testing type */ for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { /* 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) { printf("error getting XML description %s\n", dev->descURL); } #endif if(desc[i].xml) { 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); } } } /* iterate the list to find a device depending on state */ for(state = 1; state <= 3; state++) { for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); 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 printf("We tried %s, now we try %s !\n", data->first.servicetype, data->second.servicetype); #endif /* swaping WANPPPConnection and WANIPConnection ! */ memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); 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); } } memset(data, 0, sizeof(struct IGDdatas)); } } } state = 0; free_and_return: if(desc) { for(i = 0; i < ndev; i++) { if(desc[i].xml) { free(desc[i].xml); } } free(desc); } return state; } /* UPNP_GetIGDFromUrl() * Used when skipping the discovery process. * return value : * 0 - Not ok * 1 - OK */ int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { 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)); parserootdesc(descXML, descXMLsize, data); free(descXML); descXML = NULL; GetUPNPUrls(urls, data, rootdescurl, 0); return 1; } else { return 0; } } 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,130 +1,152 @@ -/* $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) #define UPNPDISCOVER_UNKNOWN_ERROR (-1) #define UPNPDISCOVER_SOCKET_ERROR (-101) #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" { #endif /* Structures definitions : */ struct UPNParg { const char * elt; const char * val; }; char * 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. * It is up to the caller to free the list with freeUPNPDevlist(). * delay (in millisecond) is the maximum time for waiting any device * response. * If available, device list will be obtained from MiniSSDPd. * Default path for minissdpd socket will be used if minissdpdsock argument * 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 * ipcondescURL: url of the description of the WANIPConnection * controlURL_CIF: controlURL of the WANCommonInterfaceConfig * controlURL_6FC: controlURL of the WANIPv6FirewallControl */ struct UPNPUrls { char * controlURL; char * ipcondescURL; char * controlURL_CIF; char * controlURL_6FC; char * rootdescURL; }; /* UPNP_GetValidIGD() : * return values : * 0 = NO IGD found * 1 = A valid connected IGD has been found * 2 = A valid IGD has been found but it reported as * not connected * 3 = an UPnP device has been found but was not recognized as an IGD * * In any non zero return case, the urls and data structures * 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, char * lanaddr, int lanaddrlen); /* 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 } #endif #endif 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,172 +1,228 @@ -/* $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. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #ifdef _WIN32 #include <winsock2.h> #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 #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 */ #else /* #ifdef _WIN32 */ #include <unistd.h> #include <sys/param.h> #if defined(__amigaos__) && !defined(__amigaos4__) #define socklen_t int #else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ #include <sys/select.h> #endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #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" #include "connecthostport.h" #include "receivedata.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif /* * Read a HTTP response from a socket. * Process Content-Length and Transfer-encoding headers. * return a pointer to the content buffer, which length is saved * to the length parameter. */ void * -getHTTPResponse(int s, int * size) +getHTTPResponse(int s, int * size, int * status_code) { char buf[2048]; int n; int endofheaders = 0; int chunked = 0; int content_length = -1; unsigned int chunksize = 0; unsigned int bytestocopy = 0; /* buffers : */ char * header_buf; unsigned int header_buf_len = 2048; unsigned int header_buf_used = 0; char * content_buf; unsigned int content_buf_len = 2048; 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) { int i; int linestart=0; 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); header_buf_used += n; /* search for CR LF CR LF (end of headers) * recognize also LF LF */ i = 0; while(i < ((int)header_buf_used-1) && (endofheaders == 0)) { if(header_buf[i] == '\r') { i++; if(header_buf[i] == '\n') { i++; if(i < (int)header_buf_used && header_buf[i] == '\r') { i++; if(i < (int)header_buf_used && header_buf[i] == '\n') { endofheaders = i+1; } } } } else if(header_buf[i] == '\n') { i++; if(header_buf[i] == '\n') { endofheaders = i+1; } } i++; } if(endofheaders == 0) 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) && (header_buf[i+1] == ' ' || header_buf[i+1] == '\t')) i++; valuestart = i + 1; } /* 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", colon-linestart, header_buf+linestart, i-valuestart, header_buf+valuestart); #endif if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart)) { content_length = atoi(header_buf+valuestart); #ifdef DEBUG printf("Content-Length: %d\n", content_length); #endif } else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart) && 0==strncasecmp(header_buf+valuestart, "chunked", 7)) { #ifdef DEBUG printf("chunked transfer-encoding!\n"); #endif chunked = 1; } } while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n')) i++; linestart = i; colon = linestart; valuestart = 0; } } /* copy the remaining of the received data back to buf */ @@ -201,127 +257,146 @@ getHTTPResponse(int s, int * size) i++; /* discarding chunk-extension */ if(i<n && buf[i] == '\r') i++; if(i<n && buf[i] == '\n') { unsigned int j; for(j = 0; j < chunksize_buf_index; j++) { if(chunksize_buf[j] >= '0' && chunksize_buf[j] <= '9') chunksize = (chunksize << 4) + (chunksize_buf[j] - '0'); else chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10); } chunksize_buf[0] = '\0'; chunksize_buf_index = 0; i++; } else { /* not finished to get chunksize */ continue; } #ifdef DEBUG printf("chunksize = %u (%x)\n", chunksize, chunksize); #endif if(chunksize == 0) { #ifdef DEBUG printf("end of HTTP content - %d %d\n", i, n); /*printf("'%.*s'\n", n-i, buf+i);*/ #endif 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; i += bytestocopy; chunksize -= bytestocopy; } } else { /* 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"); #endif break; } } end_of_stream: free(header_buf); header_buf = NULL; *size = content_buf_used; if(content_buf_used == 0) { free(content_buf); content_buf = NULL; } return content_buf; } /* miniwget3() : * do all the work. * Return NULL if something failed. */ 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; int n; int len; int sent; void * content; *size = 0; s = connecthostport(host, port, scope_id); if(s < 0) return NULL; /* get address for caller ! */ if(addr_str) { struct sockaddr_storage saddr; socklen_t saddrlen; saddrlen = sizeof(saddr); if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0) { perror("getsockname"); } else { #if defined(__amigaos__) && !defined(__amigaos4__) /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD); * But his function make a string with the port : nn.nn.nn.nn:port */ /* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr), @@ -340,109 +415,117 @@ miniwget3(const char * host, } else { inet_ntop(AF_INET, &(((struct sockaddr_in *)&saddr)->sin_addr), addr_str, addr_str_len); } #endif /* getnameinfo return ip v6 address with the scope identifier * such as : 2a01:e35:8b2b:7330::%4281128194 */ n = getnameinfo((const struct sockaddr *)&saddr, saddrlen, addr_str, addr_str_len, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); if(n != 0) { #ifdef _WIN32 fprintf(stderr, "getnameinfo() failed : %d\n", n); #else fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); #endif } #endif } #ifdef DEBUG printf("address miniwget : %s\n", addr_str); #endif } len = snprintf(buf, sizeof(buf), "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) { n = send(s, buf+sent, len-sent, 0); if(n < 0) { perror("send"); closesocket(s); return NULL; } else { sent += n; } } - content = getHTTPResponse(s, size); + content = getHTTPResponse(s, size, status_code); closesocket(s); return content; } /* miniwget2() : * 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 printf("Retrying with HTTP/1.1\n"); #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; } /* parseURL() * arguments : * url : source string not modified * hostname : hostname destination string (size of MAXHOSTNAMELEN+1) * port : port (destination) * path : pointer to the path part of the URL * * Return values : * 0 - Failure * 1 - Success */ int parseURL(const char * url, char * hostname, unsigned short * port, char * * path, unsigned int * scope_id) { char * p1, *p2, *p3; if(!url) return 0; p1 = strstr(url, "://"); if(!p1) return 0; p1 += 3; @@ -513,66 +596,68 @@ parseURL(const char * url, *path = p3; return 1; } } p2 = strchr(p1, ':'); p3 = strchr(p1, '/'); if(!p3) return 0; if(!p2 || (p2>p3)) { strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1))); *port = 80; } else { strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); *port = 0; p2++; while( (*p2 >= '0') && (*p2 <= '9')) { *port *= 10; *port += (unsigned short)(*p2 - '0'); p2++; } } *path = p3; return 1; } 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; /* protocol://host:port/chemin */ char hostname[MAXHOSTNAMELEN+1]; *size = 0; if(!parseURL(url, hostname, &port, &path, &scope_id)) return NULL; #ifdef DEBUG 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; /* protocol://host:port/path */ char hostname[MAXHOSTNAMELEN+1]; *size = 0; if(addr) addr[0] = '\0'; if(!parseURL(url, hostname, &port, &path, &scope_id)) return NULL; #ifdef DEBUG 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,30 +1,30 @@ -/* $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 *); #ifdef __cplusplus } #endif #endif 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,37 +1,37 @@ -/* $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 modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <string.h> #include "minixml.h" /* parseatt : used to parse the argument list * return 0 (false) in case of success and -1 (true) if the end @@ -86,61 +86,74 @@ static int parseatt(struct xmlparser * p) else { attvalue = p->xml; attvaluelen = 0; while( !IS_WHITE_SPACE(*p->xml) && *p->xml != '>' && *p->xml != '/') { attvaluelen++; p->xml++; if(p->xml >= p->xmlend) return -1; } } /*printf("%.*s='%.*s'\n", attnamelen, attname, attvaluelen, attvalue);*/ if(p->attfunc) p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen); } p->xml++; } return -1; } /* parseelt parse the xml stream and * call the callback functions when needed... */ static void parseelt(struct xmlparser * p) { int i; const char * elementname; while(p->xml < (p->xmlend - 1)) { - if((p->xml)[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) && (*p->xml!='>') && (*p->xml!='/') ) { i++; p->xml++; if (p->xml >= p->xmlend) return; /* to ignore namespace : */ if(*p->xml==':') { i = 0; elementname = ++p->xml; } } if(i>0) { if(p->starteltfunc) p->starteltfunc(p->data, elementname, i); if(parseatt(p)) return; if(*p->xml!='/') { const char * data; i = 0; data = ++p->xml; if (p->xml >= p->xmlend) return; while( IS_WHITE_SPACE(*p->xml) ) { 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,31 +1,31 @@ -/* $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 : * validation program for the minixml parser * * (c) 2006-2011 Thomas Bernard */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include "minixml.h" /* xml event structure */ struct event { enum { ELTSTART, ELTEND, ATT, CHARDATA } type; const char * data; int len; }; struct eventlist { int n; struct event * events; }; /* compare 2 xml event lists * return 0 if the two lists are equals */ int evtlistcmp(struct eventlist * a, struct eventlist * b) { int i; struct event * ae, * be; @@ -101,58 +101,63 @@ void endelt(void * data, const char * p, int l) struct eventlist * evtlist = data; struct event * evt; evt = evtlist->events + evtlist->n; /*printf("endelt : %.*s\n", l, p);*/ evt->type = ELTEND; evt->data = p; evt->len = l; evtlist->n++; } void chardata(void * data, const char * p, int l) { struct eventlist * evtlist = data; struct event * evt; evt = evtlist->events + evtlist->n; /*printf("chardata : '%.*s'\n", l, p);*/ evt->type = CHARDATA; evt->data = p; evt->len = l; evtlist->n++; } int testxmlparser(const char * xml, int size) { int r; struct eventlist evtlist; struct eventlist evtlistref; 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; parser.data = &evtlist; parser.starteltfunc = startelt; parser.endeltfunc = endelt; parser.datafunc = chardata; parsexml(&parser); printf("%d events\n", evtlist.n); /* compare */ evtlistref.n = sizeof(evtref)/sizeof(struct event); evtlistref.events = (struct event *)evtref; r = evtlistcmp(&evtlistref, &evtlist); free(evtlist.events); return r; } int main(int argc, char * * argv) { int r; (void)argc; (void)argv; r = testxmlparser(xmldata, sizeof(xmldata)-1); if(r) printf("minixml validation test failed\n"); return r; } 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,159 +1,172 @@ -/* $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" /* list of the elements */ static const struct { const portMappingElt code; const char * const str; } elements[] = { { PortMappingEntry, "PortMappingEntry"}, { NewRemoteHost, "NewRemoteHost"}, { NewExternalPort, "NewExternalPort"}, { NewProtocol, "NewProtocol"}, { NewInternalPort, "NewInternalPort"}, { NewInternalClient, "NewInternalClient"}, { NewEnabled, "NewEnabled"}, { NewDescription, "NewDescription"}, { NewLeaseTime, "NewLeaseTime"}, { PortMappingEltNone, NULL} }; /* Helper function */ static UNSIGNED_INTEGER atoui(const char * p, int l) { UNSIGNED_INTEGER r = 0; while(l > 0 && *p) { if(*p >= '0' && *p <= '9') r = r*10 + (*p - '0'); else break; p++; l--; } return r; } /* Start element handler */ static void startelt(void * d, const char * name, int l) { int i; struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; 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; } } if(pdata->curelt == PortMappingEntry) { 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; } } /* End element handler */ static void endelt(void * d, const char * name, int l) { struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; (void)name; (void)l; pdata->curelt = PortMappingEltNone; } /* Data handler */ static void 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) l = 63; switch(pdata->curelt) { case NewRemoteHost: memcpy(pm->remoteHost, data, l); pm->remoteHost[l] = '\0'; break; case NewExternalPort: pm->externalPort = (unsigned short)atoui(data, l); break; case NewProtocol: if(l > 3) l = 3; memcpy(pm->protocol, data, l); pm->protocol[l] = '\0'; break; case NewInternalPort: pm->internalPort = (unsigned short)atoui(data, l); break; case NewInternalClient: memcpy(pm->internalClient, data, l); pm->internalClient[l] = '\0'; break; case NewEnabled: pm->enabled = (unsigned char)atoui(data, l); break; case NewDescription: memcpy(pm->description, data, l); pm->description[l] = '\0'; break; case NewLeaseTime: pm->leaseTime = atoui(data, l); break; default: break; } } /* Parse the PortMappingList XML document for IGD version 2 */ void ParsePortListing(const char * buffer, int bufsize, struct PortMappingParserData * pdata) { struct xmlparser parser; memset(pdata, 0, sizeof(struct PortMappingParserData)); - LIST_INIT(&(pdata->head)); /* init xmlparser */ parser.xmlstart = buffer; parser.xmlsize = bufsize; parser.data = pdata; parser.starteltfunc = startelt; parser.endeltfunc = endelt; parser.datafunc = data; parser.attfunc = 0; parsexml(&parser); } 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,71 +1,65 @@ -/* $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 /* sample of PortMappingEntry : <p:PortMappingEntry> <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost> <p:NewExternalPort>2345</p:NewExternalPort> <p:NewProtocol>TCP</p:NewProtocol> <p:NewInternalPort>2345</p:NewInternalPort> <p:NewInternalClient>192.168.1.137</p:NewInternalClient> <p:NewEnabled>1</p:NewEnabled> <p:NewDescription>dooom</p:NewDescription> <p:NewLeaseTime>345</p:NewLeaseTime> </p:PortMappingEntry> */ typedef enum { PortMappingEltNone, PortMappingEntry, NewRemoteHost, NewExternalPort, NewProtocol, NewInternalPort, NewInternalClient, NewEnabled, NewDescription, NewLeaseTime } portMappingElt; struct PortMapping { - LIST_ENTRY(PortMapping) entries; + struct PortMapping * l_next; /* list next element */ UNSIGNED_INTEGER leaseTime; unsigned short externalPort; unsigned short internalPort; char remoteHost[64]; char internalClient[64]; char description[64]; char protocol[4]; unsigned char enabled; }; 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 } #endif #endif 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,109 +1,105 @@ -/* $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 #else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ #include <sys/select.h> #endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ #include <sys/socket.h> #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 #include "receivedata.h" int 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; } else if(n == 0) { /* 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; FD_ZERO(&socketSet); FD_SET(socket, &socketSet); timeval.tv_sec = timeout / 1000; timeval.tv_usec = (timeout % 1000) * 1000; n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval); if(n < 0) { PRINT_SOCKET_ERROR("select"); return -1; } 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,99 +1,119 @@ -/* $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. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #ifdef _WIN32 #include <winsock2.h> #define snprintf _snprintf #else /* 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 */ const char * protofix(const char * proto) { static const char proto_tcp[4] = { 'T', 'C', 'P', 0}; static const char proto_udp[4] = { 'U', 'D', 'P', 0}; int i, b; for(i=0, b=1; i<4; i++) b = b && ( (proto[i] == proto_tcp[i]) || (proto[i] == (proto_tcp[i] | 32)) ); if(b) return proto_tcp; for(i=0, b=1; i<4; i++) b = b && ( (proto[i] == proto_udp[i]) || (proto[i] == (proto_udp[i] | 32)) ); if(b) return proto_udp; 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) { char externalIPAddress[40]; 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; if(UPNP_GetConnectionTypeInfo(urls->controlURL, data->first.servicetype, connectionType) != UPNPCOMMAND_SUCCESS) printf("GetConnectionTypeInfo failed.\n"); else printf("Connection Type : %s\n", connectionType); if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS) printf("GetStatusInfo failed.\n"); else printf("Status : %s, uptime=%us, LastConnectionError : %s\n", status, uptime, lastconnerr); - timenow = time(NULL); - timestarted = timenow - uptime; - printf(" Time started : %s", ctime(×tarted)); + if(uptime > 0) { + timenow = time(NULL); + timestarted = timenow - uptime; + printf(" Time started : %s", ctime(×tarted)); + } if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype, &brDown, &brUp) != UPNPCOMMAND_SUCCESS) { printf("GetLinkLayerMaxBitRates failed.\n"); } else { printf("MaxBitRateDown : %u bps", brDown); if(brDown >= 1000000) { printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10); } else if(brDown >= 1000) { printf(" (%u Kbps)", brDown / 1000); } printf(" MaxBitRateUp %u bps", brUp); if(brUp >= 1000000) { printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10); } else if(brUp >= 1000) { printf(" (%u Kbps)", brUp / 1000); } printf("\n"); } r = UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, externalIPAddress); if(r != UPNPCOMMAND_SUCCESS) { printf("GetExternalIPAddress failed. (errorcode=%d)\n", r); } else { printf("ExternalIPAddress = %s\n", externalIPAddress); } } static void GetConnectionStatus(struct UPNPUrls * urls, struct IGDdatas * data) @@ -147,186 +167,241 @@ static void ListRedirections(struct UPNPUrls * urls, */ printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n", i, protocol, extPort, intClient, intPort, desc, rHost, duration); else printf("GetGenericPortMappingEntry() returned %d (%s)\n", r, strupnperror(r)); i++; } while(r==0); } static void NewListRedirections(struct UPNPUrls * urls, struct IGDdatas * data) { int r; int i = 0; struct PortMappingParserData pdata; struct PortMapping * pm; memset(&pdata, 0, sizeof(struct PortMappingParserData)); r = UPNP_GetListOfPortMappings(urls->controlURL, data->first.servicetype, "0", "65535", "TCP", "1000", &pdata); 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, pm->internalPort, pm->description, pm->remoteHost, (unsigned)pm->leaseTime); i++; } FreePortListing(&pdata); } else { printf("GetListOfPortMappings() returned %d (%s)\n", r, strupnperror(r)); } r = UPNP_GetListOfPortMappings(urls->controlURL, data->first.servicetype, "0", "65535", "UDP", "1000", &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, pm->internalPort, pm->description, pm->remoteHost, (unsigned)pm->leaseTime); i++; } FreePortListing(&pdata); } else { printf("GetListOfPortMappings() returned %d (%s)\n", r, strupnperror(r)); } } /* Test function * 1 - get connection type * 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 */ static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data) { unsigned int bytessent, bytesreceived, packetsreceived, packetssent; int firewallEnabled = 0, inboundPinholeAllowed = 0; UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed); printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed); printf("GetFirewallStatus:\n Firewall Enabled: %s\n Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No"); bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype); bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); } /* Test function * 1 - Add pinhole * 2 - Check if pinhole is working from the IGD side */ static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data, const char * remoteaddr, const char * eport, const char * intaddr, const char * iport, const char * proto, const char * lease_time) { char uniqueID[8]; /*int isWorking = 0;*/ @@ -454,232 +529,288 @@ CheckPinhole(struct UPNPUrls * urls, } r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); if(r!=UPNPCOMMAND_SUCCESS) printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); else printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); } static void RemovePinhole(struct UPNPUrls * urls, struct IGDdatas * data, const char * uniqueID) { int r; if(!uniqueID) { fprintf(stderr, "invalid arguments\n"); return; } r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID); printf("UPNP_DeletePinhole() returned : %d\n", r); } /* sample upnp client program */ int main(int argc, char ** argv) { char command = 0; 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 WSADATA wsaData; int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); if(nResult != NO_ERROR) { fprintf(stderr, "WSAStartup() failed.\n"); 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 */ for(i=1; i<argc; i++) { if(0 == strcmp(argv[i], "--help") || 0 == strcmp(argv[i], "-h")) { command = 0; break; } if(argv[i][0] == '-') { if(argv[i][1] == 'u') 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]; i++; commandargv = argv + i; commandargc = argc - i; break; } } else { fprintf(stderr, "option '%s' invalid\n", argv[i]); } } - if(!command || (command == 'a' && commandargc<4) + if(!command + || (command == 'a' && commandargc<4) || (command == 'd' && argc<2) || (command == 'r' && argc<2) || (command == 'A' && commandargc<6) || (command == 'U' && commandargc<2) || (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]); fprintf(stderr, " \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -G remote_ip remote_port internal_ip internal_port protocol\n\t\tGet Outbound Pinhole Timeout (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]); fprintf(stderr, "\nprotocol is UDP or TCP\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -e description : set description for port mapping.\n"); 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; struct IGDdatas data; if(devlist) { printf("List of UPNP devices found on the network :\n"); for(device = devlist; device; device = device->pNext) { printf(" desc: %s\n st: %s\n\n", device->descURL, device->st); } } - else + else if(!rootdescurl) { printf("upnpDiscover() error code=%d\n", error); } i = 1; if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr))) || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))) { switch(i) { case 1: printf("Found valid IGD : %s\n", urls.controlURL); break; case 2: printf("Found a (not connected?) IGD : %s\n", urls.controlURL); printf("Trying to continue anyway\n"); break; case 3: printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL); printf("Trying to continue anyway\n"); break; default: printf("Found device (igd ?) : %s\n", urls.controlURL); printf("Trying to continue anyway\n"); } printf("Local LAN ip address : %s\n", lanaddr); #if 0 printf("getting \"%s\"\n", urls.ipcondescURL); descXML = miniwget(urls.ipcondescURL, &descXMLsize); if(descXML) { /*fwrite(descXML, 1, descXMLsize, stdout);*/ free(descXML); descXML = NULL; } #endif switch(command) { case 'l': DisplayInfos(&urls, &data); ListRedirections(&urls, &data); break; case 'L': 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': SetPinholeAndTest(&urls, &data, commandargv[0], commandargv[1], commandargv[2], commandargv[3], commandargv[4], commandargv[5]); break; case 'U': GetPinholeAndUpdate(&urls, &data, commandargv[0], commandargv[1]); break; case 'C': for(i=0; i<commandargc; i++) { CheckPinhole(&urls, &data, commandargv[i]); } break; case 'K': for(i=0; i<commandargc; i++) { GetPinholePackets(&urls, &data, commandargv[i]); } break; case 'D': for(i=0; i<commandargc; i++) { RemovePinhole(&urls, &data, commandargv[i]); } break; @@ -688,33 +819,39 @@ int main(int argc, char ** argv) break; case 'G': GetPinholeOutboundTimeout(&urls, &data, commandargv[0], commandargv[1], commandargv[2], commandargv[3], commandargv[4]); break; case 'P': printf("Presentation URL found:\n"); printf(" %s\n", data.presentationurl); break; default: fprintf(stderr, "Unknown switch -%c\n", command); retcode = 1; } FreeUPNPUrls(&urls); } else { fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n"); retcode = 1; } freeUPNPDevlist(devlist); devlist = 0; } else { 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,257 +1,258 @@ -/* $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. * */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include "upnpcommands.h" #include "miniupnpc.h" #include "portlistingparse.h" static UNSIGNED_INTEGER my_atoui(const char * s) { return s ? ((UNSIGNED_INTEGER)STRTOUI(s, NULL, 0)) : 0; } /* * */ -LIBSPEC UNSIGNED_INTEGER +MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesSent(const char * controlURL, const char * servicetype) { struct NameValueParserData pdata; char * buffer; int bufsize; unsigned int r = 0; char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalBytesSent", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent"); r = my_atoui(p); ClearNameValueList(&pdata); return r; } /* * */ -LIBSPEC UNSIGNED_INTEGER +MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesReceived(const char * controlURL, const char * servicetype) { struct NameValueParserData pdata; char * buffer; int bufsize; unsigned int r = 0; char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalBytesReceived", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived"); r = my_atoui(p); ClearNameValueList(&pdata); return r; } /* * */ -LIBSPEC UNSIGNED_INTEGER +MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsSent(const char * controlURL, const char * servicetype) { struct NameValueParserData pdata; char * buffer; int bufsize; unsigned int r = 0; char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalPacketsSent", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent"); r = my_atoui(p); ClearNameValueList(&pdata); return r; } /* * */ -LIBSPEC UNSIGNED_INTEGER +MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsReceived(const char * controlURL, const char * servicetype) { struct NameValueParserData pdata; char * buffer; int bufsize; unsigned int r = 0; char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalPacketsReceived", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived"); r = my_atoui(p); ClearNameValueList(&pdata); return r; } /* 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, unsigned int * uptime, char * lastconnerror) { struct NameValueParserData pdata; char * buffer; int bufsize; char * p; char * up; char * err; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!status && !uptime) return UPNPCOMMAND_INVALID_ARGS; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetStatusInfo", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ free(buffer); buffer = NULL; up = GetValueFromNameValueList(&pdata, "NewUptime"); p = GetValueFromNameValueList(&pdata, "NewConnectionStatus"); err = GetValueFromNameValueList(&pdata, "NewLastConnectionError"); if(p && up) ret = UPNPCOMMAND_SUCCESS; if(status) { if(p){ strncpy(status, p, 64 ); status[63] = '\0'; }else status[0]= '\0'; } if(uptime) { if(up) sscanf(up,"%u",uptime); else - uptime = 0; + *uptime = 0; } if(lastconnerror) { if(err) { strncpy(lastconnerror, err, 64 ); lastconnerror[63] = '\0'; } else lastconnerror[0] = '\0'; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* 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) { struct NameValueParserData pdata; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!connectionType) return UPNPCOMMAND_INVALID_ARGS; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetConnectionTypeInfo", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewConnectionType"); /*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/ /* PossibleConnectionTypes will have several values.... */ if(p) { strncpy(connectionType, p, 64 ); connectionType[63] = '\0'; ret = UPNPCOMMAND_SUCCESS; } else connectionType[0] = '\0'; p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method. * Returns 2 values: Downloadlink bandwidth and Uplink bandwidth. * 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, unsigned int * bitrateUp) { struct NameValueParserData pdata; char * buffer; int bufsize; int ret = UPNPCOMMAND_UNKNOWN_ERROR; char * down; char * up; char * p; if(!bitrateDown && !bitrateUp) return UPNPCOMMAND_INVALID_ARGS; /* shouldn't we use GetCommonLinkProperties ? */ if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetCommonLinkProperties", 0, &bufsize))) { /*"GetLinkLayerMaxBitRates", 0, &bufsize);*/ return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; /*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/ /*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/ down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate"); up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate"); /*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/ @@ -266,833 +267,974 @@ UPNP_GetLinkLayerMaxBitRates(const char * controlURL, *bitrateDown = 0; } if(bitrateUp) { if(up) sscanf(up,"%u",bitrateUp); else *bitrateUp = 0; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* UPNP_GetExternalIPAddress() call the corresponding UPNP method. * if the third arg is not null the value is copied to it. * at least 16 bytes must be available * * Return values : * 0 : SUCCESS * NON ZERO : ERROR Either an UPnP error code or an unknown error. * * 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) { struct NameValueParserData pdata; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!extIpAdd || !controlURL || !servicetype) return UPNPCOMMAND_INVALID_ARGS; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetExternalIPAddress", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; /*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/ p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress"); if(p) { strncpy(extIpAdd, p, 16 ); extIpAdd[15] = '\0'; ret = UPNPCOMMAND_SUCCESS; } else extIpAdd[0] = '\0'; p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); 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; 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"; - 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);*/ /*buffer[bufsize] = '\0';*/ /*puts(buffer);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { 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) { /*struct NameValueParserData pdata;*/ struct UPNParg * DeletePortMappingArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!extPort || !proto) 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);*/ 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; +} + +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, char * extPort, char * intClient, char * intPort, char * protocol, char * desc, char * enabled, char * rHost, char * duration) { struct NameValueParserData pdata; struct UPNParg * GetPortMappingArgs; char * buffer; int bufsize; char * p; int r = UPNPCOMMAND_UNKNOWN_ERROR; if(!index) return UPNPCOMMAND_INVALID_ARGS; 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); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewRemoteHost"); if(p && rHost) { strncpy(rHost, p, 64); rHost[63] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewExternalPort"); if(p && extPort) { strncpy(extPort, p, 6); extPort[5] = '\0'; r = UPNPCOMMAND_SUCCESS; } p = GetValueFromNameValueList(&pdata, "NewProtocol"); if(p && protocol) { strncpy(protocol, p, 4); 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'; } p = GetValueFromNameValueList(&pdata, "NewEnabled"); if(p && enabled) { strncpy(enabled, p, 4); enabled[3] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); if(p && desc) { strncpy(desc, p, 80); desc[79] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); if(p && duration) { strncpy(duration, p, 16); duration[15] = '\0'; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { r = UPNPCOMMAND_UNKNOWN_ERROR; 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) { struct NameValueParserData pdata; char * buffer; int bufsize; char* p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetPortMappingNumberOfEntries", 0, &bufsize))) { return UPNPCOMMAND_HTTP_ERROR; } #ifdef DEBUG DisplayNameValueList(buffer, bufsize); #endif ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries"); if(numEntries && p) { *numEntries = 0; sscanf(p, "%u", numEntries); ret = UPNPCOMMAND_SUCCESS; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } /* 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, const char * proto, const char * remoteHost, char * intClient, char * intPort, char * desc, char * enabled, char * leaseDuration) { struct NameValueParserData pdata; struct UPNParg * GetPortMappingArgs; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!intPort || !intClient || !extPort || !proto) 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);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "NewInternalClient"); if(p) { strncpy(intClient, p, 16); intClient[15] = '\0'; ret = UPNPCOMMAND_SUCCESS; } else intClient[0] = '\0'; p = GetValueFromNameValueList(&pdata, "NewInternalPort"); if(p) { strncpy(intPort, p, 6); intPort[5] = '\0'; } else intPort[0] = '\0'; p = GetValueFromNameValueList(&pdata, "NewEnabled"); if(p && enabled) { strncpy(enabled, p, 4); enabled[3] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); if(p && desc) { strncpy(desc, p, 80); desc[79] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); if(p && leaseDuration) { strncpy(leaseDuration, p, 16); leaseDuration[15] = '\0'; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); - free(GetPortMappingArgs); return ret; } /* UPNP_GetListOfPortMappings() * * Possible UPNP Error codes : * 606 Action not Authorized * 730 PortMappingNotFound - no port mapping is found in the specified range. * 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, const char * endPort, const char * protocol, const char * numberOfPorts, struct PortMappingParserData * data) { struct NameValueParserData pdata; struct UPNParg * GetListOfPortMappingsArgs; const char * p; char * buffer; int bufsize; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!startPort || !endPort || !protocol) 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"; GetListOfPortMappingsArgs[1].val = endPort; GetListOfPortMappingsArgs[2].elt = "NewProtocol"; GetListOfPortMappingsArgs[2].val = protocol; GetListOfPortMappingsArgs[3].elt = "NewManage"; GetListOfPortMappingsArgs[3].val = "1"; 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); free(buffer); buffer = NULL; /*p = GetValueFromNameValueList(&pdata, "NewPortListing");*/ /*if(p) { printf("NewPortListing : %s\n", p); }*/ /*printf("NewPortListing(%d chars) : %s\n", pdata.portListingLength, pdata.portListing);*/ if(pdata.portListing) { /*struct PortMapping * pm; int i = 0;*/ ParsePortListing(pdata.portListing, pdata.portListingLength, data); ret = UPNPCOMMAND_SUCCESS; /* for(pm = data->head.lh_first; pm != NULL; pm = pm->entries.le_next) { printf("%2d %s %5hu->%s:%-5hu '%s' '%s'\n", i, pm->protocol, pm->externalPort, pm->internalClient, pm->internalPort, pm->description, pm->remoteHost); i++; } */ /*FreePortListing(&data);*/ } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); /*printf("%.*s", bufsize, buffer);*/ return ret; } /* IGD:2, functions for service WANIPv6FirewallControl:1 */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetFirewallStatus(const char * controlURL, const char * servicetype, int * firewallEnabled, int * inboundPinholeAllowed) { struct NameValueParserData pdata; char * buffer; int bufsize; char * fe, *ipa, *p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!firewallEnabled || !inboundPinholeAllowed) return UPNPCOMMAND_INVALID_ARGS; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetFirewallStatus", 0, &bufsize); if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; fe = GetValueFromNameValueList(&pdata, "FirewallEnabled"); ipa = GetValueFromNameValueList(&pdata, "InboundPinholeAllowed"); if(ipa && fe) ret = UPNPCOMMAND_SUCCESS; if(fe) *firewallEnabled = my_atoui(fe); /*else *firewallEnabled = 0;*/ if(ipa) *inboundPinholeAllowed = my_atoui(ipa); /*else *inboundPinholeAllowed = 0;*/ p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); return ret; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, const char * intClient, const char * intPort, const char * proto, int * opTimeout) { struct UPNParg * GetOutboundPinholeTimeoutArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; char * p; int ret; if(!intPort || !intClient || !proto || !remotePort || !remoteHost) 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"; GetOutboundPinholeTimeoutArgs[1].val = remotePort; GetOutboundPinholeTimeoutArgs[2].elt = "Protocol"; GetOutboundPinholeTimeoutArgs[2].val = proto; GetOutboundPinholeTimeoutArgs[3].elt = "InternalPort"; GetOutboundPinholeTimeoutArgs[3].val = intPort; GetOutboundPinholeTimeoutArgs[4].elt = "InternalClient"; GetOutboundPinholeTimeoutArgs[4].val = intClient; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize); + free(GetOutboundPinholeTimeoutArgs); 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; p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout"); if(p) *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, const char * intClient, const char * intPort, const char * proto, const char * leaseTime, char * uniqueID) { struct UPNParg * AddPinholeArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; char * p; int ret; if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime) 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) { AddPinholeArgs[0].elt = "RemoteHost"; AddPinholeArgs[0].val = ""; } else { AddPinholeArgs[0].elt = "RemoteHost"; AddPinholeArgs[0].val = remoteHost; } AddPinholeArgs[1].elt = "RemotePort"; AddPinholeArgs[1].val = remotePort; AddPinholeArgs[2].elt = "Protocol"; AddPinholeArgs[2].val = proto; AddPinholeArgs[3].elt = "InternalPort"; AddPinholeArgs[3].val = intPort; if(strncmp(intClient, "empty", 5)==0) { AddPinholeArgs[4].elt = "InternalClient"; AddPinholeArgs[4].val = ""; } else { AddPinholeArgs[4].elt = "InternalClient"; AddPinholeArgs[4].val = intClient; } AddPinholeArgs[5].elt = "LeaseTime"; AddPinholeArgs[5].val = leaseTime; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "AddPinhole", AddPinholeArgs, &bufsize); + free(AddPinholeArgs); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "UniqueID"); if(p) { strncpy(uniqueID, p, 8); uniqueID[7] = '\0'; } resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { /*printf("AddPortMapping errorCode = '%s'\n", resVal);*/ ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { 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) { struct UPNParg * UpdatePinholeArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!uniqueID || !leaseTime) 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); free(buffer); buffer = NULL; resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { 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;*/ struct UPNParg * DeletePinholeArgs; char * buffer; int bufsize; struct NameValueParserData pdata; const char * resVal; int ret; if(!uniqueID) 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);*/ ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } else { ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); - free(DeletePinholeArgs); return ret; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, const char * uniqueID, int * isWorking) { struct NameValueParserData pdata; struct UPNParg * CheckPinholeWorkingArgs; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!uniqueID) 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; p = GetValueFromNameValueList(&pdata, "IsWorking"); if(p) { *isWorking=my_atoui(p); ret = UPNPCOMMAND_SUCCESS; } else *isWorking = 0; p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } ClearNameValueList(&pdata); - free(CheckPinholeWorkingArgs); return ret; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, const char * uniqueID, int * packets) { struct NameValueParserData pdata; struct UPNParg * GetPinholePacketsArgs; char * buffer; int bufsize; char * p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; if(!uniqueID) 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); free(buffer); buffer = NULL; p = GetValueFromNameValueList(&pdata, "PinholePackets"); if(p) { *packets=my_atoui(p); ret = UPNPCOMMAND_SUCCESS; } p = GetValueFromNameValueList(&pdata, "errorCode"); if(p) { ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(p, "%d", &ret); } 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,273 +1,348 @@ -/* $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 #define UPNPCOMMANDS_H_INCLUDED #include "upnpreplyparse.h" #include "portlistingparse.h" -#include "declspec.h" +#include "miniupnpc_declspec.h" #include "miniupnpctypes.h" /* MiniUPnPc return codes : */ #define UPNPCOMMAND_SUCCESS (0) #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); /* UPNP_GetStatusInfo() * status and lastconnerror are 64 byte buffers * 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, unsigned int * uptime, char * lastconnerror); /* UPNP_GetConnectionTypeInfo() * argument connectionType is a 64 character buffer * 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); /* UPNP_GetExternalIPAddress() call the corresponding UPNP method. * if the third arg is not null the value is copied to it. * at least 16 bytes must be available * * Return values : * 0 : SUCCESS * NON ZERO : ERROR Either an UPnP error code or an unknown error. * * 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); /* UPNP_GetLinkLayerMaxBitRates() * call WANCommonInterfaceConfig:1#GetCommonLinkProperties * * 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, unsigned int * bitrateUp); /* UPNP_AddPortMapping() * 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 * 718 ConflictInMappingEntry - The port mapping entry specified conflicts * with a mapping assigned previously to another client * 724 SamePortValuesRequired - Internal and External port values * must be the same * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports * permanent lease times on port mappings * 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(). * 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 : * 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); /* UPNP_GetSpecificPortMappingEntry() * retrieves an existing port mapping * params : * in extPort * in proto * in remoteHost * out intClient (16 bytes) * out intPort (6 bytes) * out desc (80 bytes) * out enabled (4 bytes) * out leaseDuration (16 bytes) * * 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, const char * proto, const char * remoteHost, char * intClient, char * intPort, char * desc, char * enabled, char * leaseDuration); /* UPNP_GetGenericPortMappingEntry() * params : * in index * out extPort (6 bytes) * out intClient (16 bytes) * out intPort (6 bytes) * out protocol (4 bytes) * out desc (80 bytes) * out enabled (4 bytes) * out rHost (64 bytes) * out duration (16 bytes) * * return value : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error Code. * * 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, char * extPort, char * intClient, char * intPort, char * protocol, char * desc, char * enabled, char * rHost, char * duration); /* UPNP_GetListOfPortMappings() Available in IGD v2 * * * Possible UPNP Error codes : * 606 Action not Authorized * 730 PortMappingNotFound - no port mapping is found in the specified range. * 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, const char * endPort, const char * protocol, const char * numberOfPorts, 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, const char * intClient, const char * intPort, const char * proto, int * opTimeout); -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_AddPinhole(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, const char * intClient, const char * intPort, const char * proto, 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); #ifdef __cplusplus } #endif #endif 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,56 +1,59 @@ -/* $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 * All Right reserved. * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #include <string.h> #include "upnperrors.h" #include "upnpcommands.h" #include "miniupnpc.h" const char * strupnperror(int err) { const char * s = NULL; switch(err) { case UPNPCOMMAND_SUCCESS: s = "Success"; break; case UPNPCOMMAND_UNKNOWN_ERROR: s = "Miniupnpc Unknown Error"; break; 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; case UPNPDISCOVER_MEMORY_ERROR: s = "Miniupnpc Memory allocation error"; break; case 401: s = "Invalid Action"; break; case 402: s = "Invalid Args"; break; case 501: s = "Action Failed"; break; case 606: s = "Action not authorized"; break; case 701: s = "PinholeSpaceExhausted"; break; case 702: s = "FirewallDisabled"; break; case 703: s = "InboundPinholeNotAllowed"; break; case 704: s = "NoSuchEntry"; 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,26 +1,26 @@ -/* $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/ * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #ifndef UPNPERRORS_H_INCLUDED #define UPNPERRORS_H_INCLUDED -#include "declspec.h" +#include "miniupnpc_declspec.h" #ifdef __cplusplus extern "C" { #endif /* 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 } #endif #endif 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,183 +1,197 @@ -/* $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 */ #include <stdlib.h> #include <string.h> #include <stdio.h> #include "upnpreplyparse.h" #include "minixml.h" static void NameValueParserStartElt(void * d, const char * name, int l) { struct NameValueParserData * data = (struct NameValueParserData *)d; data->topelt = 1; if(l>63) l = 63; memcpy(data->curelt, name, l); data->curelt[l] = '\0'; data->cdata = NULL; data->cdatalen = 0; } static void NameValueParserEndElt(void * d, const char * name, int l) { struct NameValueParserData * data = (struct NameValueParserData *)d; struct NameValue * nv; (void)name; (void)l; if(!data->topelt) return; if(strcmp(data->curelt, "NewPortListing") != 0) { int l; /* standard case. Limited to n chars strings */ l = data->cdatalen; nv = malloc(sizeof(struct NameValue)); + if(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); nv->name[63] = '\0'; if(data->cdata != NULL) { memcpy(nv->value, data->cdata, l); nv->value[l] = '\0'; } else { 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; data->topelt = 0; } static void NameValueParserGetData(void * d, const char * datas, int l) { struct NameValueParserData * data = (struct NameValueParserData *)d; if(strcmp(data->curelt, "NewPortListing") == 0) { /* specific case for NewPortListing which is a XML Document */ data->portListing = malloc(l + 1); if(!data->portListing) { /* malloc error */ +#ifdef DEBUG + fprintf(stderr, "%s: error allocating memory", + "NameValueParserGetData"); +#endif /* DEBUG */ return; } memcpy(data->portListing, datas, l); data->portListing[l] = '\0'; data->portListingLength = l; } else { /* standard case. */ data->cdata = datas; data->cdatalen = l; } } void ParseNameValue(const char * buffer, int bufsize, struct NameValueParserData * data) { - struct xmlparser parser; - 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 ClearNameValueList(struct NameValueParserData * pdata) { struct NameValue * nv; if(pdata->portListing) { free(pdata->portListing); 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); } } char * GetValueFromNameValueList(struct NameValueParserData * pdata, const char * Name) { 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; } return p; } #if 0 /* useless now that minixml ignores namespaces by itself */ char * GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, const char * Name) { struct NameValue * nv; char * p = NULL; char * pname; for(nv = pdata->head.lh_first; (nv != NULL) && (p == NULL); nv = nv->entries.le_next) { pname = strrchr(nv->name, ':'); if(pname) pname++; else pname = nv->name; if(strcmp(pname, Name)==0) p = nv->value; } return p; } #endif /* debug all-in-one function * do parsing then display to stdout */ #ifdef DEBUG void DisplayNameValueList(char * buffer, int bufsize) { struct NameValueParserData pdata; struct NameValue * nv; ParseNameValue(buffer, bufsize, &pdata); - for(nv = pdata.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,59 +1,53 @@ -/* $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 * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #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; const char * cdata; int cdatalen; }; /* ParseNameValue() */ void ParseNameValue(const char * buffer, int bufsize, struct NameValueParserData * data); /* ClearNameValueList() */ void ClearNameValueList(struct NameValueParserData * pdata); /* GetValueFromNameValueList() */ char * GetValueFromNameValueList(struct NameValueParserData * pdata, const char * Name); #if 0 /* GetValueFromNameValueListIgnoreNS() */ char * GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, const char * Name); #endif /* DisplayNameValueList() */ #ifdef DEBUG |