diff options
Diffstat (limited to '3rdParty/LibMiniUPnPc/src')
34 files changed, 2565 insertions, 1163 deletions
diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE b/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE index 2434c86..0816733 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE @@ -1,5 +1,5 @@ MiniUPnPc -Copyright (c) 2005-2011, Thomas BERNARD +Copyright (c) 2005-2016, Thomas BERNARD All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/bsdqueue.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/bsdqueue.h index 1fe0599..c6afe1f 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/bsdqueue.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/bsdqueue.h @@ -36,7 +36,7 @@ #define _SYS_QUEUE_H_ /* - * This file defines five types of data structures: singly-linked lists, + * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues, and circular queues. * * @@ -95,7 +95,7 @@ struct name { \ struct type *slh_first; /* first element */ \ } - + #define SLIST_HEAD_INITIALIZER(head) \ { NULL } @@ -107,7 +107,7 @@ struct name { \ struct { \ struct type *sle_next; /* next element */ \ } - + /* * Singly-linked List access methods. */ @@ -322,8 +322,8 @@ struct { \ struct type **tqe_prev; /* address of previous next element */ \ } -/* - * tail queue access methods +/* + * tail queue access methods */ #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_END(head) NULL @@ -430,7 +430,7 @@ struct { \ } /* - * Circular queue access methods + * Circular queue access methods */ #define CIRCLEQ_FIRST(head) ((head)->cqh_first) #define CIRCLEQ_LAST(head) ((head)->cqh_last) diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h index f11e5e9..f5f8e30 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h @@ -1,24 +1,54 @@ -/* $Id: codelength.h,v 1.1 2008/10/06 22:04:06 nanard Exp $ */ +/* $Id: codelength.h,v 1.5 2015/07/09 12:40:18 nanard Exp $ */ /* Project : miniupnp * Author : Thomas BERNARD - * copyright (c) 2005-2008 Thomas Bernard + * copyright (c) 2005-2015 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ -#ifndef __CODELENGTH_H__ -#define __CODELENGTH_H__ +#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); + 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 7afd2b1..aed62c7 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c @@ -1,7 +1,7 @@ -/* $Id: connecthostport.c,v 1.5 2011/04/09 08:49:50 nanard Exp $ */ +/* $Id: connecthostport.c,v 1.17 2017/04/21 09:58:30 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard - * Copyright (c) 2010-2011 Thomas Bernard + * Copyright (c) 2010-2017 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ @@ -13,7 +13,7 @@ #include <string.h> #include <stdio.h> -#ifdef WIN32 +#ifdef _WIN32 #include <winsock2.h> #include <ws2tcpip.h> #include <io.h> @@ -21,24 +21,28 @@ #define snprintf _snprintf #define herror #define socklen_t int -#else /* #ifdef WIN32 */ +#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 */ -#endif /* #else WIN32 */ +#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()); +#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 @@ -49,10 +53,15 @@ #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) +int connecthostport(const char * host, unsigned short port, + unsigned int scope_id) { int s, n; #ifdef USE_GETHOSTBYNAME @@ -67,7 +76,7 @@ int connecthostport(const char * host, unsigned short port) #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT struct timeval timeout; #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ - + #ifdef USE_GETHOSTBYNAME hp = gethostbyname(host); if(hp == NULL) @@ -85,24 +94,27 @@ int connecthostport(const char * host, unsigned short port) } #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT /* setting a 3 seconds timeout for the connect() call */ - timeout.tv_sec = 5; + 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 = 5; + 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; @@ -145,10 +157,12 @@ int connecthostport(const char * host, unsigned short port) if(host[0] == '[') { /* literal ip v6 address */ - int i; - for(i = 0; host[i+1] && (host[i+1] != ']') && i < MAXHOSTNAMELEN; i++) + int i, j; + for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++) { - tmp_host[i] = host[i+1]; + tmp_host[i] = host[j]; + if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */ + j+=2; /* skip "25" */ } tmp_host[i] = '\0'; } @@ -160,7 +174,7 @@ int connecthostport(const char * host, unsigned short port) n = getaddrinfo(tmp_host, port_str, &hints, &ai); if(n != 0) { -#ifdef WIN32 +#ifdef _WIN32 fprintf(stderr, "getaddrinfo() error : %d\n", n); #else fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n)); @@ -173,15 +187,19 @@ int connecthostport(const char * host, unsigned short port) 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 = 5; + 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 = 5; + timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) { @@ -190,7 +208,10 @@ int connecthostport(const char * host, unsigned short port) #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ n = connect(s, p->ai_addr, p->ai_addrlen); #ifdef MINIUPNPC_IGNORE_EINTR - while(n < 0 && errno == EINTR) + /* EINTR The system call was interrupted by a signal that was caught + * EINPROGRESS The socket is nonblocking and the connection cannot + * be completed immediately. */ + while(n < 0 && (errno == EINTR || errno == EINPROGRESS)) { socklen_t len; fd_set wset; diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.h index 57e24eb..56941d6 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.h @@ -1,17 +1,18 @@ -/* $Id: connecthostport.h,v 1.1 2010/04/04 23:21:03 nanard Exp $ */ +/* $Id: connecthostport.h,v 1.3 2012/09/27 15:42:10 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ * Author: Thomas Bernard - * Copyright (c) 2010 Thomas Bernard + * Copyright (c) 2010-2012 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ -#ifndef __CONNECTHOSTPORT_H__ -#define __CONNECTHOSTPORT_H__ +#ifndef CONNECTHOSTPORT_H_INCLUDED +#define CONNECTHOSTPORT_H_INCLUDED /* 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); +int connecthostport(const char * host, unsigned short port, + unsigned int scope_id); #endif diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/declspec.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/declspec.h index b804247..f66b6d7 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/declspec.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/declspec.h @@ -1,7 +1,7 @@ -#ifndef __DECLSPEC_H__ -#define __DECLSPEC_H__ +#ifndef DECLSPEC_H_INCLUDED +#define DECLSPEC_H_INCLUDED -#if defined(WIN32) && !defined(STATICLIB) +#if defined(_WIN32) && !defined(STATICLIB) #ifdef MINIUPNP_EXPORTS #define LIBSPEC __declspec(dllexport) #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,8 +1,8 @@ -/* $Id: igd_desc_parse.c,v 1.14 2011/04/11 09:19:24 nanard Exp $ */ +/* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */ /* Project : miniupnp * http://miniupnp.free.fr/ * Author : Thomas Bernard - * Copyright (c) 2005-2010 Thomas Bernard + * Copyright (c) 2005-2015 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ @@ -15,7 +15,9 @@ void IGDstartelt(void * d, const char * name, int l) { struct IGDdatas * datas = (struct IGDdatas *)d; - memcpy( datas->cureltname, name, l); + if(l >= MINIUPNPC_URL_MAXSIZE) + l = MINIUPNPC_URL_MAXSIZE-1; + memcpy(datas->cureltname, name, l); datas->cureltname[l] = '\0'; datas->level++; if( (l==7) && !memcmp(name, "service", l) ) { @@ -26,6 +28,8 @@ void IGDstartelt(void * d, const char * name, int l) } } +#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) + /* End element handler : * update nesting level counter and update parser state if * service element is parsed */ @@ -36,23 +40,16 @@ void IGDendelt(void * d, const char * name, int l) /*printf("endelt %2d %.*s\n", datas->level, l, name);*/ if( (l==7) && !memcmp(name, "service", l) ) { - /* - if( datas->state < 1 - && !strcmp(datas->servicetype, - // "urn:schemas-upnp-org:service:WANIPConnection:1") ) - "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) - datas->state ++; - */ - if(0==strcmp(datas->tmp.servicetype, - "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) { + if(COMPARE(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) { memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service)); - } else if(0==strcmp(datas->tmp.servicetype, - "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1")) { + } else if(COMPARE(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) { memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service)); - } else if(0==strcmp(datas->tmp.servicetype, - "urn:schemas-upnp-org:service:WANIPConnection:1") - || 0==strcmp(datas->tmp.servicetype, - "urn:schemas-upnp-org:service:WANPPPConnection:1") ) { + } else if(COMPARE(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANIPConnection:") + || COMPARE(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANPPPConnection:") ) { if(datas->first.servicetype[0] == '\0') { memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service)); } else { @@ -93,6 +90,7 @@ void IGDdata(void * d, const char * data, int l) } } +#ifdef DEBUG void printIGD(struct IGDdatas * d) { printf("urlbase = '%s'\n", d->urlbase); @@ -121,5 +119,5 @@ void printIGD(struct IGDdatas * d) printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl); printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl); } - +#endif /* DEBUG */ diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h index bab1fd5..0de546b 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h @@ -1,13 +1,13 @@ -/* $Id: igd_desc_parse.h,v 1.10 2011/04/11 09:19:24 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__ -#define __IGD_DESC_PARSE_H__ +#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 */ @@ -42,7 +42,8 @@ struct IGDdatas { void IGDstartelt(void *, const char *, int); void IGDendelt(void *, const char *, int); void IGDdata(void *, const char *, int); +#ifdef DEBUG void printIGD(struct IGDdatas *); +#endif /* DEBUG */ -#endif - +#endif /* IGD_DESC_PARSE_H_INCLUDED */ diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c index 8889bf0..0b4de30 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c @@ -1,7 +1,7 @@ -/* $Id: minisoap.c,v 1.21 2011/03/22 19:15:35 nanard Exp $ */ +/* $Id: minisoap.c,v 1.25 2017/04/21 10:03:24 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard - * Copyright (c) 2005-2009 Thomas Bernard + * Copyright (c) 2005-2015 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * @@ -9,7 +9,7 @@ */ #include <stdio.h> #include <string.h> -#ifdef WIN32 +#ifdef _WIN32 #include <io.h> #include <winsock2.h> #define snprintf _snprintf @@ -24,8 +24,8 @@ /* only for malloc */ #include <stdlib.h> -#ifdef WIN32 -#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#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 @@ -43,10 +43,10 @@ httpWrite(int fd, const char * body, int bodysize, /* Note : my old linksys router only took into account * soap request that are sent into only one packet */ char * p; - /* TODO: AVOID MALLOC */ + /* TODO: AVOID MALLOC, we could use writev() for that */ p = malloc(headerssize+bodysize); if(!p) - return 0; + return -1; memcpy(p, headers, headerssize); memcpy(p+headerssize, body, bodysize); /*n = write(fd, p, headerssize+bodysize);*/ @@ -57,7 +57,7 @@ httpWrite(int fd, const char * body, int bodysize, /* disable send on the socket */ /* draytek routers dont seems to like that... */ #if 0 -#ifdef WIN32 +#ifdef _WIN32 if(shutdown(fd, SD_SEND)<0) { #else if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/ @@ -96,7 +96,7 @@ int soapPostSubmit(int fd, headerssize = snprintf(headerbuf, sizeof(headerbuf), "POST %s HTTP/%s\r\n" "Host: %s%s\r\n" - "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" + "User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" "Content-Length: %d\r\n" "Content-Type: text/xml\r\n" "SOAPAction: \"%s\"\r\n" @@ -105,6 +105,8 @@ int soapPostSubmit(int fd, "Pragma: no-cache\r\n" "\r\n", url, httpversion, host, portstr, bodysize, action); + if ((unsigned int)headerssize >= sizeof(headerbuf)) + return -1; #ifdef DEBUG /*printf("SOAP request : headersize=%d bodysize=%d\n", headerssize, bodysize); diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.h index 696725f..14c859d 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.h @@ -1,11 +1,11 @@ -/* $Id: minisoap.h,v 1.4 2010/04/12 20:39:41 nanard Exp $ */ +/* $Id: minisoap.h,v 1.5 2012/09/27 15:42:10 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ -#ifndef __MINISOAP_H__ -#define __MINISOAP_H__ +#ifndef MINISOAP_H_INCLUDED +#define MINISOAP_H_INCLUDED /*int httpWrite(int, const char *, int, const char *);*/ int soapPostSubmit(int, const char *, const char *, unsigned short, diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c index a92c009..3a81939 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c @@ -1,77 +1,207 @@ -/* $Id: minissdpc.c,v 1.14 2010/11/25 09:57:25 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-2009 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> - -#ifndef WIN32 -#include <unistd.h> #include <sys/types.h> -#else -#define ssize_t int +#if defined (__NetBSD__) +#include <net/if.h> #endif - -#if defined(WIN32) || defined(__amigaos__) || defined(__amigaos4__) -#ifdef WIN32 +#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) +#ifdef _WIN32 #include <winsock2.h> #include <ws2tcpip.h> #include <io.h> +#include <iphlpapi.h> #include <winsock.h> -#if _MSC_VER >= 1600 +#define snprintf _snprintf +#if !defined(_MSC_VER) #include <stdint.h> -#else -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -#endif -#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 */ @@ -79,17 +209,45 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) { /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ close(s); - return NULL; + return MINISSDPC_SOCKET_ERROR; } + return s; +} + +int +disconnectFromMiniSSDPD(int s) +{ + if (close(s) < 0) + return MINISSDPC_SOCKET_ERROR; + return MINISSDPC_SUCCESS; +} + +int +requestDevicesFromMiniSSDPD(int s, const char * devtype) +{ + unsigned char buffer[256]; + unsigned char * p; + unsigned int stsize, l; + stsize = strlen(devtype); - buffer[0] = 1; /* request type 1 : request devices/services by type */ + if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8)) + { + buffer[0] = 3; /* request type 3 : everything */ + } + else + { + buffer[0] = 1; /* request type 1 : request devices/services by type */ + } p = buffer + 1; l = stsize; CODELENGTH(l, p); if(p + stsize > buffer + sizeof(buffer)) { /* devtype is too long ! */ - close(s); - return NULL; +#ifdef DEBUG + fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n", + stsize, (unsigned)sizeof(buffer)); +#endif /* DEBUG */ + return MINISSDPC_INVALID_INPUT; } memcpy(p, devtype, stsize); p += stsize; @@ -97,47 +255,634 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) { /*syslog(LOG_ERR, "write(): %m");*/ perror("minissdpc.c: write()"); - close(s); - return NULL; + return MINISSDPC_SOCKET_ERROR; } + return MINISSDPC_SUCCESS; +} + +struct UPNPDev * +receiveDevicesFromMiniSSDPD(int s, int * error) +{ + struct UPNPDev * tmp; + struct UPNPDev * devlist = NULL; + unsigned char buffer[256]; + ssize_t n; + unsigned char * p; + unsigned char * url; + unsigned char * st; + unsigned int bufferindex; + unsigned int i, ndev; + unsigned int urlsize, stsize, usnsize, l; + n = read(s, buffer, sizeof(buffer)); if(n<=0) { perror("minissdpc.c: read()"); - close(s); + if (error) + *error = MINISSDPC_SOCKET_ERROR; return NULL; } - p = buffer + 1; - for(i = 0; i < buffer[0]; i++) + ndev = buffer[0]; + bufferindex = 1; + for(i = 0; i < ndev; i++) { - if(p+2>=buffer+sizeof(buffer)) - break; - DECODELENGTH(urlsize, p); - if(p+urlsize+2>=buffer+sizeof(buffer)) - break; - url = p; - p += urlsize; - DECODELENGTH(stsize, p); - if(p+stsize+2>=buffer+sizeof(buffer)) - break; - tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); + DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER); + if(n<=0) { + if (error) + *error = MINISSDPC_INVALID_SERVER_REPLY; + return devlist; + } +#ifdef DEBUG + printf(" urlsize=%u", urlsize); +#endif /* DEBUG */ + url = malloc(urlsize); + if(url == NULL) { + if (error) + *error = MINISSDPC_MEMORY_ERROR; + return devlist; + } + READ_COPY_BUFFER(url, urlsize); + if(n<=0) { + if (error) + *error = MINISSDPC_INVALID_SERVER_REPLY; + goto free_url_and_return; + } + DECODELENGTH_READ(stsize, READ_BYTE_BUFFER); + if(n<=0) { + if (error) + *error = MINISSDPC_INVALID_SERVER_REPLY; + goto free_url_and_return; + } +#ifdef DEBUG + printf(" stsize=%u", stsize); +#endif /* DEBUG */ + st = malloc(stsize); + if (st == NULL) { + if (error) + *error = MINISSDPC_MEMORY_ERROR; + goto free_url_and_return; + } + READ_COPY_BUFFER(st, stsize); + if(n<=0) { + if (error) + *error = MINISSDPC_INVALID_SERVER_REPLY; + goto free_url_and_st_and_return; + } + DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER); + if(n<=0) { + if (error) + *error = MINISSDPC_INVALID_SERVER_REPLY; + goto free_url_and_st_and_return; + } +#ifdef DEBUG + printf(" usnsize=%u\n", usnsize); +#endif /* DEBUG */ + tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize); + if(tmp == NULL) { + if (error) + *error = MINISSDPC_MEMORY_ERROR; + goto free_url_and_st_and_return; + } tmp->pNext = devlist; tmp->descURL = tmp->buffer; tmp->st = tmp->buffer + 1 + urlsize; memcpy(tmp->buffer, url, urlsize); tmp->buffer[urlsize] = '\0'; - memcpy(tmp->buffer + urlsize + 1, p, stsize); - p += stsize; + memcpy(tmp->st, st, stsize); tmp->buffer[urlsize+1+stsize] = '\0'; + free(url); + free(st); + url = NULL; + st = NULL; + tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize; + READ_COPY_BUFFER(tmp->usn, usnsize); + if(n<=0) { + if (error) + *error = MINISSDPC_INVALID_SERVER_REPLY; + goto free_tmp_and_return; + } + tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0'; + tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */ devlist = tmp; - /* added for compatibility with recent versions of MiniSSDPd - * >= 2007/12/19 */ - DECODELENGTH(usnsize, p); - p += usnsize; - if(p>buffer + sizeof(buffer)) + } + if (error) + *error = MINISSDPC_SUCCESS; + return devlist; + +free_url_and_st_and_return: + free(st); +free_url_and_return: + free(url); + return devlist; + +free_tmp_and_return: + free(tmp); + return devlist; +} + +#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */ + +/* parseMSEARCHReply() + * the last 4 arguments are filled during the parsing : + * - location/locationsize : "location:" field of the SSDP reply packet + * - st/stsize : "st:" field of the SSDP reply packet. + * The strings are NOT null terminated */ +static void +parseMSEARCHReply(const char * reply, int size, + const char * * location, int * locationsize, + const char * * st, int * stsize, + const char * * usn, int * usnsize) +{ + int a, b, i; + i = 0; + a = i; /* start of the line */ + b = 0; /* end of the "header" (position of the colon) */ + while(i<size) + { + switch(reply[i]) + { + case ':': + if(b==0) + { + b = i; /* end of the "header" */ + /*for(j=a; j<b; j++) + { + putchar(reply[j]); + } + */ + } + break; + case '\x0a': + case '\x0d': + if(b!=0) + { + /*for(j=b+1; j<i; j++) + { + putchar(reply[j]); + } + putchar('\n');*/ + /* skip the colon and white spaces */ + do { b++; } while(reply[b]==' '); + if(0==strncasecmp(reply+a, "location", 8)) + { + *location = reply+b; + *locationsize = i-b; + } + else if(0==strncasecmp(reply+a, "st", 2)) + { + *st = reply+b; + *stsize = i-b; + } + else if(0==strncasecmp(reply+a, "usn", 3)) + { + *usn = reply+b; + *usnsize = i-b; + } + b = 0; + } + a = i+1; + break; + default: + break; + } + i++; + } +} + +/* port upnp discover : SSDP protocol */ +#define SSDP_PORT 1900 +#define XSTR(s) STR(s) +#define STR(s) #s +#define UPNP_MCAST_ADDR "239.255.255.250" +/* for IPv6 */ +#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */ +#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */ + +/* direct discovery if minissdpd responses are not sufficient */ +/* ssdpDiscoverDevices() : + * return a chained list of all devices found or NULL if + * no devices was found. + * It is up to the caller to free the chained list + * delay is in millisecond (poll). + * UDA v1.1 says : + * The TTL for the IP packet SHOULD default to 2 and + * SHOULD be configurable. */ +struct UPNPDev * +ssdpDiscoverDevices(const char * const deviceTypes[], + int delay, const char * multicastif, + int localport, + int ipv6, unsigned char ttl, + int * error, + int searchalltypes) +{ + struct UPNPDev * tmp; + struct UPNPDev * devlist = 0; + unsigned int scope_id = 0; + int opt = 1; + static const char MSearchMsgFmt[] = + "M-SEARCH * HTTP/1.1\r\n" + "HOST: %s:" XSTR(SSDP_PORT) "\r\n" + "ST: %s\r\n" + "MAN: \"ssdp:discover\"\r\n" + "MX: %u\r\n" + "\r\n"; + int deviceIndex; + char bufr[1536]; /* reception and emission buffer */ + int sudp; + int n; + struct sockaddr_storage sockudp_r; + unsigned int mx; +#ifdef NO_GETADDRINFO + struct sockaddr_storage sockudp_w; +#else + int rv; + struct addrinfo hints, *servinfo, *p; +#endif +#ifdef _WIN32 + MIB_IPFORWARDROW ip_forward; + unsigned long _ttl = (unsigned long)ttl; +#endif + int linklocal = 1; + int sentok; + + if(error) + *error = MINISSDPC_UNKNOWN_ERROR; + + if(localport==UPNP_LOCAL_PORT_SAME) + localport = SSDP_PORT; + +#ifdef _WIN32 + sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP); +#else + sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0); +#endif + if(sudp < 0) + { + if(error) + *error = MINISSDPC_SOCKET_ERROR; + PRINT_SOCKET_ERROR("socket"); + return NULL; + } + /* reception */ + memset(&sockudp_r, 0, sizeof(struct sockaddr_storage)); + if(ipv6) { + struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r; + p->sin6_family = AF_INET6; + if(localport > 0 && localport < 65536) + p->sin6_port = htons((unsigned short)localport); + p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */ + } else { + struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; + p->sin_family = AF_INET; + if(localport > 0 && localport < 65536) + p->sin_port = htons((unsigned short)localport); + p->sin_addr.s_addr = INADDR_ANY; + } +#ifdef _WIN32 +/* This code could help us to use the right Network interface for + * SSDP multicast traffic */ +/* Get IP associated with the index given in the ip_forward struct + * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ + if(!ipv6 + && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) { + DWORD dwRetVal = 0; + PMIB_IPADDRTABLE pIPAddrTable; + DWORD dwSize = 0; +#ifdef DEBUG + IN_ADDR IPAddr; +#endif + int i; +#ifdef DEBUG + printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); +#endif + pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); + if(pIPAddrTable) { + if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free(pIPAddrTable); + pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); + } + } + if(pIPAddrTable) { + dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); + if (dwRetVal == NO_ERROR) { +#ifdef DEBUG + printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); +#endif + for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { +#ifdef DEBUG + printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); + IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; + printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); + IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; + printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); + IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; + printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); + printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); + printf("\tType and State[%d]:", i); + printf("\n"); +#endif + if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { + /* Set the address of this interface to be used */ + struct in_addr mc_if; + memset(&mc_if, 0, sizeof(mc_if)); + mc_if.s_addr = pIPAddrTable->table[i].dwAddr; + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { + PRINT_SOCKET_ERROR("setsockopt"); + } + ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; +#ifndef DEBUG + break; +#endif + } + } + } + free(pIPAddrTable); + pIPAddrTable = NULL; + } + } +#endif /* _WIN32 */ + +#ifdef _WIN32 + if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) +#else + if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) +#endif + { + if(error) + *error = MINISSDPC_SOCKET_ERROR; + PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)"); + return NULL; + } + + if(ipv6) { + int mcastHops = ttl; + if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastHops, sizeof(mcastHops)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt(IPV6_MULTICAST_HOPS,...)"); + } + } else { +#ifdef _WIN32 + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0) +#else /* _WIN32 */ + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) +#endif /* _WIN32 */ + { + /* not a fatal error */ + PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)"); + } + } + + if(multicastif) + { + if(ipv6) { +#if !defined(_WIN32) + /* according to MSDN, if_nametoindex() is supported since + * MS Windows Vista and MS Windows Server 2008. + * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */ + unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ + if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt IPV6_MULTICAST_IF"); + } +#else +#ifdef DEBUG + printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); +#endif +#endif + } else { + struct in_addr mc_if; + mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ + if(mc_if.s_addr != INADDR_NONE) + { + ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); + } + } else { +#ifdef HAS_IP_MREQN + /* was not an ip address, try with an interface name */ + struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ + memset(&reqn, 0, sizeof(struct ip_mreqn)); + reqn.imr_ifindex = if_nametoindex(multicastif); + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); + } +#elif !defined(_WIN32) + struct ifreq ifr; + int ifrlen = sizeof(ifr); + strncpy(ifr.ifr_name, multicastif, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0) + { + PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)"); + } + mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); + } +#else /* _WIN32 */ +#ifdef DEBUG + printf("Setting of multicast interface not supported with interface name.\n"); +#endif +#endif /* #ifdef HAS_IP_MREQN / !defined(_WIN32) */ + } + } + } + + /* Before sending the packed, we first "bind" in order to be able + * to receive the response */ + if (bind(sudp, (const struct sockaddr *)&sockudp_r, + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) + { + if(error) + *error = MINISSDPC_SOCKET_ERROR; + PRINT_SOCKET_ERROR("bind"); + closesocket(sudp); + return NULL; + } + + if(error) + *error = MINISSDPC_SUCCESS; + /* Calculating maximum response time in seconds */ + mx = ((unsigned int)delay) / 1000u; + if(mx == 0) { + mx = 1; + delay = 1000; + } + /* receiving SSDP response packet */ + for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) { + sentok = 0; + /* sending the SSDP M-SEARCH packet */ + n = snprintf(bufr, sizeof(bufr), + MSearchMsgFmt, + ipv6 ? + (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") + : UPNP_MCAST_ADDR, + deviceTypes[deviceIndex], mx); + if ((unsigned int)n >= sizeof(bufr)) { + if(error) + *error = MINISSDPC_MEMORY_ERROR; + goto error; + } +#ifdef DEBUG + /*printf("Sending %s", bufr);*/ + printf("Sending M-SEARCH request to %s with ST: %s\n", + ipv6 ? + (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") + : UPNP_MCAST_ADDR, + deviceTypes[deviceIndex]); +#endif +#ifdef NO_GETADDRINFO + /* the following code is not using getaddrinfo */ + /* emission */ + memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); + if(ipv6) { + struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; + p->sin6_family = AF_INET6; + p->sin6_port = htons(SSDP_PORT); + inet_pton(AF_INET6, + linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, + &(p->sin6_addr)); + } else { + struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; + p->sin_family = AF_INET; + p->sin_port = htons(SSDP_PORT); + p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); + } + n = sendto(sudp, bufr, n, 0, &sockudp_w, + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + if (n < 0) { + if(error) + *error = MINISSDPC_SOCKET_ERROR; + PRINT_SOCKET_ERROR("sendto"); + } else { + sentok = 1; + } +#else /* #ifdef NO_GETADDRINFO */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */ + hints.ai_socktype = SOCK_DGRAM; + /*hints.ai_flags = */ + if ((rv = getaddrinfo(ipv6 + ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) + : UPNP_MCAST_ADDR, + XSTR(SSDP_PORT), &hints, &servinfo)) != 0) { + if(error) + *error = MINISSDPC_SOCKET_ERROR; +#ifdef _WIN32 + fprintf(stderr, "getaddrinfo() failed: %d\n", rv); +#else + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); +#endif break; + } + for(p = servinfo; p; p = p->ai_next) { + n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); + if (n < 0) { +#ifdef DEBUG + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, + sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { + fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); + } +#endif + PRINT_SOCKET_ERROR("sendto"); + continue; + } else { + sentok = 1; + } + } + freeaddrinfo(servinfo); + if(!sentok) { + if(error) + *error = MINISSDPC_SOCKET_ERROR; + } +#endif /* #ifdef NO_GETADDRINFO */ + /* Waiting for SSDP REPLY packet to M-SEARCH + * if searchalltypes is set, enter the loop only + * when the last deviceType is reached */ + if((sentok && !searchalltypes) || !deviceTypes[deviceIndex + 1]) do { + n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id); + if (n < 0) { + /* error */ + if(error) + *error = MINISSDPC_SOCKET_ERROR; + goto error; + } else if (n == 0) { + /* no data or Time Out */ +#ifdef DEBUG + printf("NODATA or TIMEOUT\n"); +#endif /* DEBUG */ + if (devlist && !searchalltypes) { + /* found some devices, stop now*/ + if(error) + *error = MINISSDPC_SUCCESS; + goto error; + } + } else { + const char * descURL=NULL; + int urlsize=0; + const char * st=NULL; + int stsize=0; + const char * usn=NULL; + int usnsize=0; + parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize); + if(st&&descURL) { +#ifdef DEBUG + printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n", + stsize, st, usnsize, (usn?usn:""), urlsize, descURL); +#endif /* DEBUG */ + for(tmp=devlist; tmp; tmp = tmp->pNext) { + if(memcmp(tmp->descURL, descURL, urlsize) == 0 && + tmp->descURL[urlsize] == '\0' && + memcmp(tmp->st, st, stsize) == 0 && + tmp->st[stsize] == '\0' && + (usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) && + tmp->usn[usnsize] == '\0') + break; + } + /* at the exit of the loop above, tmp is null if + * no duplicate device was found */ + if(tmp) + continue; + tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize); + if(!tmp) { + /* memory allocation error */ + if(error) + *error = MINISSDPC_MEMORY_ERROR; + goto error; + } + tmp->pNext = devlist; + tmp->descURL = tmp->buffer; + tmp->st = tmp->buffer + 1 + urlsize; + tmp->usn = tmp->st + 1 + stsize; + memcpy(tmp->buffer, descURL, urlsize); + tmp->buffer[urlsize] = '\0'; + memcpy(tmp->st, st, stsize); + tmp->buffer[urlsize+1+stsize] = '\0'; + if(usn != NULL) + memcpy(tmp->usn, usn, usnsize); + tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0'; + tmp->scope_id = scope_id; + devlist = tmp; + } + } + } while(n > 0); + if(ipv6) { + /* switch linklocal flag */ + if(linklocal) { + linklocal = 0; + --deviceIndex; + } else { + linklocal = 1; + } + } } - close(s); +error: + closesocket(sudp); return devlist; } diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h index 25e91ce..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.1 2007/08/31 15:15:33 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__ -#define __MINISSDPC_H__ +#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 bd46a24..2dc5c95 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c @@ -1,31 +1,22 @@ -/* $Id: miniupnpc.c,v 1.95 2011/05/15 21:42:26 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-2011 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 - #include <stdlib.h> #include <stdio.h> #include <string.h> -#ifdef WIN32 +#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 @@ -34,7 +25,7 @@ #endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ #endif /* #ifndef strncasecmp */ #define MAXHOSTNAMELEN 64 -#else /* #ifdef WIN32 */ +#else /* #ifdef _WIN32 */ /* Standard POSIX includes */ #include <unistd.h> #if defined(__amigaos__) && !defined(__amigaos4__) @@ -56,15 +47,12 @@ #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 +#endif /* #else _WIN32 */ +#ifdef __GNU__ +#define MAXHOSTNAMELEN 64 #endif + #include "miniupnpc.h" #include "minissdpc.h" #include "miniwget.h" @@ -72,20 +60,39 @@ #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) +/* 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 */ @@ -116,80 +123,100 @@ char * simpleUPnPcommand2(int s, const char * url, const char * service, char * path; char soapact[128]; char soapbody[2048]; + int soapbodylen; char * buf; - int n; + int n; + int status_code; *bufsize = 0; snprintf(soapact, sizeof(soapact), "%s#%s", service, action); if(args==NULL) { - /*soapbodylen = */snprintf(soapbody, sizeof(soapbody), - "<?xml version=\"1.0\"?>\r\n" - "<" SOAPPREFIX ":Envelope " + soapbodylen = snprintf(soapbody, sizeof(soapbody), + "<?xml version=\"1.0\"?>\r\n" + "<" SOAPPREFIX ":Envelope " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" "</" SERVICEPREFIX ":%s>" "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>" - "\r\n", action, service, action); + "\r\n", action, service, action); + if ((unsigned int)soapbodylen >= sizeof(soapbody)) + return NULL; } else { char * p; const char * pe, * pv; - int soapbodylen; + const char * const pend = soapbody + sizeof(soapbody); soapbodylen = snprintf(soapbody, sizeof(soapbody), "<?xml version=\"1.0\"?>\r\n" - "<" SOAPPREFIX ":Envelope " + "<" SOAPPREFIX ":Envelope " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", action, service); + if ((unsigned int)soapbodylen >= sizeof(soapbody)) + return NULL; p = soapbody + soapbodylen; while(args->elt) { - /* check that we are never overflowing the string... */ - if(soapbody + sizeof(soapbody) <= p + 100) - { - /* we keep a margin of at least 100 bytes */ + if(p >= pend) /* check for space to write next byte */ return NULL; - } *(p++) = '<'; + pe = args->elt; - while(*pe) + while(p < pend && *pe) *(p++) = *(pe++); + + if(p >= pend) /* check for space to write next byte */ + return NULL; *(p++) = '>'; + if((pv = args->val)) { - while(*pv) + while(p < pend && *pv) *(p++) = *(pv++); } + + if((p+2) > pend) /* check for space to write next 2 bytes */ + return NULL; *(p++) = '<'; *(p++) = '/'; + pe = args->elt; - while(*pe) + while(p < pend && *pe) *(p++) = *(pe++); + + if(p >= pend) /* check for space to write next byte */ + return NULL; *(p++) = '>'; + args++; } + if((p+4) > pend) /* check for space to write next 4 bytes */ + return NULL; *(p++) = '<'; *(p++) = '/'; *(p++) = SERVICEPREFIX2; *(p++) = ':'; + pe = action; - while(*pe) + while(p < pend && *pe) *(p++) = *(pe++); + strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n", - soapbody + sizeof(soapbody) - p); + pend - p); + if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */ + return NULL; } - if(!parseURL(url, hostname, &port, &path)) return NULL; - if(s<0) - { - s = connecthostport(hostname, port); - if(s < 0) - { + 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; } } @@ -203,11 +230,15 @@ char * simpleUPnPcommand2(int s, const char * url, const char * service, return NULL; } - buf = getHTTPResponse(s, bufsize); + buf = getHTTPResponse(s, bufsize, &status_code); #ifdef DEBUG if(*bufsize > 0 && buf) { - printf("SOAP Response :\n%.*s\n", *bufsize, buf); + printf("HTTP %d SOAP Response :\n%.*s\n", status_code, *bufsize, buf); + } + else + { + printf("HTTP %d, empty SOAP response. size=%d\n", status_code, *bufsize); } #endif closesocket(s); @@ -225,8 +256,9 @@ char * simpleUPnPcommand(int s, const char * url, const char * service, { 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) { @@ -235,523 +267,246 @@ char * simpleUPnPcommand(int s, const char * url, const char * service, #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; - 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__) +#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 */ - ((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"); - } + 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) - { - 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; - /* receiving SSDP response packet */ - for(n = 0; deviceList[deviceIndex]; deviceIndex++) - { - if(n == 0) + /* direct discovery if minissdpd responses are not sufficient */ { - /* 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) { - PRINT_SOCKET_ERROR("sendto"); - continue; - } - } - freeaddrinfo(servinfo); - if(n < 0) { - if(error) - *error = UPNPDISCOVER_SOCKET_ERROR; - break; + 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; } -#endif /* #ifdef NO_GETADDRINFO */ } - /* Waiting for SSDP REPLY packet to M-SEARCH */ - n = receivedata(sudp, bufr, sizeof(bufr), delay); - 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'; - devlist = tmp; - } - } - } - 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); + static const char * const deviceList[] = { + /*"upnp:rootdevice",*/ + "ssdp:all", + 0 + }; + return upnpDiscoverDevices(deviceList, + delay, multicastif, minissdpdsock, localport, + ipv6, ttl, error, 0); +} + +/* 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; +#if defined(IF_NAMESIZE) && !defined(_WIN32) + char ifname[IF_NAMESIZE]; +#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ + char scope_str[8]; +#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; } - else - { - int l = strlen(dst); - if(src[0] != '/') - dst[l++] = '/'; - if(l<=n) - strncpy(dst + l, src, n - l); + l = n + strlen(url) + 1; + if(url[0] != '/') + l++; + if(scope_id != 0) { +#if defined(IF_NAMESIZE) && !defined(_WIN32) + if(if_indextoname(scope_id, ifname)) { + l += 3 + strlen(ifname); /* 3 == strlen(%25) */ + } +#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) */ + } + s = malloc(l); + if(s == NULL) return NULL; + memcpy(s, base, n); + if(scope_id != 0) { + s[n] = '\0'; + if(0 == memcmp(s, "http://[fe80:", 13)) { + /* this is a linklocal IPv6 address */ + p = strchr(s, ']'); + if(p) { + /* insert %25<scope> into URL */ +#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)); + 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)); + n += 3 + strlen(scope_str); +#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ + } + } } + if(url[0] != '/') + s[n++] = '/'; + memcpy(s + n, url, l - n); + return s; } /* Prepare the Urls for usage... */ -LIBSPEC void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, - const char * descURL) +MINIUPNP_LIBSPEC void +GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, + const char * descURL, unsigned int scope_id) { - char * p; - int n1, n2, n3, n4; - n1 = strlen(data->urlbase); - if(n1==0) - n1 = strlen(descURL); - 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); - - urls->ipcondescURL = (char *)malloc(n1); - urls->controlURL = (char *)malloc(n2); - urls->controlURL_CIF = (char *)malloc(n3); - urls->controlURL_6FC = (char *)malloc(n4); - /* maintenant on chope la desc du 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'; - 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); - - url_cpy_or_cat(urls->controlURL_CIF, data->CIF.controlurl, n3); - - url_cpy_or_cat(urls->controlURL_6FC, data->IPv6FC.controlurl, n4); + /* strdup descURL */ + urls->rootdescURL = strdup(descURL); + + /* 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) @@ -764,6 +519,8 @@ FreeUPNPUrls(struct UPNPUrls * urls) urls->controlURL_CIF = 0; free(urls->controlURL_6FC); urls->controlURL_6FC = 0; + free(urls->rootdescURL); + urls->rootdescURL = 0; } int @@ -775,9 +532,9 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, status, &uptime, NULL); if(0 == strcmp("Connected", status)) - { return 1; - } + else if(0 == strcmp("Up", status)) /* Also accept "Up" */ + return 1; else return 0; } @@ -785,27 +542,37 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) /* 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 non zero return case, the urls and data structures - * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to + * In any positive non zero return case, the urls and data structures + * 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) { - char * descXML; - int descXMLsize = 0; + struct xml_desc { + char * xml; + int size; + int is_igd; + } * desc = NULL; struct UPNPDev * dev; int ndev = 0; - int state; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ + 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 @@ -813,35 +580,75 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, #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), + 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(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; dev; dev = dev->pNext) + 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 */ - descXML = miniwget_getaddr(dev->descURL, &descXMLsize, - lanaddr, lanaddrlen); - if(descXML) + if(desc[i].xml) { - ndev++; memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); - parserootdesc(descXML, descXMLsize, data); - free(descXML); - descXML = NULL; - if(0==strcmp(data->CIF.servicetype, - "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1") - || state >= 3 ) + parserootdesc(desc[i].xml, desc[i].size, data); + if(desc[i].is_igd || state >= 3 ) { - GetUPNPUrls(urls, data, dev->descURL); + 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)); -#endif - if((state >= 2) || UPNPIGD_IsConnected(urls, data)) - return state; + urls->controlURL, is_connected); +#endif + /* checks that status is connected AND there is a external IP address assigned */ + 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 @@ -852,28 +659,36 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, 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); + 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((state >= 2) || UPNPIGD_IsConnected(urls, data)) - return state; + 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)); } -#ifdef DEBUG - else - { - printf("error getting XML description %s\n", dev->descURL); + } + } + state = 0; +free_and_return: + if(desc) { + for(i = 0; i < ndev; i++) { + if(desc[i].xml) { + free(desc[i].xml); } -#endif } + free(desc); } - return 0; + return state; } /* UPNP_GetIGDFromUrl() @@ -889,15 +704,16 @@ UPNP_GetIGDFromUrl(const char * rootdescurl, { char * descXML; int descXMLsize = 0; + descXML = miniwget_getaddr(rootdescurl, &descXMLsize, - lanaddr, lanaddrlen); + 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); + 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 50df017..51aaf5b 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h @@ -1,15 +1,16 @@ -/* $Id: miniupnpc.h,v 1.23 2011/04/11 08:21:46 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-2011 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__ -#define __MINIUPNPC_H__ +#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) @@ -17,6 +18,16 @@ #define UPNPDISCOVER_SOCKET_ERROR (-101) #define UPNPDISCOVER_MEMORY_ERROR (-102) +/* versions : */ +#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 @@ -29,13 +40,6 @@ simpleUPnPcommand(int, const char *, const char *, const char *, struct UPNParg *, int *); -struct UPNPDev { - struct UPNPDev * pNext; - char * descURL; - char * st; - char buffer[2]; -}; - /* upnpDiscover() * discover UPnP devices on the network. * The discovered devices are returned as a chained list. @@ -47,21 +51,43 @@ struct UPNPDev { * is NULL. * If multicastif is not NULL, it will be used instead of the default * multicast interface for sending SSDP discover packets. - * If sameport is not null, SSDP packets will be sent from the source port - * 1900 (same as destination port) otherwise system assign a source port. */ -LIBSPEC struct UPNPDev * + * If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent + * from the source port 1900 (same as destination port), if set to + * UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will + * be attempted as the source port. + * "searchalltypes" parameter is useful when searching several types, + * if 0, the discovery will stop with the first type returning results. + * TTL should default to 2. */ +MINIUPNP_LIBSPEC struct UPNPDev * upnpDiscover(int delay, const char * multicastif, - const char * minissdpdsock, int sameport, - int ipv6, + const char * minissdpdsock, int localport, + int ipv6, unsigned char ttl, int * error); -/* freeUPNPDevlist() - * free list returned by upnpDiscover() */ -LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); + +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverAll(int delay, const char * multicastif, + const char * minissdpdsock, int localport, + int ipv6, unsigned char ttl, + int * error); + +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverDevice(const char * device, int delay, const char * multicastif, + const char * minissdpdsock, int localport, + int ipv6, unsigned char ttl, + int * error); + +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverDevices(const char * const deviceTypes[], + int delay, const char * multicastif, + const char * minissdpdsock, int localport, + int ipv6, unsigned char ttl, + int * error, + int searchalltypes); /* parserootdesc() : * parse root XML description of a UPnP device and fill the IGDdatas * structure. */ -LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); +MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); /* structure used to get fast access to urls * controlURL: controlURL of the WANIPConnection @@ -74,6 +100,7 @@ struct UPNPUrls { char * ipcondescURL; char * controlURL_CIF; char * controlURL_6FC; + char * rootdescURL; }; /* UPNP_GetValidIGD() : @@ -88,7 +115,7 @@ struct UPNPUrls { * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to * free allocated memory. */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, @@ -96,21 +123,25 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, /* UPNP_GetIGDFromUrl() * Used when skipping the discovery process. + * When succeding, urls, data, and lanaddr arguments are set. * return value : * 0 - Not ok * 1 - OK */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen); -LIBSPEC void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *); +MINIUPNP_LIBSPEC void +GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, + const char *, unsigned int); -LIBSPEC void FreeUPNPUrls(struct UPNPUrls *); +MINIUPNP_LIBSPEC void +FreeUPNPUrls(struct UPNPUrls *); /* return 0 or 1 */ -LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); +MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); #ifdef __cplusplus diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc_declspec.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc_declspec.h new file mode 100644 index 0000000..40adb92 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc_declspec.h @@ -0,0 +1,21 @@ +#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED +#define MINIUPNPC_DECLSPEC_H_INCLUDED + +#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB) + /* for windows dll */ + #ifdef MINIUPNP_EXPORTS + #define MINIUPNP_LIBSPEC __declspec(dllexport) + #else + #define MINIUPNP_LIBSPEC __declspec(dllimport) + #endif +#else + #if defined(__GNUC__) && __GNUC__ >= 4 + /* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ + #define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default"))) + #else + #define MINIUPNP_LIBSPEC + #endif +#endif + +#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */ + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpctypes.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpctypes.h index 86081c3..591c32f 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpctypes.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpctypes.h @@ -1,11 +1,11 @@ -/* $Id: miniupnpctypes.h,v 1.1 2011/02/15 11:10:40 nanard Exp $ */ +/* $Id: miniupnpctypes.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */ /* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org * Author : Thomas Bernard * Copyright (c) 2011 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided within this distribution */ -#ifndef __MINIUPNPCTYPES_H__ -#define __MINIUPNPCTYPES_H__ +#ifndef MINIUPNPCTYPES_H_INCLUDED +#define MINIUPNPCTYPES_H_INCLUDED #if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) #define UNSIGNED_INTEGER unsigned long long diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c index 0c31416..e5099db 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c @@ -1,20 +1,20 @@ -/* $Id: miniwget.c,v 1.52 2011/06/17 22:59:42 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-2011 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 +#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 @@ -24,7 +24,7 @@ #define strncasecmp memicmp #endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ #endif /* #ifndef strncasecmp */ -#else /* #ifdef WIN32 */ +#else /* #ifdef _WIN32 */ #include <unistd.h> #include <sys/param.h> #if defined(__amigaos__) && !defined(__amigaos4__) @@ -33,26 +33,31 @@ #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 -#endif /* #else WIN32 */ -#if defined(__sun) || defined(sun) -#define MIN(x,y) (((x)<(y))?(x):(y)) -#endif +#include <strings.h> +#endif /* #else _WIN32 */ +#ifdef __GNU__ +#define MAXHOSTNAMELEN 64 +#endif /* __GNU__ */ -#ifdef __ANDROID__ +#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. @@ -60,7 +65,7 @@ * to the length parameter. */ void * -getHTTPResponse(int s, int * size) +getHTTPResponse(int s, int * size, int * status_code) { char buf[2048]; int n; @@ -71,20 +76,42 @@ getHTTPResponse(int s, int * size) unsigned int bytestocopy = 0; /* buffers : */ char * header_buf; - int header_buf_len = 2048; - int header_buf_used = 0; + unsigned int header_buf_len = 2048; + unsigned int header_buf_used = 0; char * content_buf; - int content_buf_len = 2048; - int content_buf_used = 0; + unsigned int content_buf_len = 2048; + unsigned int content_buf_used = 0; char chunksize_buf[32]; - int chunksize_buf_index; + 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)) > 0) + while((n = receivedata(s, buf, sizeof(buf), 5000, NULL)) > 0) { if(endofheaders == 0) { @@ -93,7 +120,15 @@ getHTTPResponse(int s, int * size) int colon=0; int valuestart=0; if(header_buf_used + n > header_buf_len) { - header_buf = realloc(header_buf, header_buf_used + n); + char * tmp = realloc(header_buf, header_buf_used + n); + if(tmp == NULL) { + /* memory allocation error */ + free(header_buf); + free(content_buf); + *size = -1; + return NULL; + } + header_buf = tmp; header_buf_len = header_buf_used + n; } memcpy(header_buf + header_buf_used, buf, n); @@ -101,14 +136,14 @@ getHTTPResponse(int s, int * size) /* search for CR LF CR LF (end of headers) * recognize also LF LF */ i = 0; - while(i < (header_buf_used-1) && (endofheaders == 0)) { + while(i < ((int)header_buf_used-1) && (endofheaders == 0)) { if(header_buf[i] == '\r') { i++; if(header_buf[i] == '\n') { i++; - if(i < header_buf_used && header_buf[i] == '\r') { + if(i < (int)header_buf_used && header_buf[i] == '\r') { i++; - if(i < header_buf_used && header_buf[i] == '\n') { + if(i < (int)header_buf_used && header_buf[i] == '\n') { endofheaders = i+1; } } @@ -125,7 +160,7 @@ getHTTPResponse(int s, int * size) continue; /* parse header lines */ for(i = 0; i < endofheaders - 1; i++) { - if(colon <= linestart && header_buf[i]==':') + if(linestart > 0 && colon <= linestart && header_buf[i]==':') { colon = i; while(i < (endofheaders-1) @@ -136,7 +171,31 @@ getHTTPResponse(int s, int * size) /* detecting end of line */ else if(header_buf[i]=='\r' || header_buf[i]=='\n') { - if(colon > linestart && valuestart > colon) + if(linestart == 0 && status_code) + { + /* Status line + * HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ + int sp; + for(sp = 0; sp < i; sp++) + if(header_buf[sp] == ' ') + { + if(*status_code < 0) + *status_code = atoi(header_buf + sp + 1); + else + { +#ifdef DEBUG + reason_phrase = header_buf + sp + 1; + reason_phrase_len = i - sp - 1; +#endif + break; + } + } +#ifdef DEBUG + printf("HTTP status code = %d, Reason phrase = %.*s\n", + *status_code, reason_phrase_len, reason_phrase); +#endif + } + else if(colon > linestart && valuestart > colon) { #ifdef DEBUG printf("header='%.*s', value='%.*s'\n", @@ -159,12 +218,12 @@ getHTTPResponse(int s, int * size) chunked = 1; } } - while(header_buf[i]=='\r' || header_buf[i] == '\n') + 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 */ n = header_buf_used - endofheaders; @@ -198,7 +257,7 @@ getHTTPResponse(int s, int * size) i++; /* discarding chunk-extension */ if(i<n && buf[i] == '\r') i++; if(i<n && buf[i] == '\n') { - int j; + unsigned int j; for(j = 0; j < chunksize_buf_index; j++) { if(chunksize_buf[j] >= '0' && chunksize_buf[j] <= '9') @@ -225,16 +284,25 @@ getHTTPResponse(int s, int * size) goto end_of_stream; } } - bytestocopy = ((int)chunksize < n - i)?chunksize:(n - i); - if((int)(content_buf_used + bytestocopy) > content_buf_len) + /* 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 >= content_buf_used + (int)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 + (int)bytestocopy; + 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; @@ -246,26 +314,35 @@ getHTTPResponse(int s, int * size) { /* not chunked */ if(content_length > 0 - && (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 >= 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 && content_buf_used >= content_length) + if(content_length > 0 && content_buf_used >= (unsigned int)content_length) { #ifdef DEBUG printf("End of HTTP content\n"); @@ -288,10 +365,11 @@ end_of_stream: * do all the work. * Return NULL if something failed. */ static void * -miniwget3(const char * url, const char * host, +miniwget3(const char * host, unsigned short port, const char * path, int * size, char * addr_str, int addr_str_len, - const char * httpversion) + const char * httpversion, unsigned int scope_id, + int * status_code) { char buf[2048]; int s; @@ -301,7 +379,7 @@ miniwget3(const char * url, const char * host, void * content; *size = 0; - s = connecthostport(host, port); + s = connecthostport(host, port, scope_id); if(s < 0) return NULL; @@ -347,7 +425,7 @@ miniwget3(const char * url, const char * host, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); if(n != 0) { -#ifdef WIN32 +#ifdef _WIN32 fprintf(stderr, "getnameinfo() failed : %d\n", n); #else fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); @@ -364,10 +442,15 @@ miniwget3(const char * url, const char * host, "GET %s HTTP/%s\r\n" "Host: %s:%d\r\n" "Connection: Close\r\n" - "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" + "User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" "\r\n", path, httpversion, host, port); + if ((unsigned int)len >= sizeof(buf)) + { + closesocket(s); + return NULL; + } sent = 0; /* sending the HTTP request */ while(sent < len) @@ -384,7 +467,7 @@ miniwget3(const char * url, const char * host, sent += n; } } - content = getHTTPResponse(s, size); + content = getHTTPResponse(s, size, status_code); closesocket(s); return content; } @@ -392,24 +475,32 @@ miniwget3(const char * url, const char * host, /* miniwget2() : * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */ static void * -miniwget2(const char * url, const char * host, - unsigned short port, const char * path, - int * size, char * addr_str, int addr_str_len) +miniwget2(const char * host, + unsigned short port, const char * path, + int * size, char * addr_str, int addr_str_len, + unsigned int scope_id, int * status_code) { char * respbuffer; - respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.1"); -/* - respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.0"); +#if 1 + respbuffer = miniwget3(host, port, path, size, + 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, status_code); if (*size == 0) { #ifdef DEBUG printf("Retrying with HTTP/1.1\n"); #endif free(respbuffer); - respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.1"); + respbuffer = miniwget3(host, port, path, size, + addr_str, addr_str_len, "1.1", + scope_id, status_code); } -*/ +#endif return respbuffer; } @@ -421,12 +512,15 @@ miniwget2(const char * url, const char * host, * 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 + * 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) +int +parseURL(const char * url, + char * hostname, unsigned short * port, + char * * path, unsigned int * scope_id) { char * p1, *p2, *p3; if(!url) @@ -442,7 +536,43 @@ int parseURL(const char * url, char * hostname, unsigned short * port, char * * if(*p1 == '[') { /* IP v6 : http://[2a00:1450:8002::6a]/path/abc */ + char * scope; + scope = strchr(p1, '%'); p2 = strchr(p1, ']'); + if(p2 && scope && scope < p2 && scope_id) { + /* parse scope */ +#ifdef IF_NAMESIZE + char tmp[IF_NAMESIZE]; + int l; + scope++; + /* "%25" is just '%' in URL encoding */ + if(scope[0] == '2' && scope[1] == '5') + scope += 2; /* skip "25" */ + l = p2 - scope; + if(l >= IF_NAMESIZE) + l = IF_NAMESIZE - 1; + memcpy(tmp, scope, l); + tmp[l] = '\0'; + *scope_id = if_nametoindex(tmp); + if(*scope_id == 0) { + *scope_id = (unsigned int)strtoul(tmp, NULL, 10); + } +#else + /* under windows, scope is numerical */ + char tmp[8]; + int l; + scope++; + /* "%25" is just '%' in URL encoding */ + if(scope[0] == '2' && scope[1] == '5') + scope += 2; /* skip "25" */ + l = p2 - scope; + if(l >= sizeof(tmp)) + l = sizeof(tmp) - 1; + memcpy(tmp, scope, l); + tmp[l] = '\0'; + *scope_id = (unsigned int)strtoul(tmp, NULL, 10); +#endif + } p3 = strchr(p1, '/'); if(p2 && p3) { @@ -492,35 +622,42 @@ int parseURL(const char * url, char * hostname, unsigned short * port, char * * return 1; } -void * miniwget(const char * url, int * size) +void * +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)) + if(!parseURL(url, hostname, &port, &path, &scope_id)) return NULL; #ifdef DEBUG - printf("parsed url : hostname='%s' port=%hu path='%s'\n", hostname, port, path); + printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", + hostname, port, path, scope_id); #endif - return miniwget2(url, hostname, port, path, size, 0, 0); + return miniwget2(hostname, port, path, size, 0, 0, scope_id, status_code); } -void * miniwget_getaddr(const char * url, int * size, char * addr, int addrlen) +void * +miniwget_getaddr(const char * url, int * size, + char * addr, int addrlen, unsigned int scope_id, + int * status_code) { unsigned short port; char * path; - /* protocol://host:port/chemin */ + /* protocol://host:port/path */ char hostname[MAXHOSTNAMELEN+1]; *size = 0; if(addr) addr[0] = '\0'; - if(!parseURL(url, hostname, &port, &path)) + if(!parseURL(url, hostname, &port, &path, &scope_id)) return NULL; #ifdef DEBUG - printf("parsed url : hostname='%s' port=%hu path='%s'\n", hostname, port, path); + printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", + hostname, port, path, scope_id); #endif - return miniwget2(url, hostname, port, path, size, addr, addrlen); + 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 8314b40..0701494 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h @@ -1,26 +1,26 @@ -/* $Id: miniwget.h,v 1.6 2010/12/09 16:11:33 nanard Exp $ */ +/* $Id: miniwget.h,v 1.12 2016/01/24 17:24:36 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard - * Copyright (c) 2005 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__ -#define __MINIWGET_H__ +#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 *); +MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int, int *); -LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int); +MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int, int *); -int parseURL(const char *, char *, unsigned short *, char * *); +int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *); #ifdef __cplusplus } diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c index 8b5594c..3e201ec 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c @@ -1,10 +1,10 @@ -/* $Id: minixml.c,v 1.9 2011/02/07 13:44:57 nanard Exp $ */ +/* $Id: minixml.c,v 1.11 2014/02/03 15:54:12 nanard Exp $ */ /* minixml.c : the minimum size a xml parser can be ! */ /* Project : miniupnp * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author : Thomas Bernard -Copyright (c) 2005-2011, Thomas BERNARD +Copyright (c) 2005-2014, Thomas BERNARD All rights reserved. Redistribution and use in source and binary forms, with or without @@ -113,7 +113,20 @@ static void parseelt(struct xmlparser * p) const char * elementname; while(p->xml < (p->xmlend - 1)) { - if((p->xml)[0]=='<' && (p->xml)[1]!='?') + if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "<!--", 4))) + { + p->xml += 3; + /* ignore comments */ + do + { + p->xml++; + if ((p->xml + 3) >= p->xmlend) + return; + } + while(memcmp(p->xml, "-->", 3) != 0); + p->xml += 3; + } + else if((p->xml)[0]=='<' && (p->xml)[1]!='?') { i = 0; elementname = ++p->xml; while( !IS_WHITE_SPACE(*p->xml) @@ -149,7 +162,7 @@ static void parseelt(struct xmlparser * p) return; } if(memcmp(p->xml, "<![CDATA[", 9) == 0) - { + { /* CDATA handling */ p->xml += 9; data = p->xml; diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.h index 857c70e..9f43aa4 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.h @@ -1,4 +1,4 @@ -/* $Id: minixml.h,v 1.6 2006/11/30 11:47:21 nanard Exp $ */ +/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */ /* minimal xml parser * * Project : miniupnp @@ -8,8 +8,8 @@ * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ -#ifndef __MINIXML_H__ -#define __MINIXML_H__ +#ifndef MINIXML_H_INCLUDED +#define MINIXML_H_INCLUDED #define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) /* if a callback function pointer is set to NULL, diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c index 766211b..dad1488 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c @@ -1,4 +1,4 @@ -/* $Id: minixmlvalid.c,v 1.4 2011/02/07 13:44:57 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 : @@ -32,7 +32,7 @@ int evtlistcmp(struct eventlist * a, struct eventlist * b) if(a->n != b->n) { printf("event number not matching : %d != %d\n", a->n, b->n); - //return 1; + /*return 1;*/ } for(i=0; i<a->n; i++) { @@ -82,7 +82,7 @@ static const struct event evtref[] = {ELTEND, "elt2b", 5}, {ELTEND, "elt2a", 5}, {ELTEND, "xmlroot", 7} -}; +}; void startelt(void * data, const char * p, int l) { @@ -128,6 +128,11 @@ int testxmlparser(const char * xml, int size) struct xmlparser parser; evtlist.n = 0; evtlist.events = malloc(sizeof(struct event)*100); + if(evtlist.events == NULL) + { + fprintf(stderr, "Memory allocation error.\n"); + return -1; + } memset(&parser, 0, sizeof(parser)); parser.xmlstart = xml; parser.xmlsize = size; @@ -148,6 +153,8 @@ int testxmlparser(const char * xml, int size) 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"); diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c index e09e80f..d1954f5 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c @@ -1,11 +1,14 @@ -/* $Id: portlistingparse.c,v 1.4 2011/03/18 11:02:17 nanard Exp $ */ +/* $Id: portlistingparse.c,v 1.10 2016/12/16 08:53:21 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2011 Thomas Bernard + * (c) 2011-2016 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include <string.h> #include <stdlib.h> +#ifdef DEBUG +#include <stdio.h> +#endif /* DEBUG */ #include "portlistingparse.h" #include "minixml.h" @@ -52,7 +55,7 @@ startelt(void * d, const char * name, int l) pdata->curelt = PortMappingEltNone; for(i = 0; elements[i].str; i++) { - if(memcmp(name, elements[i].str, l) == 0) + if(strlen(elements[i].str) == (size_t)l && memcmp(name, elements[i].str, l) == 0) { pdata->curelt = elements[i].code; break; @@ -62,7 +65,17 @@ startelt(void * d, const char * name, int l) { struct PortMapping * pm; pm = calloc(1, sizeof(struct PortMapping)); - LIST_INSERT_HEAD( &(pdata->head), pm, entries); + if(pm == NULL) + { + /* malloc error */ +#ifdef DEBUG + fprintf(stderr, "%s: error allocating memory", + "startelt"); +#endif /* DEBUG */ + return; + } + pm->l_next = pdata->l_head; /* insert in list */ + pdata->l_head = pm; } } @@ -71,6 +84,8 @@ static void endelt(void * d, const char * name, int l) { struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; + (void)name; + (void)l; pdata->curelt = PortMappingEltNone; } @@ -80,7 +95,7 @@ data(void * d, const char * data, int l) { struct PortMapping * pm; struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; - pm = pdata->head.lh_first; + pm = pdata->l_head; if(!pm) return; if(l > 63) @@ -132,7 +147,6 @@ ParsePortListing(const char * buffer, int bufsize, struct xmlparser parser; memset(pdata, 0, sizeof(struct PortMappingParserData)); - LIST_INIT(&(pdata->head)); /* init xmlparser */ parser.xmlstart = buffer; parser.xmlsize = bufsize; @@ -148,9 +162,10 @@ void FreePortListing(struct PortMappingParserData * pdata) { struct PortMapping * pm; - while((pm = pdata->head.lh_first) != NULL) + while((pm = pdata->l_head) != NULL) { - LIST_REMOVE(pm, entries); + /* remove from list */ + pdata->l_head = pm->l_next; free(pm); } } diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h index 1852478..661ad1f 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h @@ -1,22 +1,16 @@ -/* $Id: portlistingparse.h,v 1.4 2011/02/15 23:03:56 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 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__ -#define __PORTLISTINGPARSE_H__ +#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 @@ -37,11 +31,11 @@ typedef enum { PortMappingEltNone, PortMappingEntry, NewRemoteHost, NewExternalPort, NewProtocol, NewInternalPort, NewInternalClient, - NewEnabled, NewDescription, + 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; @@ -53,15 +47,15 @@ struct PortMapping { }; struct PortMappingParserData { - LIST_HEAD(portmappinglisthead, PortMapping) head; + struct PortMapping * l_head; /* list head */ portMappingElt curelt; }; -LIBSPEC void +MINIUPNP_LIBSPEC void ParsePortListing(const char * buffer, int bufsize, struct PortMappingParserData * pdata); -LIBSPEC void +MINIUPNP_LIBSPEC void FreePortListing(struct PortMappingParserData * pdata); #ifdef __cplusplus diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c index a1eadfc..5dbd227 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c @@ -1,15 +1,17 @@ -/* $Id: receivedata.c,v 1.1 2011/04/11 08:21:47 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 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> -#ifdef WIN32 +#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 @@ -17,15 +19,16 @@ #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()); +#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 @@ -33,21 +36,27 @@ #include "receivedata.h" int -receivedata(int socket, char * data, int length, int timeout) +receivedata(int socket, + char * data, int length, + int timeout, unsigned int * scope_id) { +#ifdef MINIUPNPC_GET_SRC_ADDR + struct sockaddr_storage src_addr; + socklen_t src_addr_len = sizeof(src_addr); +#endif /* MINIUPNPC_GET_SRC_ADDR */ int n; -#if !defined(WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) +#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; @@ -55,8 +64,8 @@ receivedata(int socket, char * data, int length, int timeout) /* timeout */ return 0; } -#else /* !defined(WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ - /* using select under WIN32 and amigaos */ +#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ + /* using select under _WIN32 and amigaos */ fd_set socketSet; TIMEVAL timeval; FD_ZERO(&socketSet); @@ -69,13 +78,28 @@ receivedata(int socket, char * data, int length, int timeout) return -1; } else if(n == 0) { return 0; - } -#endif + } +#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 /* MINIUPNPC_GET_SRC_ADDR */ n = recv(socket, data, length, 0); +#endif /* MINIUPNPC_GET_SRC_ADDR */ if(n<0) { PRINT_SOCKET_ERROR("recv"); } +#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 /* DEBUG */ + if(scope_id) + *scope_id = src_addr6->sin6_scope_id; + } +#endif /* MINIUPNPC_GET_SRC_ADDR */ return n; } - diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.h index 7a551b9..0520a11 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.h @@ -1,17 +1,19 @@ -/* $Id: receivedata.h,v 1.1 2011/04/11 08:21:47 nanard Exp $ */ +/* $Id: receivedata.h,v 1.4 2012/09/27 15:42:10 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author: Thomas Bernard - * Copyright (c) 2011 Thomas Bernard + * Copyright (c) 2011-2012 Thomas Bernard * This software is subjects to the conditions detailed * in the LICENCE file provided within this distribution */ -#ifndef __RECEIVEDATA_H__ -#define __RECEIVEDATA_H__ +#ifndef RECEIVEDATA_H_INCLUDED +#define RECEIVEDATA_H_INCLUDED -/* Reads data from the specified socket. - * Returns the number of bytes read if successful, zero if no bytes were +/* Reads data from the specified socket. + * Returns the number of bytes read if successful, zero if no bytes were * read or if we timed out. Returns negative if there was an error. */ -int receivedata(int socket, char * data, int length, int timeout); +int receivedata(int socket, + char * data, int length, + int timeout, unsigned int * scope_id); #endif diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c index b136d9d..1cf1ca2 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c @@ -1,7 +1,7 @@ -/* $Id: upnpc.c,v 1.88 2011/06/17 23:31:01 nanard Exp $ */ +/* $Id: upnpc.c,v 1.116 2017/04/21 10:20:50 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard - * Copyright (c) 2005-2011 Thomas Bernard + * Copyright (c) 2005-2016 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ @@ -9,16 +9,21 @@ #include <stdlib.h> #include <string.h> #include <time.h> -#ifdef WIN32 +#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" +/* protofix() checks if protocol is "UDP" or "TCP" * returns NULL if not */ const char * protofix(const char * proto) { @@ -26,7 +31,7 @@ const char * protofix(const char * proto) 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]) + b = b && ( (proto[i] == proto_tcp[i]) || (proto[i] == (proto_tcp[i] | 32)) ); if(b) return proto_tcp; @@ -38,6 +43,22 @@ const char * protofix(const char * proto) return 0; } +/* is_int() checks if parameter is an integer or not + * 1 for integer + * 0 for not an integer */ +int is_int(char const* s) +{ + if(s == NULL) + return 0; + while(*s) { + /* #define isdigit(c) ((c) >= '0' && (c) <= '9') */ + if(!isdigit(*s)) + return 0; + s++; + } + return 1; +} + static void DisplayInfos(struct UPNPUrls * urls, struct IGDdatas * data) { @@ -45,48 +66,53 @@ static void DisplayInfos(struct UPNPUrls * urls, char connectionType[64]; char status[64]; char lastconnerr[64]; - unsigned int uptime; + unsigned int uptime = 0; unsigned int brUp, brDown; time_t timenow, timestarted; int r; - UPNP_GetConnectionTypeInfo(urls->controlURL, - data->first.servicetype, - connectionType); - if(connectionType[0]) + 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("GetConnectionTypeInfo failed.\n"); - UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, - status, &uptime, lastconnerr); - printf("Status : %s, uptime=%us, LastConnectionError : %s\n", - status, uptime, lastconnerr); - timenow = time(NULL); - timestarted = timenow - uptime; - printf(" Time started : %s", ctime(×tarted)); - UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype, - &brDown, &brUp); - 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"); + printf("Status : %s, uptime=%us, LastConnectionError : %s\n", + status, uptime, lastconnerr); + 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() returned %d\n", r); - if(externalIPAddress[0]) + if(r != UPNPCOMMAND_SUCCESS) { + printf("GetExternalIPAddress failed. (errorcode=%d)\n", r); + } else { printf("ExternalIPAddress = %s\n", externalIPAddress); - else - printf("GetExternalIPAddress failed.\n"); + } } static void GetConnectionStatus(struct UPNPUrls * urls, @@ -119,6 +145,7 @@ static void ListRedirections(struct UPNPUrls * urls, /*unsigned int num=0; UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num); printf("PortMappingNumberOfEntries : %u\n", num);*/ + printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n"); do { snprintf(index, 6, "%d", i); rHost[0] = '\0'; enabled[0] = '\0'; @@ -166,7 +193,8 @@ static void NewListRedirections(struct UPNPUrls * urls, &pdata); if(r == UPNPCOMMAND_SUCCESS) { - for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next) + printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n"); + 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, @@ -191,7 +219,7 @@ static void NewListRedirections(struct UPNPUrls * urls, &pdata); if(r == UPNPCOMMAND_SUCCESS) { - for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next) + for(pm = pdata.l_head; pm != NULL; pm = pm->l_next) { printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", i, pm->protocol, pm->externalPort, pm->internalClient, @@ -209,87 +237,144 @@ static void NewListRedirections(struct UPNPUrls * urls, } } -/* Test function +/* 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) +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 - printf("GetExternalIPAddress failed.\n"); - - r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, - eport, iport, iaddr, 0, proto, 0, leaseDuration); + + r = UPNP_GetExternalIPAddress(urls->controlURL, + data->first.servicetype, + externalIPAddress); if(r!=UPNPCOMMAND_SUCCESS) - printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", - eport, iport, iaddr, r, strupnperror(r)); + printf("GetExternalIPAddress failed.\n"); + else + printf("ExternalIPAddress = %s\n", externalIPAddress); + + if (addAny) { + r = UPNP_AddAnyPortMapping(urls->controlURL, data->first.servicetype, + eport, iport, iaddr, description, + proto, 0, leaseDuration, reservedPort); + if(r==UPNPCOMMAND_SUCCESS) + eport = reservedPort; + else + printf("AddAnyPortMapping(%s, %s, %s) failed with code %d (%s)\n", + eport, iport, iaddr, r, strupnperror(r)); + } else { + r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, + eport, iport, iaddr, description, + proto, 0, leaseDuration); + if(r!=UPNPCOMMAND_SUCCESS) { + printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", + eport, iport, iaddr, r, strupnperror(r)); + return -2; + } + } r = UPNP_GetSpecificPortMappingEntry(urls->controlURL, - data->first.servicetype, - eport, proto, - 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); + } + 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_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, 0); - printf("UPNP_DeletePortMapping() returned : %d\n", r); + 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 */ @@ -301,7 +386,7 @@ static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data) 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); @@ -310,7 +395,7 @@ static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data) printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); } -/* Test function +/* Test function * 1 - Add pinhole * 2 - Check if pinhole is working from the IGD side */ static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data, @@ -319,27 +404,43 @@ static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data, const char * proto, const char * lease_time) { char uniqueID[8]; - //int isWorking = 0; + /*int isWorking = 0;*/ int r; + char proto_tmp[8]; if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time) { fprintf(stderr, "Wrong arguments\n"); return; } - /*proto = protofix(proto); - if(!proto) + if(atoi(proto) == 0) { - fprintf(stderr, "invalid protocol\n"); - return; - }*/ + const char * protocol; + protocol = protofix(proto); + if(protocol && (strcmp("TCP", protocol) == 0)) + { + snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP); + proto = proto_tmp; + } + else if(protocol && (strcmp("UDP", protocol) == 0)) + { + snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP); + proto = proto_tmp; + } + else + { + fprintf(stderr, "invalid protocol\n"); + return; + } + } r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID); if(r!=UPNPCOMMAND_SUCCESS) printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", - intaddr, iport, remoteaddr, eport, r, strupnperror(r)); + remoteaddr, eport, intaddr, iport, r, strupnperror(r)); else { - printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n", intaddr, iport, remoteaddr, eport, uniqueID); + printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n", + remoteaddr, eport, intaddr, iport, uniqueID); /*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking); if(r!=UPNPCOMMAND_SUCCESS) printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); @@ -374,7 +475,7 @@ static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data, } } -/* Test function +/* Test function * Get pinhole timeout */ static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data, @@ -455,16 +556,19 @@ int main(int argc, char ** argv) char ** commandargv = 0; int commandargc = 0; struct UPNPDev * devlist = 0; - char lanaddr[64]; /* my ip address on the LAN */ + char lanaddr[64] = "unset"; /* my ip address on the LAN */ int i; const char * rootdescurl = 0; const char * multicastif = 0; const char * minissdpdpath = 0; + int localport = UPNP_LOCAL_PORT_ANY; int retcode = 0; int error = 0; int ipv6 = 0; + unsigned char ttl = 2; /* defaulting to 2 */ + const char * description = 0; -#ifdef WIN32 +#ifdef _WIN32 WSADATA wsaData; int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); if(nResult != NO_ERROR) @@ -473,22 +577,44 @@ int main(int argc, char ** argv) return -1; } #endif - printf("upnpc : miniupnpc library test client. (c) 2006-2011 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]; @@ -504,7 +630,8 @@ int main(int argc, char ** argv) } } - if(!command || (command == 'a' && commandargc<4) + if(!command + || (command == 'a' && commandargc<4) || (command == 'd' && argc<2) || (command == 'r' && argc<2) || (command == 'A' && commandargc<6) @@ -512,11 +639,13 @@ int main(int argc, char ** argv) || (command == 'D' && commandargc<1)) { fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration]\n\t\tAdd port redirection\n", argv[0]); - fprintf(stderr, " \t%s [options] -d external_port protocol [port2 protocol2] [...]\n\t\tDelete port redirection\n", argv[0]); + fprintf(stderr, " \t%s [options] -d external_port protocol <remote host>\n\t\tDelete port redirection\n", argv[0]); fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]); fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]); - fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings, IGD v2)\n", argv[0]); - fprintf(stderr, " \t%s [options] -r port1 protocol1 [port2 protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]); + fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]); + fprintf(stderr, " \t%s [options] -n ip port external_port protocol [duration]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]); + fprintf(stderr, " \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port redirections (for IGD:2 only)\n", argv[0]); + fprintf(stderr, " \t%s [options] -r port1 [external_port1] protocol1 [port2 [external_port2] protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]); fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]); @@ -527,16 +656,19 @@ int main(int argc, char ** argv) 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 v6) to use for sending SSDP multicast packets.\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; @@ -550,7 +682,7 @@ int main(int argc, char ** argv) device->descURL, device->st); } } - else + else if(!rootdescurl) { printf("upnpDiscover() error code=%d\n", error); } @@ -595,27 +727,63 @@ int main(int argc, char ** argv) NewListRedirections(&urls, &data); break; case 'a': - SetRedirectAndTest(&urls, &data, - commandargv[0], commandargv[1], - commandargv[2], commandargv[3], - (commandargc > 4)?commandargv[4]:"0"); + 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"); + 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': @@ -678,6 +846,12 @@ int main(int argc, char ** argv) fprintf(stderr, "No IGD UPnP Device found on the network !\n"); retcode = 1; } +#ifdef _WIN32 + nResult = WSACleanup(); + if(nResult != NO_ERROR) { + fprintf(stderr, "WSACleanup() failed.\n"); + } +#endif /* _WIN32 */ return retcode; } diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c index 1114759..d786e53 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c @@ -1,7 +1,8 @@ -/* $Id: upnpcommands.c,v 1.37 2011/06/04 15:56:23 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-2011 Thomas Bernard + * Copyright (c) 2005-2017 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ @@ -20,7 +21,7 @@ my_atoui(const char * s) /* * */ -LIBSPEC UNSIGNED_INTEGER +MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesSent(const char * controlURL, const char * servicetype) { @@ -44,7 +45,7 @@ UPNP_GetTotalBytesSent(const char * controlURL, /* * */ -LIBSPEC UNSIGNED_INTEGER +MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesReceived(const char * controlURL, const char * servicetype) { @@ -68,7 +69,7 @@ UPNP_GetTotalBytesReceived(const char * controlURL, /* * */ -LIBSPEC UNSIGNED_INTEGER +MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsSent(const char * controlURL, const char * servicetype) { @@ -92,7 +93,7 @@ UPNP_GetTotalPacketsSent(const char * controlURL, /* * */ -LIBSPEC UNSIGNED_INTEGER +MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsReceived(const char * controlURL, const char * servicetype) { @@ -116,10 +117,10 @@ UPNP_GetTotalPacketsReceived(const char * controlURL, /* UPNP_GetStatusInfo() call the corresponding UPNP method * returns the current status and uptime */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetStatusInfo(const char * controlURL, const char * servicetype, - char * status, + char * status, unsigned int * uptime, char * lastconnerror) { @@ -159,7 +160,7 @@ UPNP_GetStatusInfo(const char * controlURL, if(up) sscanf(up,"%u",uptime); else - uptime = 0; + *uptime = 0; } if(lastconnerror) { @@ -181,7 +182,7 @@ UPNP_GetStatusInfo(const char * controlURL, /* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method * returns the connection type */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetConnectionTypeInfo(const char * controlURL, const char * servicetype, char * connectionType) @@ -221,10 +222,10 @@ UPNP_GetConnectionTypeInfo(const char * controlURL, /* 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 + * 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, @@ -285,7 +286,7 @@ UPNP_GetLinkLayerMaxBitRates(const char * controlURL, /* 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. @@ -293,7 +294,7 @@ UPNP_GetLinkLayerMaxBitRates(const char * controlURL, * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetExternalIPAddress(const char * controlURL, const char * servicetype, char * extIpAdd) @@ -333,15 +334,15 @@ UPNP_GetExternalIPAddress(const char * controlURL, return ret; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_AddPortMapping(const char * controlURL, const char * servicetype, - const char * extPort, - const char * inPort, - const char * inClient, - const char * desc, - const char * proto, - const char * remoteHost, - const char * leaseDuration) + const char * extPort, + const char * inPort, + const char * inClient, + const char * desc, + const char * proto, + const char * remoteHost, + const char * leaseDuration) { struct UPNParg * AddPortMappingArgs; char * buffer; @@ -354,6 +355,8 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype, return UPNPCOMMAND_INVALID_ARGS; AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); + if(AddPortMappingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; AddPortMappingArgs[0].elt = "NewRemoteHost"; AddPortMappingArgs[0].val = remoteHost; AddPortMappingArgs[1].elt = "NewExternalPort"; @@ -370,10 +373,11 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype, AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; AddPortMappingArgs[7].elt = "NewLeaseDuration"; AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "AddPortMapping", AddPortMappingArgs, - &bufsize))) { - free(AddPortMappingArgs); + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "AddPortMapping", AddPortMappingArgs, + &bufsize); + free(AddPortMappingArgs); + if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ @@ -390,11 +394,79 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype, ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, + const char * extPort, + const char * inPort, + const char * inClient, + const char * desc, + const char * proto, + const char * remoteHost, + const char * leaseDuration, + char * reservedPort) +{ + struct UPNParg * AddPortMappingArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!inPort || !inClient || !proto || !extPort) + return UPNPCOMMAND_INVALID_ARGS; + + AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); + if(AddPortMappingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + AddPortMappingArgs[0].elt = "NewRemoteHost"; + AddPortMappingArgs[0].val = remoteHost; + AddPortMappingArgs[1].elt = "NewExternalPort"; + AddPortMappingArgs[1].val = extPort; + AddPortMappingArgs[2].elt = "NewProtocol"; + AddPortMappingArgs[2].val = proto; + AddPortMappingArgs[3].elt = "NewInternalPort"; + AddPortMappingArgs[3].val = inPort; + AddPortMappingArgs[4].elt = "NewInternalClient"; + AddPortMappingArgs[4].val = inClient; + AddPortMappingArgs[5].elt = "NewEnabled"; + AddPortMappingArgs[5].val = "1"; + AddPortMappingArgs[6].elt = "NewPortMappingDescription"; + AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; + AddPortMappingArgs[7].elt = "NewLeaseDuration"; + AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "AddAnyPortMapping", AddPortMappingArgs, + &bufsize); free(AddPortMappingArgs); + if(!buffer) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } else { + char *p; + + p = GetValueFromNameValueList(&pdata, "NewReservedPort"); + if(p) { + strncpy(reservedPort, p, 6); + reservedPort[5] = '\0'; + ret = UPNPCOMMAND_SUCCESS; + } else { + ret = UPNPCOMMAND_INVALID_RESPONSE; + } + } + ClearNameValueList(&pdata); return ret; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, const char * remoteHost) @@ -411,16 +483,19 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, return UPNPCOMMAND_INVALID_ARGS; DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg)); + if(DeletePortMappingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; DeletePortMappingArgs[0].elt = "NewRemoteHost"; DeletePortMappingArgs[0].val = remoteHost; DeletePortMappingArgs[1].elt = "NewExternalPort"; DeletePortMappingArgs[1].val = extPort; DeletePortMappingArgs[2].elt = "NewProtocol"; DeletePortMappingArgs[2].val = proto; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "DeletePortMapping", - DeletePortMappingArgs, &bufsize))) { - free(DeletePortMappingArgs); + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "DeletePortMapping", + DeletePortMappingArgs, &bufsize); + free(DeletePortMappingArgs); + if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } /*DisplayNameValueList(buffer, bufsize);*/ @@ -434,11 +509,58 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, + const char * extPortStart, const char * extPortEnd, + const char * proto, + const char * manage) +{ + struct UPNParg * DeletePortMappingArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!extPortStart || !extPortEnd || !proto || !manage) + return UPNPCOMMAND_INVALID_ARGS; + + DeletePortMappingArgs = calloc(5, sizeof(struct UPNParg)); + if(DeletePortMappingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + DeletePortMappingArgs[0].elt = "NewStartPort"; + DeletePortMappingArgs[0].val = extPortStart; + DeletePortMappingArgs[1].elt = "NewEndPort"; + DeletePortMappingArgs[1].val = extPortEnd; + DeletePortMappingArgs[2].elt = "NewProtocol"; + DeletePortMappingArgs[2].val = proto; + DeletePortMappingArgs[3].elt = "NewManage"; + DeletePortMappingArgs[3].val = manage; + + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "DeletePortMappingRange", + DeletePortMappingArgs, &bufsize); free(DeletePortMappingArgs); + if(!buffer) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } else { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); return ret; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetGenericPortMappingEntry(const char * controlURL, const char * servicetype, const char * index, @@ -462,12 +584,15 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL, intClient[0] = '\0'; intPort[0] = '\0'; GetPortMappingArgs = calloc(2, sizeof(struct UPNParg)); + if(GetPortMappingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; GetPortMappingArgs[0].elt = "NewPortMappingIndex"; GetPortMappingArgs[0].val = index; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetGenericPortMappingEntry", - GetPortMappingArgs, &bufsize))) { - free(GetPortMappingArgs); + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetGenericPortMappingEntry", + GetPortMappingArgs, &bufsize); + free(GetPortMappingArgs); + if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); @@ -493,14 +618,14 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL, protocol[3] = '\0'; } p = GetValueFromNameValueList(&pdata, "NewInternalClient"); - if(p && intClient) + if(p) { strncpy(intClient, p, 16); intClient[15] = '\0'; r = 0; } p = GetValueFromNameValueList(&pdata, "NewInternalPort"); - if(p && intPort) + if(p) { strncpy(intPort, p, 6); intPort[5] = '\0'; @@ -529,11 +654,10 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL, sscanf(p, "%d", &r); } ClearNameValueList(&pdata); - free(GetPortMappingArgs); return r; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetPortMappingNumberOfEntries(const char * controlURL, const char * servicetype, unsigned int * numEntries) @@ -574,11 +698,12 @@ UPNP_GetPortMappingNumberOfEntries(const char * controlURL, /* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping * the result is returned in the intClient and intPort strings * please provide 16 and 6 bytes of data */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetSpecificPortMappingEntry(const char * controlURL, const char * servicetype, const char * extPort, - const char * proto, + const char * proto, + const char * remoteHost, char * intClient, char * intPort, char * desc, @@ -596,16 +721,19 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL, return UPNPCOMMAND_INVALID_ARGS; GetPortMappingArgs = calloc(4, sizeof(struct UPNParg)); + if(GetPortMappingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; GetPortMappingArgs[0].elt = "NewRemoteHost"; - /* TODO : add remote host ? */ + 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);*/ @@ -653,7 +781,6 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL, } ClearNameValueList(&pdata); - free(GetPortMappingArgs); return ret; } @@ -665,7 +792,7 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL, * 733 InconsistantParameters - NewStartPort and NewEndPort values are not * consistent. */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetListOfPortMappings(const char * controlURL, const char * servicetype, const char * startPort, @@ -685,6 +812,8 @@ UPNP_GetListOfPortMappings(const char * controlURL, return UPNPCOMMAND_INVALID_ARGS; GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg)); + if(GetListOfPortMappingsArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; GetListOfPortMappingsArgs[0].elt = "NewStartPort"; GetListOfPortMappingsArgs[0].val = startPort; GetListOfPortMappingsArgs[1].elt = "NewEndPort"; @@ -696,13 +825,13 @@ UPNP_GetListOfPortMappings(const char * controlURL, GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts"; GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000"; - if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, - "GetListOfPortMappings", - GetListOfPortMappingsArgs, &bufsize))) { - free(GetListOfPortMappingsArgs); + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetListOfPortMappings", + GetListOfPortMappingsArgs, &bufsize); + free(GetListOfPortMappingsArgs); + if(!buffer) { return UPNPCOMMAND_HTTP_ERROR; } - free(GetListOfPortMappingsArgs); /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); @@ -741,16 +870,16 @@ UPNP_GetListOfPortMappings(const char * controlURL, } ClearNameValueList(&pdata); - //printf("%.*s", bufsize, buffer); + /*printf("%.*s", bufsize, buffer);*/ return ret; } -/* IGD:2, functions for service WANIPv6FirewallControl:1 */ -LIBSPEC int +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +MINIUPNP_LIBSPEC int UPNP_GetFirewallStatus(const char * controlURL, const char * servicetype, - int * firewallEnabled, + int * firewallEnabled, int * inboundPinholeAllowed) { struct NameValueParserData pdata; @@ -759,7 +888,7 @@ UPNP_GetFirewallStatus(const char * controlURL, char * fe, *ipa, *p; int ret = UPNPCOMMAND_UNKNOWN_ERROR; - if(!firewallEnabled && !inboundPinholeAllowed) + if(!firewallEnabled || !inboundPinholeAllowed) return UPNPCOMMAND_INVALID_ARGS; buffer = simpleUPnPcommand(-1, controlURL, servicetype, @@ -791,7 +920,7 @@ UPNP_GetFirewallStatus(const char * controlURL, return ret; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, @@ -812,6 +941,8 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype return UPNPCOMMAND_INVALID_ARGS; GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg)); + if(GetOutboundPinholeTimeoutArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost"; GetOutboundPinholeTimeoutArgs[0].val = remoteHost; GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort"; @@ -824,6 +955,7 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype GetOutboundPinholeTimeoutArgs[4].val = intClient; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize); + free(GetOutboundPinholeTimeoutArgs); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); @@ -842,11 +974,10 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype *opTimeout = my_atoui(p); } ClearNameValueList(&pdata); - free(GetOutboundPinholeTimeoutArgs); return ret; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_AddPinhole(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, @@ -868,7 +999,9 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype, return UPNPCOMMAND_INVALID_ARGS; AddPinholeArgs = calloc(7, sizeof(struct UPNParg)); - // RemoteHost can be wilcarded + if(AddPinholeArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + /* RemoteHost can be wilcarded */ if(strncmp(remoteHost, "empty", 5)==0) { AddPinholeArgs[0].elt = "RemoteHost"; @@ -899,6 +1032,7 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype, AddPinholeArgs[5].val = leaseTime; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "AddPinhole", AddPinholeArgs, &bufsize); + free(AddPinholeArgs); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); @@ -912,7 +1046,7 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype, resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { - //printf("AddPortMapping errorCode = '%s'\n", resVal); + /*printf("AddPortMapping errorCode = '%s'\n", resVal);*/ ret = UPNPCOMMAND_UNKNOWN_ERROR; sscanf(resVal, "%d", &ret); } @@ -921,11 +1055,10 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype, ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); - free(AddPinholeArgs); return ret; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, const char * uniqueID, const char * leaseTime) @@ -941,12 +1074,15 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, return UPNPCOMMAND_INVALID_ARGS; UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg)); + if(UpdatePinholeArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; UpdatePinholeArgs[0].elt = "UniqueID"; UpdatePinholeArgs[0].val = uniqueID; UpdatePinholeArgs[1].elt = "NewLeaseTime"; UpdatePinholeArgs[1].val = leaseTime; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "UpdatePinhole", UpdatePinholeArgs, &bufsize); + free(UpdatePinholeArgs); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); @@ -963,11 +1099,10 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); - free(UpdatePinholeArgs); return ret; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID) { /*struct NameValueParserData pdata;*/ @@ -982,10 +1117,13 @@ UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char return UPNPCOMMAND_INVALID_ARGS; DeletePinholeArgs = calloc(2, sizeof(struct UPNParg)); + if(DeletePinholeArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; DeletePinholeArgs[0].elt = "UniqueID"; DeletePinholeArgs[0].val = uniqueID; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "DeletePinhole", DeletePinholeArgs, &bufsize); + free(DeletePinholeArgs); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; /*DisplayNameValueList(buffer, bufsize);*/ @@ -1002,11 +1140,10 @@ UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); - free(DeletePinholeArgs); return ret; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, const char * uniqueID, int * isWorking) { @@ -1021,12 +1158,17 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, return UPNPCOMMAND_INVALID_ARGS; CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg)); + if(CheckPinholeWorkingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; CheckPinholeWorkingArgs[0].elt = "UniqueID"; CheckPinholeWorkingArgs[0].val = uniqueID; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize); + free(CheckPinholeWorkingArgs); if(!buffer) + { return UPNPCOMMAND_HTTP_ERROR; + } ParseNameValue(buffer, bufsize, &pdata); free(buffer); buffer = NULL; @@ -1047,11 +1189,10 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, } ClearNameValueList(&pdata); - free(CheckPinholeWorkingArgs); return ret; } -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, const char * uniqueID, int * packets) { @@ -1066,10 +1207,13 @@ UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, return UPNPCOMMAND_INVALID_ARGS; GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg)); + if(GetPinholePacketsArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; GetPinholePacketsArgs[0].elt = "UniqueID"; GetPinholePacketsArgs[0].val = uniqueID; buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetPinholePackets", GetPinholePacketsArgs, &bufsize); + free(GetPinholePacketsArgs); if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); @@ -1090,7 +1234,6 @@ UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, } ClearNameValueList(&pdata); - free(GetPinholePacketsArgs); return ret; } diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h index 66d95e0..22eda5e 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h @@ -1,15 +1,15 @@ -/* $Id: upnpcommands.h,v 1.23 2011/04/11 09:14:00 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__ -#define __UPNPCOMMANDS_H__ +#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 : */ @@ -17,24 +17,26 @@ #define UPNPCOMMAND_UNKNOWN_ERROR (-1) #define UPNPCOMMAND_INVALID_ARGS (-2) #define UPNPCOMMAND_HTTP_ERROR (-3) +#define UPNPCOMMAND_INVALID_RESPONSE (-4) +#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5) #ifdef __cplusplus extern "C" { #endif -LIBSPEC UNSIGNED_INTEGER +MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesSent(const char * controlURL, const char * servicetype); -LIBSPEC UNSIGNED_INTEGER +MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalBytesReceived(const char * controlURL, const char * servicetype); -LIBSPEC UNSIGNED_INTEGER +MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsSent(const char * controlURL, const char * servicetype); -LIBSPEC UNSIGNED_INTEGER +MINIUPNP_LIBSPEC UNSIGNED_INTEGER UPNP_GetTotalPacketsReceived(const char * controlURL, const char * servicetype); @@ -43,7 +45,7 @@ UPNP_GetTotalPacketsReceived(const char * controlURL, * Return values : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error code */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetStatusInfo(const char * controlURL, const char * servicetype, char * status, @@ -55,23 +57,23 @@ UPNP_GetStatusInfo(const char * controlURL, * Return Values : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error code */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetConnectionTypeInfo(const char * controlURL, const char * servicetype, char * connectionType); /* 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 + * 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); @@ -82,7 +84,7 @@ UPNP_GetExternalIPAddress(const char * controlURL, * return values : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR * or a UPnP Error Code. */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetLinkLayerMaxBitRates(const char* controlURL, const char* servicetype, unsigned int * bitrateDown, @@ -95,33 +97,75 @@ UPNP_GetLinkLayerMaxBitRates(const char* controlURL, * 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 + * 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(). @@ -132,15 +176,36 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype, * * List of possible UPnP errors for DeletePortMapping : * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. * 714 NoSuchEntryInArray - The specified value does not exist in the array */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, - const char * extPort, const char * proto, - const char * remoteHost); + const char * extPort, const char * proto, + const char * remoteHost); + +/* UPNP_DeletePortRangeMapping() + * Use same argument values as what was used for AddPortMapping(). + * remoteHost is usually NULL because IGD don't support it. + * Return Values : + * 0 : SUCCESS + * NON ZERO : error. Either an UPnP error code or an undefined error. + * + * List of possible UPnP errors for DeletePortMapping : + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 730 PortMappingNotFound - This error message is returned if no port + * mapping is found in the specified range. + * 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */ +MINIUPNP_LIBSPEC int +UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, + const char * extPortStart, const char * extPortEnd, + const char * proto, + const char * manage); /* UPNP_GetPortMappingNumberOfEntries() * not supported by all routers */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetPortMappingNumberOfEntries(const char* controlURL, const char* servicetype, unsigned int * num); @@ -150,6 +215,7 @@ UPNP_GetPortMappingNumberOfEntries(const char* controlURL, * params : * in extPort * in proto + * in remoteHost * out intClient (16 bytes) * out intPort (6 bytes) * out desc (80 bytes) @@ -158,12 +224,21 @@ UPNP_GetPortMappingNumberOfEntries(const char* controlURL, * * return value : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. */ -LIBSPEC int + * or a UPnP Error Code. + * + * List of possible UPnP errors for _GetSpecificPortMappingEntry : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 714 NoSuchEntryInArray - The specified value does not exist in the array. + */ +MINIUPNP_LIBSPEC int UPNP_GetSpecificPortMappingEntry(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, + const char * remoteHost, char * intClient, char * intPort, char * desc, @@ -188,9 +263,11 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL, * * Possible UPNP Error codes : * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetGenericPortMappingEntry(const char * controlURL, const char * servicetype, const char * index, @@ -212,7 +289,7 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL, * 733 InconsistantParameters - NewStartPort and NewEndPort values are not * consistent. */ -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetListOfPortMappings(const char * controlURL, const char * servicetype, const char * startPort, @@ -221,14 +298,14 @@ UPNP_GetListOfPortMappings(const char * controlURL, const char * numberOfPorts, struct PortMappingParserData * data); -/* IGD:2, functions for service WANIPv6FirewallControl:1 */ -LIBSPEC int +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +MINIUPNP_LIBSPEC int UPNP_GetFirewallStatus(const char * controlURL, const char * servicetype, - int * firewallEnabled, + int * firewallEnabled, int * inboundPinholeAllowed); -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, @@ -237,7 +314,7 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype const char * proto, int * opTimeout); -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_AddPinhole(const char * controlURL, const char * servicetype, const char * remoteHost, const char * remotePort, @@ -247,19 +324,19 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype, const char * leaseTime, char * uniqueID); -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, const char * uniqueID, const char * leaseTime); -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, const char * uniqueID, int * isWorking); -LIBSPEC int +MINIUPNP_LIBSPEC int UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, const char * uniqueID, int * packets); diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpdev.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpdev.c new file mode 100644 index 0000000..d89a993 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpdev.c @@ -0,0 +1,23 @@ +/* $Id: upnpdev.c,v 1.1 2015/08/28 12:14:19 nanard Exp $ */ +/* Project : miniupnp + * Web : http://miniupnp.free.fr/ + * Author : Thomas BERNARD + * copyright (c) 2005-2015 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENSE file. */ +#include <stdlib.h> +#include "upnpdev.h" + +/* freeUPNPDevlist() should be used to + * free the chained list returned by upnpDiscover() */ +void freeUPNPDevlist(struct UPNPDev * devlist) +{ + struct UPNPDev * next; + while(devlist) + { + next = devlist->pNext; + free(devlist); + devlist = next; + } +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpdev.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpdev.h new file mode 100644 index 0000000..f49fbe1 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpdev.h @@ -0,0 +1,36 @@ +/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */ +/* Project : miniupnp + * Web : http://miniupnp.free.fr/ + * Author : Thomas BERNARD + * copyright (c) 2005-2015 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENSE file. */ +#ifndef UPNPDEV_H_INCLUDED +#define UPNPDEV_H_INCLUDED + +#include "miniupnpc_declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct UPNPDev { + struct UPNPDev * pNext; + char * descURL; + char * st; + unsigned int scope_id; + char * usn; + char buffer[3]; +}; + +/* freeUPNPDevlist() + * free list returned by upnpDiscover() */ +MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); + + +#ifdef __cplusplus +} +#endif + + +#endif /* UPNPDEV_H_INCLUDED */ diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c index a48ae10..7ab8ee9 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c @@ -1,4 +1,4 @@ -/* $Id: upnperrors.c,v 1.5 2011/04/10 11:19:36 nanard Exp $ */ +/* $Id: upnperrors.c,v 1.8 2014/06/10 09:41:48 nanard Exp $ */ /* Project : miniupnp * Author : Thomas BERNARD * copyright (c) 2007 Thomas Bernard @@ -24,6 +24,9 @@ const char * strupnperror(int err) case UPNPCOMMAND_INVALID_ARGS: s = "Miniupnpc Invalid Arguments"; break; + case UPNPCOMMAND_INVALID_RESPONSE: + s = "Miniupnpc Invalid response"; + break; case UPNPDISCOVER_SOCKET_ERROR: s = "Miniupnpc Socket error"; break; @@ -97,7 +100,8 @@ const char * strupnperror(int err) s = "ExternalPortOnlySupportsWildcard"; break; default: - s = NULL; + s = "UnknownError"; + break; } return s; } diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h index 2c544c9..3115aee 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h @@ -1,23 +1,23 @@ -/* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 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__ -#define __UPNPERRORS_H__ +#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 + * Return a string description of the UPnP error code * or NULL for undefinded errors */ -LIBSPEC const char * strupnperror(int err); +MINIUPNP_LIBSPEC const char * strupnperror(int err); #ifdef __cplusplus } diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c index 482030b..5de5796 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c @@ -1,7 +1,7 @@ -/* $Id: upnpreplyparse.c,v 1.11 2011/02/07 16:17:06 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-2011 Thomas Bernard + * (c) 2006-2015 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -15,18 +15,65 @@ static void NameValueParserStartElt(void * d, const char * name, int l) { - struct NameValueParserData * data = (struct NameValueParserData *)d; + 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 -NameValueParserGetData(void * d, const char * datas, int l) +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'; + } + 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 */ @@ -34,6 +81,10 @@ NameValueParserGetData(void * d, const char * datas, int l) if(!data->portListing) { /* malloc error */ +#ifdef DEBUG + fprintf(stderr, "%s: error allocating memory", + "NameValueParserGetData"); +#endif /* DEBUG */ return; } memcpy(data->portListing, datas, l); @@ -42,15 +93,9 @@ NameValueParserGetData(void * d, const char * datas, int l) } else { - /* standard case. Limited to 63 chars strings */ - nv = malloc(sizeof(struct NameValue)); - if(l>63) - l = 63; - strncpy(nv->name, data->curelt, 64); - nv->name[63] = '\0'; - memcpy(nv->value, datas, l); - nv->value[l] = '\0'; - LIST_INSERT_HEAD( &(data->head), nv, entries); + /* standard case. */ + data->cdata = datas; + data->cdatalen = l; } } @@ -58,19 +103,19 @@ void ParseNameValue(const char * buffer, int bufsize, struct NameValueParserData * data) { - struct xmlparser parser; - LIST_INIT(&(data->head)); + struct xmlparser parser; + data->l_head = NULL; data->portListing = NULL; data->portListingLength = 0; - /* init xmlparser object */ - parser.xmlstart = buffer; - parser.xmlsize = bufsize; - parser.data = data; - parser.starteltfunc = NameValueParserStartElt; - parser.endeltfunc = 0; - 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 @@ -83,22 +128,22 @@ ClearNameValueList(struct NameValueParserData * pdata) pdata->portListing = NULL; pdata->portListingLength = 0; } - while((nv = pdata->head.lh_first) != NULL) + while((nv = pdata->l_head) != NULL) { - LIST_REMOVE(nv, entries); + pdata->l_head = nv->l_next; free(nv); } } -char * +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; @@ -131,7 +176,7 @@ GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, } #endif -/* debug all-in-one function +/* debug all-in-one function * do parsing then display to stdout */ #ifdef DEBUG void @@ -140,13 +185,13 @@ DisplayNameValueList(char * buffer, int bufsize) struct NameValueParserData pdata; struct NameValue * nv; ParseNameValue(buffer, bufsize, &pdata); - for(nv = pdata.head.lh_first; + for(nv = pdata.l_head; nv != NULL; - nv = nv->entries.le_next) + nv = nv->l_next) { printf("%s = %s\n", nv->name, nv->value); } ClearNameValueList(&pdata); } -#endif +#endif /* DEBUG */ diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h index 267ea87..6badd15 100644 --- a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h @@ -1,34 +1,31 @@ -/* $Id: upnpreplyparse.h,v 1.11 2011/02/07 16:17:06 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-2011 Thomas Bernard + * (c) 2006-2013 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ -#ifndef __UPNPREPLYPARSE_H__ -#define __UPNPREPLYPARSE_H__ - -#if defined(NO_SYS_QUEUE_H) || defined(WIN32) || defined(__HAIKU__) -#include "bsdqueue.h" -#else -#include <sys/queue.h> -#endif +#ifndef UPNPREPLYPARSE_H_INCLUDED +#define UPNPREPLYPARSE_H_INCLUDED #ifdef __cplusplus extern "C" { #endif struct NameValue { - LIST_ENTRY(NameValue) entries; - char name[64]; - char value[64]; + 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() */ @@ -45,10 +42,12 @@ char * GetValueFromNameValueList(struct NameValueParserData * pdata, const char * Name); +#if 0 /* GetValueFromNameValueListIgnoreNS() */ char * GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, const char * Name); +#endif /* DisplayNameValueList() */ #ifdef DEBUG |