Created
October 9, 2015 11:39
-
-
Save laanwj/6caebd77a1c253a486e4 to your computer and use it in GitHub Desktop.
Difference between miniupnp 1.9.20150730 and 1.9.20151008
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -duN miniupnpc-1.9.20150730/apiversions.txt miniupnpc-1.9.20151008/apiversions.txt | |
--- miniupnpc-1.9.20150730/apiversions.txt 2015-07-30 00:05:55.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/apiversions.txt 2015-10-08 18:16:03.000000000 +0200 | |
@@ -1,7 +1,15 @@ | |
-$Id: apiversions.txt,v 1.7 2015/07/23 20:40:08 nanard Exp $ | |
+$Id: apiversions.txt,v 1.8 2015/10/08 16:15:47 nanard Exp $ | |
Differences in API between miniUPnPc versions | |
+API version 15 | |
+ changed "sameport" argument of upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice() | |
+ to "localport". When 0 or 1, behaviour is not changed, but it can take | |
+ any other value between 2 and 65535 | |
+ Existing programs should be compatible | |
+ updated macro : | |
+ #define MINIUPNPC_API_VERSION 15 | |
+ | |
API version 14 | |
miniupnpc.h | |
add ttl argument to upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice() | |
@@ -9,6 +17,8 @@ | |
getDevicesFromMiniSSDPD() : | |
connectToMiniSSDPD() / disconnectFromMiniSSDPD() | |
requestDevicesFromMiniSSDPD() / receiveDevicesFromMiniSSDPD() | |
+ updated macro : | |
+ #define MINIUPNPC_API_VERSION 14 | |
API version 13 | |
miniupnpc.h: | |
diff -duN miniupnpc-1.9.20150730/Changelog.txt miniupnpc-1.9.20151008/Changelog.txt | |
--- miniupnpc-1.9.20150730/Changelog.txt 2015-07-30 00:05:55.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/Changelog.txt 2015-10-08 18:16:03.000000000 +0200 | |
@@ -1,6 +1,24 @@ | |
-$Id: Changelog.txt,v 1.212 2015/07/23 20:41:50 nanard Exp $ | |
+$Id: Changelog.txt,v 1.216 2015/10/08 16:15:45 nanard Exp $ | |
miniUPnP client Changelog. | |
+2015/10/08: | |
+ Change sameport to localport | |
+ see https://github.com/miniupnp/miniupnp/pull/120 | |
+ increments API_VERSION to 15 | |
+ | |
+2015/09/15: | |
+ Fix buffer overflow in igd_desc_parse.c/IGDstartelt() | |
+ Discovered by Aleksandar Nikolic of Cisco Talos | |
+ | |
+2015/08/28: | |
+ move ssdpDiscoverDevices() to minissdpc.c | |
+ | |
+2015/08/27: | |
+ avoid unix socket leak in getDevicesFromMiniSSDPD() | |
+ | |
+2015/08/16: | |
+ Also accept "Up" as ConnectionStatus value | |
+ | |
2015/07/23: | |
split getDevicesFromMiniSSDPD | |
add ttl argument to upnpDiscover() functions | |
diff -duN miniupnpc-1.9.20150730/CMakeLists.txt miniupnpc-1.9.20151008/CMakeLists.txt | |
--- miniupnpc-1.9.20150730/CMakeLists.txt 2015-07-30 00:05:55.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/CMakeLists.txt 2015-10-08 18:16:03.000000000 +0200 | |
@@ -2,7 +2,7 @@ | |
project (miniupnpc C) | |
set (MINIUPNPC_VERSION 1.9) | |
-set (MINIUPNPC_API_VERSION 14) | |
+set (MINIUPNPC_API_VERSION 15) | |
if (NOT CMAKE_BUILD_TYPE) | |
if (WIN32) | |
@@ -70,9 +70,11 @@ | |
miniupnpc.c | |
minixml.c | |
minisoap.c | |
+ minissdpc.c | |
miniwget.c | |
upnpc.c | |
upnpcommands.c | |
+ upnpdev.c | |
upnpreplyparse.c | |
upnperrors.c | |
connecthostport.c | |
@@ -164,9 +166,10 @@ | |
igd_desc_parse.h | |
upnpreplyparse.h | |
upnperrors.h | |
+ upnpdev.h | |
miniupnpctypes.h | |
portlistingparse.h | |
- declspec.h | |
+ miniupnpc_declspec.h | |
DESTINATION include/miniupnpc | |
) | |
diff -duN miniupnpc-1.9.20150730/connecthostport.c miniupnpc-1.9.20151008/connecthostport.c | |
--- miniupnpc-1.9.20150730/connecthostport.c 2014-03-31 14:41:45.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/connecthostport.c 2015-10-02 19:02:48.000000000 +0200 | |
@@ -1,7 +1,7 @@ | |
-/* $Id: connecthostport.c,v 1.13 2014/03/31 12:36:36 nanard Exp $ */ | |
+/* $Id: connecthostport.c,v 1.14 2015/10/02 11:08:34 nanard Exp $ */ | |
/* Project : miniupnp | |
* Author : Thomas Bernard | |
- * Copyright (c) 2010-2014 Thomas Bernard | |
+ * Copyright (c) 2010-2015 Thomas Bernard | |
* This software is subject to the conditions detailed in the | |
* LICENCE file provided in this distribution. */ | |
@@ -23,6 +23,10 @@ | |
#define socklen_t int | |
#else /* #ifdef _WIN32 */ | |
#include <unistd.h> | |
+#include <sys/types.h> | |
+#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT | |
+#include <sys/time.h> | |
+#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ | |
#include <sys/param.h> | |
#include <sys/select.h> | |
#include <errno.h> | |
@@ -33,7 +37,6 @@ | |
* during the connect() call */ | |
#define MINIUPNPC_IGNORE_EINTR | |
#ifndef USE_GETHOSTBYNAME | |
-#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <sys/select.h> | |
#endif /* #ifndef USE_GETHOSTBYNAME */ | |
diff -duN miniupnpc-1.9.20150730/igd_desc_parse.c miniupnpc-1.9.20151008/igd_desc_parse.c | |
--- miniupnpc-1.9.20150730/igd_desc_parse.c 2014-11-26 11:42:59.000000000 +0100 | |
+++ miniupnpc-1.9.20151008/igd_desc_parse.c 2015-09-17 15:05:25.000000000 +0200 | |
@@ -1,8 +1,8 @@ | |
-/* $Id: igd_desc_parse.c,v 1.16 2014/11/17 17:19:13 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-2014 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) ) { | |
Common subdirectories: miniupnpc-1.9.20150730/java and miniupnpc-1.9.20151008/java | |
diff -duN miniupnpc-1.9.20150730/listdevices.c miniupnpc-1.9.20151008/listdevices.c | |
--- miniupnpc-1.9.20150730/listdevices.c 2015-07-30 00:05:55.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/listdevices.c 2015-10-08 18:16:03.000000000 +0200 | |
@@ -1,4 +1,4 @@ | |
-/* $Id: listdevices.c,v 1.6 2015/07/23 20:40:08 nanard Exp $ */ | |
+/* $Id: listdevices.c,v 1.7 2015/10/08 16:15:47 nanard Exp $ */ | |
/* Project : miniupnp | |
* Author : Thomas Bernard | |
* Copyright (c) 2013-2015 Thomas Bernard | |
@@ -81,18 +81,18 @@ | |
printf("searching UPnP device type %s\n", searched_device); | |
devlist = upnpDiscoverDevice(searched_device, | |
2000, multicastif, minissdpdpath, | |
- 0/*sameport*/, ipv6, ttl, &error); | |
+ 0/*localport*/, ipv6, ttl, &error); | |
} else if(searched_devices) { | |
printf("searching UPnP device types :\n"); | |
for(i = 0; searched_devices[i]; i++) | |
printf("\t%s\n", searched_devices[i]); | |
devlist = upnpDiscoverDevices(searched_devices, | |
2000, multicastif, minissdpdpath, | |
- 0/*sameport*/, ipv6, ttl, &error, 1); | |
+ 0/*localport*/, ipv6, ttl, &error, 1); | |
} else { | |
printf("searching all UPnP devices\n"); | |
devlist = upnpDiscoverAll(2000, multicastif, minissdpdpath, | |
- 0/*sameport*/, ipv6, ttl, &error); | |
+ 0/*localport*/, ipv6, ttl, &error); | |
} | |
if(devlist) { | |
for(dev = devlist, i = 1; dev != NULL; dev = dev->pNext, i++) { | |
diff -duN miniupnpc-1.9.20150730/Makefile miniupnpc-1.9.20151008/Makefile | |
--- miniupnpc-1.9.20150730/Makefile 2015-07-30 00:05:55.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/Makefile 2015-10-08 18:16:03.000000000 +0200 | |
@@ -1,4 +1,4 @@ | |
-# $Id: Makefile,v 1.125 2015/07/29 22:05:23 nanard Exp $ | |
+# $Id: Makefile,v 1.131 2015/10/08 16:15:46 nanard Exp $ | |
# MiniUPnP Project | |
# http://miniupnp.free.fr/ | |
# http://miniupnp.tuxfamily.org/ | |
@@ -35,8 +35,15 @@ | |
CFLAGS += -fno-common | |
CFLAGS += -DMINIUPNPC_SET_SOCKET_TIMEOUT | |
CFLAGS += -DMINIUPNPC_GET_SRC_ADDR | |
-CFLAGS += -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112L | |
-CFLAGS += -ansi | |
+CFLAGS += -D_BSD_SOURCE | |
+CFLAGS += -D_DEFAULT_SOURCE | |
+ifneq ($(OS), FreeBSD) | |
+ifneq ($(OS), Darwin) | |
+#CFLAGS += -D_POSIX_C_SOURCE=200112L | |
+CFLAGS += -D_XOPEN_SOURCE=600 | |
+endif | |
+endif | |
+#CFLAGS += -ansi | |
# -DNO_GETADDRINFO | |
INSTALL = install | |
SH = /bin/sh | |
@@ -46,29 +53,32 @@ | |
#JNAERATOR = jnaerator-0.9.8-shaded.jar | |
#JNAERATORARGS = -library miniupnpc | |
#JNAERATOR = jnaerator-0.10-shaded.jar | |
-JNAERATOR = jnaerator-0.11-shaded.jar | |
+#JNAERATOR = jnaerator-0.11-shaded.jar | |
+# https://repo1.maven.org/maven2/com/nativelibs4java/jnaerator/0.12/jnaerator-0.12-shaded.jar | |
+JNAERATOR = jnaerator-0.12-shaded.jar | |
JNAERATORARGS = -mode StandaloneJar -runtime JNAerator -library miniupnpc | |
-JNAERATORBASEURL = http://jnaerator.googlecode.com/files/ | |
+#JNAERATORBASEURL = http://jnaerator.googlecode.com/files/ | |
+JNAERATORBASEURL = https://repo1.maven.org/maven2/com/nativelibs4java/jnaerator/0.12 | |
ifeq (SunOS, $(OS)) | |
LDFLAGS=-lsocket -lnsl -lresolv | |
endif | |
# APIVERSION is used to build SONAME | |
-APIVERSION = 14 | |
+APIVERSION = 15 | |
SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \ | |
upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \ | |
minixmlvalid.c testupnpreplyparse.c minissdpc.c \ | |
upnperrors.c testigddescparse.c testminiwget.c \ | |
connecthostport.c portlistingparse.c receivedata.c \ | |
- testportlistingparse.c miniupnpcmodule.c \ | |
+ upnpdev.c testportlistingparse.c miniupnpcmodule.c \ | |
minihttptestserver.c \ | |
listdevices.c | |
LIBOBJS = miniwget.o minixml.o igd_desc_parse.o minisoap.o \ | |
miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \ | |
- connecthostport.o portlistingparse.o receivedata.o | |
+ connecthostport.o portlistingparse.o receivedata.o upnpdev.o | |
ifneq ($(OS), AmigaOS) | |
CFLAGS := -fPIC $(CFLAGS) | |
@@ -81,6 +91,7 @@ | |
HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \ | |
upnpreplyparse.h upnperrors.h miniupnpctypes.h \ | |
portlistingparse.h \ | |
+ upnpdev.h \ | |
miniupnpc_declspec.h | |
# library names | |
@@ -325,39 +336,40 @@ | |
# DO NOT DELETE THIS LINE -- make depend depends on it. | |
igd_desc_parse.o: igd_desc_parse.h | |
-miniupnpc.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h minissdpc.h | |
-miniupnpc.o: miniwget.h minisoap.h minixml.h upnpcommands.h upnpreplyparse.h | |
-miniupnpc.o: portlistingparse.h miniupnpctypes.h connecthostport.h | |
-miniupnpc.o: receivedata.h | |
+miniupnpc.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h upnpdev.h | |
+miniupnpc.o: minissdpc.h miniwget.h minisoap.h minixml.h upnpcommands.h | |
+miniupnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h | |
+miniupnpc.o: connecthostport.h | |
minixml.o: minixml.h | |
minisoap.o: minisoap.h miniupnpcstrings.h | |
miniwget.o: miniupnpcstrings.h miniwget.h miniupnpc_declspec.h | |
miniwget.o: connecthostport.h receivedata.h | |
upnpc.o: miniwget.h miniupnpc_declspec.h miniupnpc.h igd_desc_parse.h | |
-upnpc.o: upnpcommands.h upnpreplyparse.h portlistingparse.h miniupnpctypes.h | |
-upnpc.o: upnperrors.h miniupnpcstrings.h | |
+upnpc.o: upnpdev.h upnpcommands.h upnpreplyparse.h portlistingparse.h | |
+upnpc.o: miniupnpctypes.h upnperrors.h miniupnpcstrings.h | |
upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h | |
upnpcommands.o: miniupnpc_declspec.h miniupnpctypes.h miniupnpc.h | |
-upnpcommands.o: igd_desc_parse.h | |
+upnpcommands.o: igd_desc_parse.h upnpdev.h | |
upnpreplyparse.o: upnpreplyparse.h minixml.h | |
testminixml.o: minixml.h igd_desc_parse.h | |
minixmlvalid.o: minixml.h | |
testupnpreplyparse.o: upnpreplyparse.h | |
-minissdpc.o: minissdpc.h miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h | |
-minissdpc.o: codelength.h | |
+minissdpc.o: minissdpc.h miniupnpc_declspec.h upnpdev.h miniupnpc.h | |
+minissdpc.o: igd_desc_parse.h receivedata.h codelength.h | |
upnperrors.o: upnperrors.h miniupnpc_declspec.h upnpcommands.h | |
upnperrors.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h | |
-upnperrors.o: miniupnpc.h igd_desc_parse.h | |
+upnperrors.o: miniupnpc.h igd_desc_parse.h upnpdev.h | |
testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.h | |
-testigddescparse.o: miniupnpc_declspec.h | |
+testigddescparse.o: miniupnpc_declspec.h upnpdev.h | |
testminiwget.o: miniwget.h miniupnpc_declspec.h | |
connecthostport.o: connecthostport.h | |
portlistingparse.o: portlistingparse.h miniupnpc_declspec.h miniupnpctypes.h | |
portlistingparse.o: minixml.h | |
receivedata.o: receivedata.h | |
+upnpdev.o: upnpdev.h miniupnpc_declspec.h | |
testportlistingparse.o: portlistingparse.h miniupnpc_declspec.h | |
testportlistingparse.o: miniupnpctypes.h | |
miniupnpcmodule.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h | |
-miniupnpcmodule.o: upnpcommands.h upnpreplyparse.h portlistingparse.h | |
-miniupnpcmodule.o: miniupnpctypes.h upnperrors.h | |
-listdevices.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h | |
+miniupnpcmodule.o: upnpdev.h upnpcommands.h upnpreplyparse.h | |
+miniupnpcmodule.o: portlistingparse.h miniupnpctypes.h upnperrors.h | |
+listdevices.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h upnpdev.h | |
diff -duN miniupnpc-1.9.20150730/Makefile.mingw miniupnpc-1.9.20151008/Makefile.mingw | |
--- miniupnpc-1.9.20150730/Makefile.mingw 2014-06-10 12:02:51.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/Makefile.mingw 2015-09-22 11:59:25.000000000 +0200 | |
@@ -1,7 +1,7 @@ | |
-# $Id: Makefile.mingw,v 1.19 2014/06/10 09:48:11 nanard Exp $ | |
+# $Id: Makefile.mingw,v 1.21 2015/09/18 12:45:16 nanard Exp $ | |
# Miniupnp project. | |
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ | |
-# (c) 2005-2014 Thomas Bernard | |
+# (c) 2005-2015 Thomas Bernard | |
# This Makefile is made for MinGW | |
# | |
CC = gcc | |
@@ -12,8 +12,10 @@ | |
# -liphlpapi is needed for GetBestRoute() and GetIpAddrTable() | |
PYTHON=\utils\python25\python | |
OBJS=miniwget.o minixml.o igd_desc_parse.o minisoap.o \ | |
+ minissdpc.o \ | |
miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \ | |
- connecthostport.o portlistingparse.o receivedata.o | |
+ connecthostport.o portlistingparse.o receivedata.o \ | |
+ upnpdev.o | |
OBJSDLL=$(addprefix dll/, $(OBJS)) | |
all: init upnpc-static upnpc-shared testminixml libminiupnpc.a miniupnpc.dll | |
@@ -71,9 +73,10 @@ | |
miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings | |
wingenminiupnpcstrings $< $@ | |
-minixml.o: minixml.c minixml.h miniupnpcstrings.h | |
+minixml.o: minixml.c minixml.h | |
-upnpc.o: upnpc.c miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h upnpreplyparse.h upnpcommands.h upnperrors.h | |
+upnpc.o: upnpc.c miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h | |
+upnpc.o: upnpreplyparse.h upnpcommands.h upnperrors.h miniupnpcstrings.h | |
miniwget.o: miniwget.c miniwget.h miniupnpcstrings.h connecthostport.h | |
@@ -89,3 +92,7 @@ | |
upnpcommands.o: upnpcommands.c upnpcommands.h upnpreplyparse.h miniupnpc.h portlistingparse.h | |
+minissdpc.o: minissdpc.c minissdpc.h receivedata.h | |
+ | |
+upnpdev.o: upnpdev.c upnpdev.h | |
+ | |
Common subdirectories: miniupnpc-1.9.20150730/man3 and miniupnpc-1.9.20151008/man3 | |
diff -duN miniupnpc-1.9.20150730/minissdpc.c miniupnpc-1.9.20151008/minissdpc.c | |
--- miniupnpc-1.9.20150730/minissdpc.c 2015-07-30 00:05:55.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/minissdpc.c 2015-10-08 18:16:03.000000000 +0200 | |
@@ -1,4 +1,4 @@ | |
-/* $Id: minissdpc.c,v 1.22 2015/07/23 17:15:01 nanard Exp $ */ | |
+/* $Id: minissdpc.c,v 1.29 2015/10/08 16:15:47 nanard Exp $ */ | |
/* Project : miniupnp | |
* Web : http://miniupnp.free.fr/ | |
* Author : Thomas BERNARD | |
@@ -9,42 +9,92 @@ | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
-#include <unistd.h> | |
#include <sys/types.h> | |
#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) | |
#ifdef _WIN32 | |
#include <winsock2.h> | |
#include <ws2tcpip.h> | |
#include <io.h> | |
+#include <iphlpapi.h> | |
#include <winsock.h> | |
+#define snprintf _snprintf | |
+#if !defined(_MSC_VER) | |
#include <stdint.h> | |
-#endif | |
+#else /* !defined(_MSC_VER) */ | |
+typedef unsigned short uint16_t; | |
+#endif /* !defined(_MSC_VER) */ | |
+#ifndef strncasecmp | |
+#if defined(_MSC_VER) && (_MSC_VER >= 1400) | |
+#define strncasecmp _memicmp | |
+#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ | |
+#define strncasecmp memicmp | |
+#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ | |
+#endif /* #ifndef strncasecmp */ | |
+#endif /* _WIN32 */ | |
#if defined(__amigaos__) || defined(__amigaos4__) | |
#include <sys/socket.h> | |
-#endif | |
+#endif /* defined(__amigaos__) || defined(__amigaos4__) */ | |
#if defined(__amigaos__) | |
#define uint16_t unsigned short | |
-#endif | |
+#endif /* defined(__amigaos__) */ | |
/* Hack */ | |
#define UNIX_PATH_LEN 108 | |
struct sockaddr_un { | |
uint16_t sun_family; | |
char sun_path[UNIX_PATH_LEN]; | |
}; | |
-#else | |
+#else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */ | |
+#include <strings.h> | |
+#include <unistd.h> | |
#include <sys/socket.h> | |
+#include <sys/param.h> | |
+#include <sys/time.h> | |
#include <sys/un.h> | |
+#include <netinet/in.h> | |
+#include <arpa/inet.h> | |
+#include <netdb.h> | |
+#include <net/if.h> | |
+#define closesocket close | |
+#endif | |
+ | |
+#ifdef _WIN32 | |
+#define PRINT_SOCKET_ERROR(x) printf("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(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, int * error) | |
{ | |
- struct UPNPDev * devlist; | |
+ struct UPNPDev * devlist = NULL; | |
int s; | |
int res; | |
@@ -58,16 +108,16 @@ | |
if (res < 0) { | |
if (error) | |
*error = res; | |
- return NULL; | |
+ } else { | |
+ devlist = receiveDevicesFromMiniSSDPD(s, error); | |
} | |
- devlist = receiveDevicesFromMiniSSDPD(s, error); | |
disconnectFromMiniSSDPD(s); | |
return devlist; | |
} | |
/* macros used to read from unix socket */ | |
#define READ_BYTE_BUFFER(c) \ | |
- if(bufferindex >= n) { \ | |
+ if((int)bufferindex >= n) { \ | |
n = read(s, buffer, sizeof(buffer)); \ | |
if(n<=0) break; \ | |
bufferindex = 0; \ | |
@@ -81,7 +131,7 @@ | |
#define READ_COPY_BUFFER(dst, len) \ | |
for(l = len, p = (unsigned char *)dst; l > 0; ) { \ | |
unsigned int lcopy; \ | |
- if(bufferindex >= n) { \ | |
+ if((int)bufferindex >= n) { \ | |
n = read(s, buffer, sizeof(buffer)); \ | |
if(n<=0) break; \ | |
bufferindex = 0; \ | |
@@ -145,6 +195,7 @@ | |
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) | |
{ | |
/*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ | |
+ close(s); | |
return MINISSDPC_SOCKET_ERROR; | |
} | |
return s; | |
@@ -316,3 +367,478 @@ | |
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; | |
+ | |
+ 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; | |
+ } | |
+ | |
+#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"); | |
+ } | |
+#else | |
+#ifdef DEBUG | |
+ printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); | |
+#endif | |
+#endif | |
+ } else { | |
+ struct in_addr mc_if; | |
+ mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ | |
+ if(mc_if.s_addr != INADDR_NONE) | |
+ { | |
+ ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; | |
+ if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) | |
+ { | |
+ PRINT_SOCKET_ERROR("setsockopt"); | |
+ } | |
+ } else { | |
+#ifdef HAS_IP_MREQN | |
+ /* was not an ip address, try with an interface name */ | |
+ struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ | |
+ memset(&reqn, 0, sizeof(struct ip_mreqn)); | |
+ reqn.imr_ifindex = if_nametoindex(multicastif); | |
+ if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) | |
+ { | |
+ PRINT_SOCKET_ERROR("setsockopt"); | |
+ } | |
+#else | |
+#ifdef DEBUG | |
+ printf("Setting of multicast interface not supported with interface name.\n"); | |
+#endif | |
+#endif | |
+ } | |
+ } | |
+ } | |
+ | |
+ /* 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++) { | |
+ /* 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); | |
+#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"); | |
+ 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(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; | |
+ } | |
+ } | |
+ freeaddrinfo(servinfo); | |
+ if(n < 0) { | |
+ if(error) | |
+ *error = MINISSDPC_SOCKET_ERROR; | |
+ break; | |
+ } | |
+#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(!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; | |
+ } | |
+ } | |
+ } | |
+error: | |
+ closesocket(sudp); | |
+ return devlist; | |
+} | |
+ | |
diff -duN miniupnpc-1.9.20150730/minissdpc.h miniupnpc-1.9.20151008/minissdpc.h | |
--- miniupnpc-1.9.20150730/minissdpc.h 2015-07-30 00:05:55.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/minissdpc.h 2015-10-08 18:16:03.000000000 +0200 | |
@@ -1,4 +1,4 @@ | |
-/* $Id: minissdpc.h,v 1.4 2015/07/23 20:40:08 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 | |
@@ -9,9 +9,11 @@ | |
#define MINISSDPC_H_INCLUDED | |
#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) | |
@@ -21,6 +23,8 @@ | |
extern "C" { | |
#endif | |
+#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) | |
+ | |
MINIUPNP_LIBSPEC struct UPNPDev * | |
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error); | |
@@ -36,6 +40,16 @@ | |
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 | |
diff -duN miniupnpc-1.9.20150730/miniupnpc.c miniupnpc-1.9.20151008/miniupnpc.c | |
--- miniupnpc-1.9.20150730/miniupnpc.c 2015-07-30 00:05:55.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/miniupnpc.c 2015-10-08 18:16:03.000000000 +0200 | |
@@ -1,26 +1,10 @@ | |
-/* $Id: miniupnpc.c,v 1.135 2015/07/23 20:40:08 nanard Exp $ */ | |
+/* $Id: miniupnpc.c,v 1.140 2015/10/08 16:15:47 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. */ | |
-#define __EXTENSIONS__ 1 | |
-#if !defined(__APPLE__) && !defined(__sun) | |
-#if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__) | |
-#ifndef __cplusplus | |
-#define _XOPEN_SOURCE 600 | |
-#endif | |
-#endif | |
-#ifndef __BSD_VISIBLE | |
-#define __BSD_VISIBLE 1 | |
-#endif | |
-#endif | |
- | |
-#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__) | |
-#define HAS_IP_MREQN | |
-#endif | |
- | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
@@ -63,26 +47,11 @@ | |
#include <errno.h> | |
#define closesocket close | |
#endif /* #else _WIN32 */ | |
-#if defined(__amigaos__) || defined(__amigaos4__) | |
-/* Amiga OS specific stuff */ | |
-#define TIMEVAL struct timeval | |
-#endif | |
#ifdef __GNU__ | |
#define MAXHOSTNAMELEN 64 | |
#endif | |
-#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN) | |
-/* Several versions of glibc don't define this structure, | |
- * define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */ | |
-struct ip_mreqn | |
-{ | |
- struct in_addr imr_multiaddr; /* IP multicast address of group */ | |
- struct in_addr imr_address; /* local IP address of interface */ | |
- int imr_ifindex; /* Interface index */ | |
-}; | |
-#endif | |
- | |
#include "miniupnpc.h" | |
#include "minissdpc.h" | |
#include "miniwget.h" | |
@@ -90,17 +59,10 @@ | |
#include "minixml.h" | |
#include "upnpcommands.h" | |
#include "connecthostport.h" | |
-#include "receivedata.h" | |
/* compare the begining of a string with a constant string */ | |
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) | |
-#ifdef _WIN32 | |
-#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); | |
-#else | |
-#define PRINT_SOCKET_ERROR(x) perror(x) | |
-#endif | |
- | |
#ifndef MAXHOSTNAMELEN | |
#define MAXHOSTNAMELEN 64 | |
#endif | |
@@ -264,82 +226,6 @@ | |
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, | |
- 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 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 */ | |
- | |
/* upnpDiscoverDevices() : | |
* return a chained list of all devices found or NULL if | |
* no devices was found. | |
@@ -351,38 +237,16 @@ | |
MINIUPNP_LIBSPEC struct UPNPDev * | |
upnpDiscoverDevices(const char * const deviceTypes[], | |
int delay, const char * multicastif, | |
- const char * minissdpdsock, int sameport, | |
+ const char * minissdpdsock, int localport, | |
int ipv6, unsigned char ttl, | |
int * error, | |
int searchalltypes) | |
{ | |
struct UPNPDev * tmp; | |
struct UPNPDev * devlist = 0; | |
- unsigned int scope_id = 0; | |
- int opt = 1; | |
- static const char MSearchMsgFmt[] = | |
- "M-SEARCH * HTTP/1.1\r\n" | |
- "HOST: %s:" XSTR(PORT) "\r\n" | |
- "ST: %s\r\n" | |
- "MAN: \"ssdp:discover\"\r\n" | |
- "MX: %u\r\n" | |
- "\r\n"; | |
+#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) | |
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; | |
-#endif | |
- int linklocal = 1; | |
+#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ | |
if(error) | |
*error = UPNPDISCOVER_UNKNOWN_ERROR; | |
@@ -427,349 +291,24 @@ | |
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ | |
/* direct discovery if minissdpd responses are not sufficient */ | |
-#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; | |
-#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 ); | |
-#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 = UPNPDISCOVER_SOCKET_ERROR; | |
- PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)"); | |
- return NULL; | |
- } | |
- | |
- if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) | |
- { | |
- /* 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"); | |
- } | |
-#else | |
-#ifdef DEBUG | |
- printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); | |
-#endif | |
-#endif | |
- } else { | |
- struct in_addr mc_if; | |
- mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ | |
- if(mc_if.s_addr != INADDR_NONE) | |
- { | |
- ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; | |
- if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) | |
- { | |
- PRINT_SOCKET_ERROR("setsockopt"); | |
- } | |
- } else { | |
-#ifdef HAS_IP_MREQN | |
- /* was not an ip address, try with an interface name */ | |
- struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ | |
- memset(&reqn, 0, sizeof(struct ip_mreqn)); | |
- reqn.imr_ifindex = if_nametoindex(multicastif); | |
- if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) | |
- { | |
- PRINT_SOCKET_ERROR("setsockopt"); | |
- } | |
-#else | |
-#ifdef DEBUG | |
- printf("Setting of multicast interface not supported with interface name.\n"); | |
-#endif | |
-#endif | |
- } | |
- } | |
- } | |
- | |
- /* 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 = UPNPDISCOVER_SOCKET_ERROR; | |
- PRINT_SOCKET_ERROR("bind"); | |
- closesocket(sudp); | |
- return NULL; | |
- } | |
- | |
- if(error) | |
- *error = UPNPDISCOVER_SUCCESS; | |
- /* Calculating maximum response time in seconds */ | |
- mx = ((unsigned int)delay) / 1000u; | |
- if(mx == 0) { | |
- mx = 1; | |
- delay = 1000; | |
- } | |
- /* receiving SSDP response packet */ | |
- for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) { | |
- /* 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); | |
-#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(PORT); | |
- inet_pton(AF_INET6, | |
- linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, | |
- &(p->sin6_addr)); | |
- } else { | |
- struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; | |
- p->sin_family = AF_INET; | |
- p->sin_port = htons(PORT); | |
- p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); | |
- } | |
- n = sendto(sudp, bufr, n, 0, &sockudp_w, | |
- ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); | |
- if (n < 0) { | |
- if(error) | |
- *error = UPNPDISCOVER_SOCKET_ERROR; | |
- PRINT_SOCKET_ERROR("sendto"); | |
- break; | |
- } | |
-#else /* #ifdef NO_GETADDRINFO */ | |
- memset(&hints, 0, sizeof(hints)); | |
- hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */ | |
- hints.ai_socktype = SOCK_DGRAM; | |
- /*hints.ai_flags = */ | |
- if ((rv = getaddrinfo(ipv6 | |
- ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) | |
- : UPNP_MCAST_ADDR, | |
- XSTR(PORT), &hints, &servinfo)) != 0) { | |
- if(error) | |
- *error = UPNPDISCOVER_SOCKET_ERROR; | |
-#ifdef _WIN32 | |
- fprintf(stderr, "getaddrinfo() failed: %d\n", rv); | |
-#else | |
- fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); | |
-#endif | |
- break; | |
- } | |
- for(p = servinfo; p; p = p->ai_next) { | |
- n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); | |
- if (n < 0) { | |
-#ifdef DEBUG | |
- char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; | |
- if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, | |
- sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { | |
- fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); | |
- } | |
-#endif | |
- PRINT_SOCKET_ERROR("sendto"); | |
- continue; | |
- } | |
- } | |
- freeaddrinfo(servinfo); | |
- if(n < 0) { | |
- if(error) | |
- *error = UPNPDISCOVER_SOCKET_ERROR; | |
- break; | |
- } | |
-#endif /* #ifdef NO_GETADDRINFO */ | |
- /* Waiting for SSDP REPLY packet to M-SEARCH | |
- * if searchalltypes is set, enter the loop only | |
- * when the last deviceType is reached */ | |
- if(!searchalltypes || !deviceTypes[deviceIndex + 1]) do { | |
- n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id); | |
- if (n < 0) { | |
- /* error */ | |
- if(error) | |
- *error = UPNPDISCOVER_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 = UPNPDISCOVER_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 = UPNPDISCOVER_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; | |
- } | |
+ 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; | |
} | |
} | |
-error: | |
- closesocket(sudp); | |
return devlist; | |
} | |
/* upnpDiscover() Discover IGD device */ | |
MINIUPNP_LIBSPEC struct UPNPDev * | |
upnpDiscover(int delay, const char * multicastif, | |
- const char * minissdpdsock, int sameport, | |
+ const char * minissdpdsock, int localport, | |
int ipv6, unsigned char ttl, | |
int * error) | |
{ | |
@@ -786,14 +325,14 @@ | |
0 | |
}; | |
return upnpDiscoverDevices(deviceList, | |
- delay, multicastif, minissdpdsock, sameport, | |
+ delay, multicastif, minissdpdsock, localport, | |
ipv6, ttl, error, 0); | |
} | |
/* upnpDiscoverAll() Discover all UPnP devices */ | |
MINIUPNP_LIBSPEC struct UPNPDev * | |
upnpDiscoverAll(int delay, const char * multicastif, | |
- const char * minissdpdsock, int sameport, | |
+ const char * minissdpdsock, int localport, | |
int ipv6, unsigned char ttl, | |
int * error) | |
{ | |
@@ -803,14 +342,14 @@ | |
0 | |
}; | |
return upnpDiscoverDevices(deviceList, | |
- delay, multicastif, minissdpdsock, sameport, | |
+ 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 sameport, | |
+ const char * minissdpdsock, int localport, | |
int ipv6, unsigned char ttl, | |
int * error) | |
{ | |
@@ -819,23 +358,10 @@ | |
0 | |
}; | |
return upnpDiscoverDevices(deviceList, | |
- delay, multicastif, minissdpdsock, sameport, | |
+ delay, multicastif, minissdpdsock, localport, | |
ipv6, ttl, error, 0); | |
} | |
-/* freeUPNPDevlist() should be used to | |
- * free the chained list returned by upnpDiscover() */ | |
-MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist) | |
-{ | |
- struct UPNPDev * next; | |
- while(devlist) | |
- { | |
- next = devlist->pNext; | |
- free(devlist); | |
- devlist = next; | |
- } | |
-} | |
- | |
static char * | |
build_absolute_url(const char * baseurl, const char * descURL, | |
const char * url, unsigned int scope_id) | |
@@ -961,9 +487,9 @@ | |
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; | |
} | |
diff -duN miniupnpc-1.9.20150730/miniupnpc.h miniupnpc-1.9.20151008/miniupnpc.h | |
--- miniupnpc-1.9.20150730/miniupnpc.h 2015-07-30 00:09:48.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/miniupnpc.h 2015-10-08 18:22:17.000000000 +0200 | |
@@ -1,4 +1,4 @@ | |
-/* $Id: miniupnpc.h,v 1.44 2015/07/23 20:40:10 nanard Exp $ */ | |
+/* $Id: miniupnpc.h,v 1.48 2015/10/08 16:19:40 nanard Exp $ */ | |
/* Project: miniupnp | |
* http://miniupnp.free.fr/ | |
* Author: Thomas Bernard | |
@@ -10,6 +10,7 @@ | |
#include "miniupnpc_declspec.h" | |
#include "igd_desc_parse.h" | |
+#include "upnpdev.h" | |
/* error codes : */ | |
#define UPNPDISCOVER_SUCCESS (0) | |
@@ -18,8 +19,14 @@ | |
#define UPNPDISCOVER_MEMORY_ERROR (-102) | |
/* versions : */ | |
-#define MINIUPNPC_VERSION "1.9.20150730" | |
-#define MINIUPNPC_API_VERSION 14 | |
+#define MINIUPNPC_VERSION "1.9.20151008" | |
+#define MINIUPNPC_API_VERSION 15 | |
+ | |
+/* Source port: | |
+ Using "1" as an alias for 1900 for backwards compatability | |
+ (presuming one would have used that for the "sameport" parameter) */ | |
+#define UPNP_LOCAL_PORT_ANY 0 | |
+#define UPNP_LOCAL_PORT_SAME 1 | |
#ifdef __cplusplus | |
extern "C" { | |
@@ -33,15 +40,6 @@ | |
const char *, struct UPNParg *, | |
int *); | |
-struct UPNPDev { | |
- struct UPNPDev * pNext; | |
- char * descURL; | |
- char * st; | |
- unsigned int scope_id; | |
- char * usn; | |
- char buffer[3]; | |
-}; | |
- | |
/* upnpDiscover() | |
* discover UPnP devices on the network. | |
* The discovered devices are returned as a chained list. | |
@@ -53,41 +51,39 @@ | |
* 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. | |
+ * 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, | |
+ const char * minissdpdsock, int localport, | |
int ipv6, unsigned char ttl, | |
int * error); | |
MINIUPNP_LIBSPEC struct UPNPDev * | |
upnpDiscoverAll(int delay, const char * multicastif, | |
- const char * minissdpdsock, int sameport, | |
+ 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 sameport, | |
+ 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 sameport, | |
+ const char * minissdpdsock, int localport, | |
int ipv6, unsigned char ttl, | |
int * error, | |
int searchalltypes); | |
-/* freeUPNPDevlist() | |
- * free list returned by upnpDiscover() */ | |
-MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); | |
- | |
/* parserootdesc() : | |
* parse root XML description of a UPnP device and fill the IGDdatas | |
* structure. */ | |
diff -duN miniupnpc-1.9.20150730/miniupnpcmodule.c miniupnpc-1.9.20151008/miniupnpcmodule.c | |
--- miniupnpc-1.9.20150730/miniupnpcmodule.c 2015-05-22 12:58:32.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/miniupnpcmodule.c 2015-10-08 18:16:06.000000000 +0200 | |
@@ -1,4 +1,4 @@ | |
-/* $Id: miniupnpcmodule.c,v 1.26 2015/05/22 10:29:08 nanard Exp $*/ | |
+/* $Id: miniupnpcmodule.c,v 1.28 2015/10/08 16:15:48 nanard Exp $*/ | |
/* Project : miniupnp | |
* Author : Thomas BERNARD | |
* website : http://miniupnp.tuxfamily.org/ | |
@@ -42,6 +42,7 @@ | |
struct UPNPUrls urls; | |
struct IGDdatas data; | |
unsigned int discoverdelay; /* value passed to upnpDiscover() */ | |
+ unsigned int localport; /* value passed to upnpDiscover() */ | |
char lanaddr[40]; /* our ip address on the LAN */ | |
char * multicastif; | |
char * minissdpdsocket; | |
@@ -54,6 +55,15 @@ | |
{"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay), | |
0/*READWRITE*/, "value in ms used to wait for SSDP responses" | |
}, | |
+ {"localport", T_UINT, offsetof(UPnPObject, localport), | |
+ 0/*READWRITE*/, | |
+ "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" | |
+ }, | |
/* T_STRING is allways readonly :( */ | |
{"multicastif", T_STRING, offsetof(UPnPObject, multicastif), | |
0, "IP of the network interface to be used for multicast operations" | |
@@ -70,15 +80,22 @@ | |
char* multicastif = NULL; | |
char* minissdpdsocket = NULL; | |
static char *kwlist[] = { | |
- "multicastif", "minissdpdsocket", "discoverdelay", NULL | |
+ "multicastif", "minissdpdsocket", "discoverdelay", | |
+ "localport", NULL | |
}; | |
- if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzI", kwlist, | |
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist, | |
&multicastif, | |
&minissdpdsocket, | |
- &self->discoverdelay)) | |
- return -1; | |
+ &self->discoverdelay, | |
+ &self->localport)) | |
+ return -1; | |
+ if(self->localport>1 && | |
+ (self->localport>65534||self->localport<1024)) { | |
+ PyErr_SetString(PyExc_Exception, "Invalid localport value"); | |
+ return -1; | |
+ } | |
if(multicastif) | |
self->multicastif = strdup(multicastif); | |
if(minissdpdsocket) | |
@@ -112,8 +129,9 @@ | |
self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/, | |
self->multicastif, | |
self->minissdpdsocket, | |
- 0/*sameport flag*/, | |
+ (int)self->localport, | |
0/*ip v6*/, | |
+ 2/* TTL */, | |
0/*error */); | |
Py_END_ALLOW_THREADS | |
/* Py_RETURN_NONE ??? */ | |
diff -duN miniupnpc-1.9.20150730/miniwget.c miniupnpc-1.9.20151008/miniwget.c | |
--- miniupnpc-1.9.20150730/miniwget.c 2015-07-15 18:14:01.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/miniwget.c 2015-08-06 15:36:25.000000000 +0200 | |
@@ -1,4 +1,4 @@ | |
-/* $Id: miniwget.c,v 1.70 2015/07/15 12:41:13 nanard Exp $ */ | |
+/* $Id: miniwget.c,v 1.71 2015/08/06 09:54:20 nanard Exp $ */ | |
/* Project : miniupnp | |
* Website : http://miniupnp.free.fr/ | |
* Author : Thomas Bernard | |
@@ -94,7 +94,7 @@ | |
return NULL; | |
} | |
content_buf = malloc(content_buf_len); | |
- if(header_buf == NULL) | |
+ if(content_buf == NULL) | |
{ | |
free(header_buf); | |
#ifdef DEBUG | |
Common subdirectories: miniupnpc-1.9.20150730/msvc and miniupnpc-1.9.20151008/msvc | |
diff -duN miniupnpc-1.9.20150730/pymoduletest.py miniupnpc-1.9.20151008/pymoduletest.py | |
--- miniupnpc-1.9.20150730/pymoduletest.py 2015-05-22 12:58:32.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/pymoduletest.py 2015-10-08 18:16:06.000000000 +0200 | |
@@ -14,6 +14,7 @@ | |
parser.add_argument('-m', '--multicastif') | |
parser.add_argument('-p', '--minissdpdsocket') | |
parser.add_argument('-d', '--discoverdelay', type=int, default=200) | |
+parser.add_argument('-z', '--localport', type=int, default=0) | |
# create the object | |
u = miniupnpc.UPnP(**vars(parser.parse_args())) | |
Common subdirectories: miniupnpc-1.9.20150730/testdesc and miniupnpc-1.9.20151008/testdesc | |
diff -duN miniupnpc-1.9.20150730/testigddescparse.c miniupnpc-1.9.20151008/testigddescparse.c | |
--- miniupnpc-1.9.20150730/testigddescparse.c 2015-07-21 15:24:16.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/testigddescparse.c 2015-08-06 15:36:25.000000000 +0200 | |
@@ -1,4 +1,4 @@ | |
-/* $Id: testigddescparse.c,v 1.9 2015/07/21 13:17:50 nanard Exp $ */ | |
+/* $Id: testigddescparse.c,v 1.10 2015/08/06 09:55:24 nanard Exp $ */ | |
/* Project : miniupnp | |
* http://miniupnp.free.fr/ | |
* Author : Thomas Bernard | |
@@ -165,6 +165,7 @@ | |
fprintf(stderr, "Failed to read file %s. %d out of %d bytes.\n", | |
argv[1], r, len); | |
fclose(f); | |
+ free(buffer); | |
return 1; | |
} | |
fclose(f); | |
diff -duN miniupnpc-1.9.20150730/testminiwget.sh miniupnpc-1.9.20151008/testminiwget.sh | |
--- miniupnpc-1.9.20150730/testminiwget.sh 2015-07-21 15:24:16.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/testminiwget.sh 2015-09-17 15:05:27.000000000 +0200 | |
@@ -1,5 +1,5 @@ | |
#!/bin/sh | |
-# $Id: testminiwget.sh,v 1.12 2015/07/16 15:13:49 nanard Exp $ | |
+# $Id: testminiwget.sh,v 1.13 2015/09/03 17:57:44 nanard Exp $ | |
# project miniupnp : http://miniupnp.free.fr/ | |
# (c) 2011-2015 Thomas Bernard | |
# | |
@@ -15,7 +15,7 @@ | |
# The script was tested and works with ksh, bash | |
# it should now also run with dash | |
-TMPD=`mktemp -t -d miniwgetXXXXXXXXXX` | |
+TMPD=`mktemp -d -t miniwgetXXXXXXXXXX` | |
HTTPSERVEROUT="${TMPD}/httpserverout" | |
EXPECTEDFILE="${TMPD}/expectedfile" | |
DOWNLOADEDFILE="${TMPD}/downloadedfile" | |
Common subdirectories: miniupnpc-1.9.20150730/testreplyparse and miniupnpc-1.9.20151008/testreplyparse | |
diff -duN miniupnpc-1.9.20150730/upnpc.c miniupnpc-1.9.20151008/upnpc.c | |
--- miniupnpc-1.9.20150730/upnpc.c 2015-07-30 00:05:57.000000000 +0200 | |
+++ miniupnpc-1.9.20151008/upnpc.c 2015-10-08 18:16:06.000000000 +0200 | |
@@ -1,4 +1,4 @@ | |
-/* $Id: upnpc.c,v 1.111 2015/07/23 20:40:10 nanard Exp $ */ | |
+/* $Id: upnpc.c,v 1.112 2015/10/08 16:15:48 nanard Exp $ */ | |
/* Project : miniupnp | |
* Author : Thomas Bernard | |
* Copyright (c) 2005-2015 Thomas Bernard | |
@@ -543,6 +543,7 @@ | |
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; | |
@@ -559,7 +560,7 @@ | |
} | |
#endif | |
printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING); | |
- printf(" (c) 2005-2014 Thomas Bernard.\n"); | |
+ printf(" (c) 2005-2015 Thomas Bernard.\n"); | |
printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n" | |
"for more information.\n"); | |
/* command line processing */ | |
@@ -576,6 +577,18 @@ | |
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') | |
@@ -629,6 +642,7 @@ | |
fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n"); | |
fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n"); | |
fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n"); | |
+ fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n"); | |
fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n"); | |
fprintf(stderr, " -t ttl : set multicast TTL. Default value is 2.\n"); | |
return 1; | |
@@ -636,7 +650,7 @@ | |
if( rootdescurl | |
|| (devlist = upnpDiscover(2000, multicastif, minissdpdpath, | |
- 0/*sameport*/, ipv6, ttl, &error))) | |
+ localport, ipv6, ttl, &error))) | |
{ | |
struct UPNPDev * device; | |
struct UPNPUrls urls; | |
diff -duN miniupnpc-1.9.20150730/upnpdev.c miniupnpc-1.9.20151008/upnpdev.c | |
--- miniupnpc-1.9.20150730/upnpdev.c 1970-01-01 01:00:00.000000000 +0100 | |
+++ miniupnpc-1.9.20151008/upnpdev.c 2015-08-28 14:14:19.000000000 +0200 | |
@@ -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 -duN miniupnpc-1.9.20150730/upnpdev.h miniupnpc-1.9.20151008/upnpdev.h | |
--- miniupnpc-1.9.20150730/upnpdev.h 1970-01-01 01:00:00.000000000 +0100 | |
+++ miniupnpc-1.9.20151008/upnpdev.h 2015-08-28 14:14:19.000000000 +0200 | |
@@ -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 */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment