updated miniupnpc

This commit is contained in:
Riccardo Spagni 2015-12-30 09:56:25 +02:00
parent 9e45eadb98
commit 7da9905589
No known key found for this signature in database
GPG key ID: 55432DF31CCD4FCD
45 changed files with 2070 additions and 1472 deletions

View file

@ -23,3 +23,10 @@ jnaerator-*.jar
miniupnpc.h.bak
testupnpreplyparse
validateupnpreplyparse
testportlistingparse
validateportlistingparse
listdevices
testigddescparse
validateigddescparse
dist/
miniupnpc.egg-info/

View file

@ -2,30 +2,67 @@ cmake_minimum_required (VERSION 2.6)
project (miniupnpc C)
set (MINIUPNPC_VERSION 1.9)
set (MINIUPNPC_API_VERSION 10)
set (MINIUPNPC_API_VERSION 15)
if (NOT CMAKE_BUILD_TYPE)
if (WIN32)
set (DEFAULT_BUILD_TYPE MinSizeRel)
else (WIN32)
set (DEFAULT_BUILD_TYPE RelWithDebInfo)
endif(WIN32)
set (CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE} CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif()
option (UPNPC_BUILD_STATIC "Build static library" TRUE)
option (UPNPC_BUILD_SHARED "Build shared library" TRUE)
if (NOT WIN32)
option (UPNPC_BUILD_TESTS "Build test executables" TRUE)
endif (NOT WIN32)
option (NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE)
mark_as_advanced (NO_GETADDRINFO)
if (NO_GETADDRINFO)
add_definitions (-DNO_GETADDRINFO)
endif ()
endif (NO_GETADDRINFO)
if (NOT WIN32)
add_definitions (-DMINIUPNPC_SET_SOCKET_TIMEOUT)
add_definitions (-D_BSD_SOURCE -D_POSIX_C_SOURCE=201112)
else ()
add_definitions (-D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112L)
else (NOT WIN32)
add_definitions (-D_WIN32_WINNT=0x0501) # XP or higher for getnameinfo and friends
endif ()
endif (NOT WIN32)
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_definitions (-D_DARWIN_C_SOURCE)
endif ()
configure_file (miniupnpcstrings.h.cmake ${CMAKE_BINARY_DIR}/miniupnpcstrings.h)
# Set compiler specific build flags
if (CMAKE_COMPILER_IS_GNUC)
# Set our own default flags at first run.
if (NOT CONFIGURED)
if (NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
set (_PIC -fPIC)
endif (CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
set (CMAKE_C_FLAGS "${_PIC} -Wall $ENV{CFLAGS}" # CMAKE_C_FLAGS gets appended to the other C flags
CACHE STRING "Flags used by the C compiler during normal builds." FORCE)
set (CMAKE_C_FLAGS_DEBUG "-g -DDDEBUG"
CACHE STRING "Flags used by the C compiler during debug builds." FORCE)
set (CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG"
CACHE STRING "Flags used by the C compiler during release builds." FORCE)
set (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG"
CACHE STRING "Flags used by the C compiler during release builds." FORCE)
set (CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG"
CACHE STRING "Flags used by the C compiler during release builds." FORCE)
endif (NOT CONFIGURED)
endif ()
configure_file (${CMAKE_SOURCE_DIR}/miniupnpcstrings.h.cmake ${CMAKE_BINARY_DIR}/miniupnpcstrings.h)
include_directories (${CMAKE_BINARY_DIR})
set (MINIUPNPC_SOURCES
@ -33,9 +70,11 @@ set (MINIUPNPC_SOURCES
miniupnpc.c
minixml.c
minisoap.c
minissdpc.c
miniwget.c
upnpc.c
upnpcommands.c
upnpdev.c
upnpreplyparse.c
upnperrors.c
connecthostport.c
@ -43,48 +82,77 @@ set (MINIUPNPC_SOURCES
receivedata.c
)
if (NOT WIN32)
if (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
set (MINIUPNPC_SOURCES ${MINIUPNPC_SOURCES} minissdpc.c)
endif ()
endif (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
if (WIN32)
set_source_files_properties (${MINIUPNPC_SOURCES} PROPERTIES
COMPILE_DEFINITIONS MINIUPNP_STATICLIB
COMPILE_DEFINITIONS MINIUPNP_EXPORTS
COMPILE_DEFINITIONS "MINIUPNP_STATICLIB;MINIUPNP_EXPORTS"
)
endif ()
endif (WIN32)
if (WIN32)
# find_library (WINSOCK2_LIBRARY NAMES ws2_32 WS2_32 Ws2_32)
# find_library (IPHLPAPI_LIBRARY NAMES iphlpapi)
set(WINSOCK2_LIBRARY ws2_32)
set(IPHLPAPI_LIBRARY iphlpapi)
find_library (WINSOCK2_LIBRARY NAMES ws2_32 WS2_32 Ws2_32)
find_library (IPHLPAPI_LIBRARY NAMES iphlpapi)
set (LDLIBS ${WINSOCK2_LIBRARY} ${IPHLPAPI_LIBRARY} ${LDLIBS})
endif ()
#elseif (CMAKE_SYSTEM_NAME STREQUAL "Solaris")
# find_library (SOCKET_LIBRARY NAMES socket)
# find_library (NSL_LIBRARY NAMES nsl)
# find_library (RESOLV_LIBRARY NAMES resolv)
# set (LDLIBS ${SOCKET_LIBRARY} ${NSL_LIBRARY} ${RESOLV_LIBRARY} ${LDLIBS})
endif (WIN32)
if (NOT UPNPC_BUILD_STATIC AND NOT UPNPC_BUILD_SHARED)
message (FATAL "Both shared and static libraries are disabled!")
endif ()
message (FATAL "Both shared and static libraries are disabled!")
endif (NOT UPNPC_BUILD_STATIC AND NOT UPNPC_BUILD_SHARED)
if (UPNPC_BUILD_STATIC)
add_library (upnpc-static STATIC ${MINIUPNPC_SOURCES})
set_target_properties (upnpc-static PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
set_target_properties (upnpc-static PROPERTIES OUTPUT_NAME "miniupnpc")
target_link_libraries (upnpc-static ${LDLIBS})
set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} upnpc-static)
set (UPNPC_LIBRARY_TARGET upnpc-static)
endif ()
endif (UPNPC_BUILD_STATIC)
if (UPNPC_BUILD_SHARED)
add_library (upnpc-shared SHARED ${MINIUPNPC_SOURCES})
set_target_properties (upnpc-shared PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
set_target_properties (upnpc-shared PROPERTIES OUTPUT_NAME "miniupnpc")
set_target_properties (upnpc-shared PROPERTIES VERSION ${MINIUPNPC_VERSION})
set_target_properties (upnpc-shared PROPERTIES SOVERSION ${MINIUPNPC_API_VERSION})
target_link_libraries (upnpc-shared ${LDLIBS})
set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} upnpc-shared)
set (UPNPC_LIBRARY_TARGET upnpc-shared)
endif ()
endif (UPNPC_BUILD_SHARED)
if (UPNPC_BUILD_TESTS)
add_executable (testminixml testminixml.c minixml.c igd_desc_parse.c)
target_link_libraries (testminixml ${LDLIBS})
add_executable (minixmlvalid minixmlvalid.c minixml.c)
target_link_libraries (minixmlvalid ${LDLIBS})
add_executable (testupnpreplyparse testupnpreplyparse.c
minixml.c upnpreplyparse.c)
target_link_libraries (testupnpreplyparse ${LDLIBS})
add_executable (testigddescparse testigddescparse.c
igd_desc_parse.c minixml.c miniupnpc.c miniwget.c minissdpc.c
upnpcommands.c upnpreplyparse.c minisoap.c connecthostport.c
portlistingparse.c receivedata.c
)
target_link_libraries (testigddescparse ${LDLIBS})
add_executable (testminiwget testminiwget.c
miniwget.c miniupnpc.c minisoap.c upnpcommands.c minissdpc.c
upnpreplyparse.c minixml.c igd_desc_parse.c connecthostport.c
portlistingparse.c receivedata.c
)
target_link_libraries (testminiwget ${LDLIBS})
# set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} testminixml minixmlvalid testupnpreplyparse testigddescparse testminiwget)
endif (UPNPC_BUILD_TESTS)
install (TARGETS ${UPNPC_INSTALL_TARGETS}
RUNTIME DESTINATION bin
@ -92,16 +160,19 @@ install (TARGETS ${UPNPC_INSTALL_TARGETS}
ARCHIVE DESTINATION lib${LIB_SUFFIX}
)
install (FILES
miniupnpc.h
miniupnpc.h
miniwget.h
upnpcommands.h
igd_desc_parse.h
upnpreplyparse.h
upnperrors.h
upnpdev.h
miniupnpctypes.h
portlistingparse.h
declspec.h
miniupnpc_declspec.h
DESTINATION include/miniupnpc
)
set (CONFIGURED YES CACHE INTERNAL "")
# vim: ts=2:sw=2

View file

@ -1,6 +1,73 @@
$Id: Changelog.txt,v 1.198 2014/09/11 14:13:31 nanard Exp $
$Id: Changelog.txt,v 1.219 2015/10/26 17:05:06 nanard Exp $
miniUPnP client Changelog.
2015/10/26:
snprintf() overflow check. check overflow in simpleUPnPcommand2()
2015/10/25:
fix compilation with old macs
fix compilation with mingw32 (for Appveyor)
fix python module for python <= 2.3
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
increments API_VERSION to 14
2015/07/22:
Read USN from SSDP messages.
2015/07/15:
Check malloc/calloc
2015/06/16:
update getDevicesFromMiniSSDPD() to process longer minissdpd
responses
2015/05/22:
add searchalltypes param to upnpDiscoverDevices()
increments API_VERSION to 13
2015/04/30:
upnpc: output version on the terminal
2015/04/27:
_BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE
fix CMakeLists.txt COMPILE_DEFINITIONS
fix getDevicesFromMiniSSDPD() not setting scope_id
improve -r command of upnpc command line tool
2014/11/17:
search all :
upnpDiscoverDevices() / upnpDiscoverAll() functions
listdevices executable
increment API_VERSION to 12
validate igd_desc_parse
2014/11/13:
increment API_VERSION to 11
2014/11/05:
simplified function GetUPNPUrls()
2014/09/11:
use remoteHost arg of DeletePortMapping

View file

@ -1,5 +1,5 @@
MiniUPnPc
Copyright (c) 2005-2014, Thomas BERNARD
Copyright (c) 2005-2015, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without

View file

@ -1,9 +1,9 @@
# $Id: Makefile,v 1.110 2014/09/06 08:24:12 nanard Exp $
# $Id: Makefile,v 1.126 2015/08/28 12:14:18 nanard Exp $
# MiniUPnP Project
# http://miniupnp.free.fr/
# http://miniupnp.tuxfamily.org/
# https://github.com/miniupnp/miniupnp
# (c) 2005-2014 Thomas Bernard
# (c) 2005-2015 Thomas Bernard
# to install use :
# $ make DESTDIR=/tmp/dummylocation install
# or
@ -15,6 +15,7 @@ VERSION = $(shell cat VERSION)
ifeq ($(OS), Darwin)
JARSUFFIX=mac
LIBTOOL ?= $(shell which libtool)
endif
ifeq ($(OS), Linux)
JARSUFFIX=linux
@ -35,8 +36,15 @@ CFLAGS += -W -Wstrict-prototypes
CFLAGS += -fno-common
CFLAGS += -DMINIUPNPC_SET_SOCKET_TIMEOUT
CFLAGS += -DMINIUPNPC_GET_SRC_ADDR
CFLAGS += -D_BSD_SOURCE -D_POSIX_C_SOURCE=1
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,26 +54,32 @@ JAVA = java
#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 = 10
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
minixmlvalid.c testupnpreplyparse.c minissdpc.c \
upnperrors.c testigddescparse.c testminiwget.c \
connecthostport.c portlistingparse.c receivedata.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)
@ -78,7 +92,8 @@ OBJS = $(patsubst %.c,%.o,$(SRCS))
HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \
upnpreplyparse.h upnperrors.h miniupnpctypes.h \
portlistingparse.h \
declspec.h
upnpdev.h \
miniupnpc_declspec.h
# library names
LIBRARY = libminiupnpc.a
@ -96,9 +111,9 @@ else
endif
endif
EXECUTABLES = upnpc-static
EXECUTABLES = upnpc-static listdevices
EXECUTABLES_ADDTESTS = testminixml minixmlvalid testupnpreplyparse \
testigddescparse testminiwget
testigddescparse testminiwget testportlistingparse
TESTMINIXMLOBJS = minixml.o igd_desc_parse.o testminixml.o
@ -106,6 +121,8 @@ TESTMINIWGETOBJS = miniwget.o testminiwget.o connecthostport.o receivedata.o
TESTUPNPREPLYPARSE = testupnpreplyparse.o minixml.o upnpreplyparse.o
TESTPORTLISTINGPARSE = testportlistingparse.o minixml.o portlistingparse.o
TESTIGDDESCPARSE = testigddescparse.o igd_desc_parse.o minixml.o \
miniupnpc.o miniwget.o upnpcommands.o upnpreplyparse.o \
minisoap.o connecthostport.o receivedata.o \
@ -139,7 +156,8 @@ all: $(LIBRARY) $(EXECUTABLES)
test: check
check: validateminixml validateminiwget validateupnpreplyparse
check: validateminixml validateminiwget validateupnpreplyparse \
validateportlistingparse validateigddescparse
everything: all $(EXECUTABLES_ADDTESTS)
@ -172,13 +190,25 @@ validateupnpreplyparse: testupnpreplyparse testupnpreplyparse.sh
./testupnpreplyparse.sh
touch $@
validateportlistingparse: testportlistingparse
@echo "portlistingparse validation test"
./testportlistingparse
touch $@
validateigddescparse: testigddescparse
@echo "igd desc parse validation test"
./testigddescparse testdesc/new_LiveBox_desc.xml testdesc/new_LiveBox_desc.values
./testigddescparse testdesc/linksys_WAG200G_desc.xml testdesc/linksys_WAG200G_desc.values
touch $@
clean:
$(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h
$(RM) $(EXECUTABLES_ADDTESTS)
# clean python stuff
$(RM) pythonmodule pythonmodule3
$(RM) validateminixml validateminiwget validateupnpreplyparse
$(RM) minihttptestserver minihttptestserver.o
$(RM) validateigddescparse
$(RM) minihttptestserver
$(RM) -r build/ dist/
#python setup.py clean
# clean jnaerator stuff
@ -209,12 +239,19 @@ endif
$(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip
ifneq ($(OS), AmigaOS)
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRMAN)/man3
$(INSTALL) man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
$(INSTALL) -m 644 man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
ifeq ($(OS), Linux)
gzip $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
gzip -f $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
endif
endif
install-static: updateversion $(FILESTOINSTALL)
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC)
$(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC)
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB)
$(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB)
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN)
$(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip
cleaninstall:
$(RM) -r $(DESTDIR)$(INSTALLDIRINC)
@ -225,7 +262,11 @@ depend:
makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null
$(LIBRARY): $(LIBOBJS)
ifeq ($(OS), Darwin)
$(LIBTOOL) -static -o $@ $?
else
$(AR) crs $@ $?
endif
$(SHAREDLIBRARY): $(LIBOBJS)
ifeq ($(OS), Darwin)
@ -236,10 +277,12 @@ else
endif
upnpc-static: upnpc.o $(LIBRARY)
$(CC) $(LDFLAGS) -o $@ $^
$(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS)
upnpc-shared: upnpc.o $(SHAREDLIBRARY)
$(CC) $(LDFLAGS) -o $@ $^
$(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS)
listdevices: listdevices.o $(LIBRARY)
testminixml: $(TESTMINIXMLOBJS)
@ -251,6 +294,8 @@ testupnpreplyparse: $(TESTUPNPREPLYPARSE)
testigddescparse: $(TESTIGDDESCPARSE)
testportlistingparse: $(TESTPORTLISTINGPARSE)
miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh VERSION
$(SH) updateminiupnpcstrings.sh
@ -262,7 +307,7 @@ jnaerator-%.jar:
jar: $(SHAREDLIBRARY) $(JNAERATOR)
$(JAVA) -jar $(JNAERATOR) $(JNAERATORARGS) \
miniupnpc.h declspec.h upnpcommands.h upnpreplyparse.h \
miniupnpc.h miniupnpc_declspec.h upnpcommands.h upnpreplyparse.h \
igd_desc_parse.h miniwget.h upnperrors.h $(SHAREDLIBRARY) \
-package fr.free.miniupnp -o . -jar java/miniupnpc_$(JARSUFFIX).jar -v
@ -295,27 +340,40 @@ minihttptestserver: minihttptestserver.o
# DO NOT DELETE THIS LINE -- make depend depends on it.
igd_desc_parse.o: igd_desc_parse.h
miniupnpc.o: miniupnpc.h declspec.h igd_desc_parse.h minissdpc.h miniwget.h
miniupnpc.o: 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 declspec.h connecthostport.h
miniwget.o: receivedata.h
upnpc.o: miniwget.h declspec.h miniupnpc.h igd_desc_parse.h upnpcommands.h
upnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h upnperrors.h
upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h declspec.h
upnpcommands.o: miniupnpctypes.h miniupnpc.h igd_desc_parse.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: 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 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 declspec.h igd_desc_parse.h codelength.h
upnperrors.o: upnperrors.h declspec.h upnpcommands.h upnpreplyparse.h
upnperrors.o: portlistingparse.h miniupnpctypes.h miniupnpc.h
upnperrors.o: igd_desc_parse.h
testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.h declspec.h
testminiwget.o: miniwget.h declspec.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 upnpdev.h
testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.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: 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

View file

@ -1,10 +1,10 @@
# $Id: Makefile.mingw,v 1.18 2014/01/17 09:04:01 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
CC ?= gcc
#CFLAGS = -Wall -g -DDEBUG -D_WIN32_WINNT=0X501
CFLAGS = -Wall -Os -DNDEBUG -D_WIN32_WINNT=0X501
LDLIBS = -lws2_32 -liphlpapi
@ -12,8 +12,10 @@ LDLIBS = -lws2_32 -liphlpapi
# -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
@ -44,16 +46,16 @@ miniupnpc.dll: libminiupnpc.a $(OBJSDLL)
$(OBJSDLL) $(LDLIBS)
miniupnpc.lib: miniupnpc.dll
echo $@ generated with $<
# echo $@ generated with $<
dll/upnpc.o: upnpc.o
echo $@ generated with $<
# echo $@ generated with $<
.c.o:
$(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $<
$(CC) $(CFLAGS) -DMINIUPNP_EXPORTS -c -o dll/$@ $<
upnpc.o:
upnpc.o: upnpc.c
$(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $<
$(CC) $(CFLAGS) -c -o dll/$@ $<
@ -71,9 +73,10 @@ wingenminiupnpcstrings.o: wingenminiupnpcstrings.c
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: 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 @@ upnpreplyparse.o: upnpreplyparse.c upnpreplyparse.h minixml.h
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

View file

@ -3,16 +3,11 @@ Project web page: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
github: https://github.com/miniupnp/miniupnp
freecode: http://freecode.com/projects/miniupnp
Author: Thomas Bernard
Copyright (c) 2005-2012 Thomas Bernard
Copyright (c) 2005-2014 Thomas Bernard
This software is subject to the conditions detailed in the
LICENSE file provided within this distribution.
For the comfort of Win32 users, bsdqueue.h is included in the distribution.
Its licence is included in the header of the file.
bsdqueue.h is a copy of the sys/queue.h of an OpenBSD system.
* miniUPnP Client - miniUPnPc *
To compile, simply run 'gmake' (could be 'make' on your system).

View file

@ -1,7 +1,47 @@
$Id: apiversions.txt,v 1.3 2014/01/31 13:14:32 nanard Exp $
$Id: apiversions.txt,v 1.7 2015/07/23 20:40:08 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()
upnpDiscoverDevices()
getDevicesFromMiniSSDPD() :
connectToMiniSSDPD() / disconnectFromMiniSSDPD()
requestDevicesFromMiniSSDPD() / receiveDevicesFromMiniSSDPD()
updated macro :
#define MINIUPNPC_API_VERSION 14
API version 13
miniupnpc.h:
add searchalltype param to upnpDiscoverDevices() function
updated macro :
#define MINIUPNPC_API_VERSION 13
API version 12
miniupnpc.h :
add upnpDiscoverAll() / upnpDiscoverDevice() / upnpDiscoverDevices()
functions
updated macros :
#define MINIUPNPC_API_VERSION 12
API version 11
upnpreplyparse.h / portlistingparse.h :
removed usage of sys/queue.h / bsdqueue.h
miniupnpc.h:
updated macros :
#define MINIUPNPC_API_VERSION 11
====================== miniUPnPc version 1.9 ======================
API version 10

View file

@ -1,531 +0,0 @@
/* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues, and circular queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
#ifdef QUEUE_MACRO_DEBUG
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
#else
#define _Q_INVALIDATE(a)
#endif
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#ifdef SLIST_ENTRY
#undef SLIST_ENTRY
#endif
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = SLIST_FIRST(head); \
(var) != SLIST_END(head); \
(var) = SLIST_NEXT(var, field))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); \
((var) = *(varp)) != SLIST_END(head); \
(varp) = &SLIST_NEXT((var), field))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) { \
SLIST_FIRST(head) = SLIST_END(head); \
}
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (0)
#define SLIST_REMOVE_NEXT(head, elm, field) do { \
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (0)
#define SLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->slh_first; \
\
while (curelm->field.sle_next != (elm)) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
_Q_INVALIDATE((elm)->field.sle_next); \
} \
} while (0)
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for((var) = LIST_FIRST(head); \
(var)!= LIST_END(head); \
(var) = LIST_NEXT(var, field))
/*
* List functions.
*/
#define LIST_INIT(head) do { \
LIST_FIRST(head) = LIST_END(head); \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_END(head) NULL
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define SIMPLEQ_FOREACH(var, head, field) \
for((var) = SIMPLEQ_FIRST(head); \
(var) != SIMPLEQ_END(head); \
(var) = SIMPLEQ_NEXT(var, field))
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (0)
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* tail queue access methods
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) NULL
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV(var, headname, field))
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
(elm2)->field.tqe_next->field.tqe_prev = \
&(elm2)->field.tqe_next; \
else \
(head)->tqh_last = &(elm2)->field.tqe_next; \
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
*(elm2)->field.tqe_prev = (elm2); \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
/*
* Circular queue definitions.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_HEAD_INITIALIZER(head) \
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue access methods
*/
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
#define CIRCLEQ_END(head) ((void *)(head))
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
#define CIRCLEQ_EMPTY(head) \
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
#define CIRCLEQ_FOREACH(var, head, field) \
for((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_NEXT(var, field))
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
for((var) = CIRCLEQ_LAST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_PREV(var, field))
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) do { \
(head)->cqh_first = CIRCLEQ_END(head); \
(head)->cqh_last = CIRCLEQ_END(head); \
} while (0)
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
(elm)->field.cqe_prev = (listelm); \
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
(listelm)->field.cqe_next = (elm); \
} while (0)
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm); \
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
(listelm)->field.cqe_prev = (elm); \
} while (0)
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
(elm)->field.cqe_next = (head)->cqh_first; \
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
if ((head)->cqh_last == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(head)->cqh_first->field.cqe_prev = (elm); \
(head)->cqh_first = (elm); \
} while (0)
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.cqe_next = CIRCLEQ_END(head); \
(elm)->field.cqe_prev = (head)->cqh_last; \
if ((head)->cqh_first == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(head)->cqh_last->field.cqe_next = (elm); \
(head)->cqh_last = (elm); \
} while (0)
#define CIRCLEQ_REMOVE(head, elm, field) do { \
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm)->field.cqe_prev; \
else \
(elm)->field.cqe_next->field.cqe_prev = \
(elm)->field.cqe_prev; \
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm)->field.cqe_next; \
else \
(elm)->field.cqe_prev->field.cqe_next = \
(elm)->field.cqe_next; \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
CIRCLEQ_END(head)) \
(head).cqh_last = (elm2); \
else \
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
CIRCLEQ_END(head)) \
(head).cqh_first = (elm2); \
else \
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#endif /* !_SYS_QUEUE_H_ */

View file

@ -1,7 +1,7 @@
/* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas BERNARD
* copyright (c) 2005-2011 Thomas Bernard
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#ifndef CODELENGTH_H_INCLUDED
@ -10,10 +10,30 @@
/* Encode length by using 7bit per Byte :
* Most significant bit of each byte specifies that the
* following byte is part of the code */
/* n : unsigned
* p : unsigned char *
*/
#define DECODELENGTH(n, p) n = 0; \
do { n = (n << 7) | (*p & 0x7f); } \
while((*(p++)&0x80) && (n<(1<<25)));
/* n : unsigned
* READ : function/macro to read one byte (unsigned char)
*/
#define DECODELENGTH_READ(n, READ) \
n = 0; \
do { \
unsigned char c; \
READ(c); \
n = (n << 7) | (c & 0x07f); \
if(!(c&0x80)) break; \
} while(n<(1<<25));
/* n : unsigned
* p : unsigned char *
* p_limit : unsigned char *
*/
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
n = 0; \
do { \
@ -21,11 +41,14 @@
n = (n << 7) | (*(p) & 0x7f); \
} while((*((p)++)&0x80) && (n<(1<<25)));
/* n : unsigned
* p : unsigned char *
*/
#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
if(n>=16384) *(p++) = (n >> 14) | 0x80; \
if(n>=128) *(p++) = (n >> 7) | 0x80; \
*(p++) = n & 0x7f;
#endif
#endif /* CODELENGTH_H_INCLUDED */

View file

@ -1,7 +1,7 @@
/* $Id: connecthostport.c,v 1.12 2014/02/05 17:26:46 nanard Exp $ */
/* $Id: connecthostport.c,v 1.15 2015/10/09 16:26:19 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,8 +37,8 @@
* 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 */
#endif /* #else _WIN32 */
@ -112,7 +116,7 @@ int connecthostport(const char * host, unsigned short port,
/* 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))
while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
{
socklen_t len;
fd_set wset;

View file

@ -1,21 +0,0 @@
#ifndef DECLSPEC_H_INCLUDED
#define 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

View file

@ -1,8 +1,8 @@
/* $Id: igd_desc_parse.c,v 1.15 2014/07/01 13:01:17 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,11 +15,9 @@
void IGDstartelt(void * d, const char * name, int l)
{
struct IGDdatas * datas = (struct IGDdatas *)d;
if (l >= MINIUPNPC_URL_MAXSIZE) {
printf("Attempt to exploit miniupnpc buffer overflow\n");
l = MINIUPNPC_URL_MAXSIZE - 1;
}
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) ) {
@ -92,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);
@ -120,5 +119,5 @@ void printIGD(struct IGDdatas * d)
printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl);
printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl);
}
#endif /* DEBUG */

View file

@ -1,8 +1,8 @@
/* $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.
* */
@ -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 */

View file

@ -29,7 +29,7 @@ public class JavaBridgeTest {
return;
}
devlist = miniupnpc.upnpDiscover(UPNP_DELAY, (String) null, (String) null, 0, 0, IntBuffer.allocate(1));
devlist = miniupnpc.upnpDiscover(UPNP_DELAY, (String) null, (String) null, 0, 0, (byte)2, IntBuffer.allocate(1));
if (devlist != null) {
System.out.println("List of UPNP devices found on the network :");
for (UPNPDev device = devlist; device != null; device = device.pNext) {

View file

@ -25,13 +25,16 @@ through the miniupnpc API. The name of the C functions are matching
the UPnP methods names. ie: GetGenericPortMappingEntry is
UPNP_GetGenericPortMappingEntry.
.SH "API FUNCTIONS"
.IP "struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error);"
.IP "struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int localport, int ipv6, int * error);"
execute the discovery process.
delay (in millisecond) is the maximum time for waiting any device response.
If available, device list will be obtained from MiniSSDPd.
Default path for minissdpd socket will be used if minissdpdsock argument is NULL.
If multicastif is not NULL, it will be used instead of the default multicast interface for sending SSDP discover packets.
If sameport is not null, SSDP packets will be sent from the source port 1900 (same as destination port) otherwise system assign a source port.
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.
If ipv6 is not 0, IPv6 is used instead of IPv4 for the discovery process.
.IP "void freeUPNPDevlist(struct UPNPDev * devlist);"
free the list returned by upnpDiscover().

View file

@ -1,7 +1,7 @@
/* $Id: minihttptestserver.c,v 1.16 2014/04/01 15:08:28 nanard Exp $ */
/* $Id: minihttptestserver.c,v 1.19 2015/11/17 09:07:17 nanard Exp $ */
/* Project : miniUPnP
* Author : Thomas Bernard
* Copyright (c) 2011-2014 Thomas Bernard
* Copyright (c) 2011-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
@ -18,6 +18,10 @@
#include <time.h>
#include <errno.h>
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001
#endif
#define CRAP_LENGTH (2048)
volatile sig_atomic_t quit = 0;
@ -104,6 +108,8 @@ char * build_chunked_response(int content_length, int * response_len)
/* allocate to have some margin */
buffer_length = 256 + content_length + (content_length >> 4);
response_buffer = malloc(buffer_length);
if(response_buffer == NULL)
return NULL;
*response_len = snprintf(response_buffer, buffer_length,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
@ -112,6 +118,10 @@ char * build_chunked_response(int content_length, int * response_len)
/* build the content */
content_buffer = malloc(content_length);
if(content_buffer == NULL) {
free(response_buffer);
return NULL;
}
build_content(content_buffer, content_length);
/* chunk it */
@ -414,7 +424,14 @@ void handle_http_connection(int c)
"Content-Length: %d\r\n"
"\r\n", content_length);
response_len = content_length+n+CRAP_LENGTH;
response_buffer = realloc(response_buffer, response_len);
p = realloc(response_buffer, response_len);
if(p == NULL) {
/* error 500 */
free(response_buffer);
response_buffer = NULL;
break;
}
response_buffer = p;
build_content(response_buffer + n, content_length);
build_crap(response_buffer + n + content_length, CRAP_LENGTH);
break;
@ -445,7 +462,14 @@ void handle_http_connection(int c)
"Content-Type: text/plain\r\n"
"\r\n");
response_len = content_length+n;
response_buffer = realloc(response_buffer, response_len);
p = realloc(response_buffer, response_len);
if(p == NULL) {
/* Error 500 */
free(response_buffer);
response_buffer = NULL;
break;
}
response_buffer = p;
build_content(response_buffer + n, response_len - n);
}
@ -564,12 +588,16 @@ int main(int argc, char * * argv) {
if(f) {
char * buffer;
buffer = malloc(16*1024);
build_content(buffer, 16*1024);
i = fwrite(buffer, 1, 16*1024, f);
if(i != 16*1024) {
fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024);
if(buffer == NULL) {
fprintf(stderr, "memory allocation error\n");
} else {
build_content(buffer, 16*1024);
i = fwrite(buffer, 1, 16*1024, f);
if(i != 16*1024) {
fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024);
}
free(buffer);
}
free(buffer);
fclose(f);
} else {
fprintf(stderr, "error opening file %s for writing\n", expected_file_name);

View file

@ -1,7 +1,7 @@
/* $Id: minisoap.c,v 1.22 2012/01/21 13:30:31 nanard Exp $ */
/* $Id: minisoap.c,v 1.23 2014/11/04 22:31:55 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
*
@ -43,10 +43,10 @@ httpWrite(int fd, const char * body, int bodysize,
/* Note : my old linksys router only took into account
* soap request that are sent into only one packet */
char * p;
/* TODO: AVOID MALLOC */
/* TODO: AVOID MALLOC, we could use writev() for that */
p = malloc(headerssize+bodysize);
if(!p)
return 0;
return -1;
memcpy(p, headers, headerssize);
memcpy(p+headerssize, body, bodysize);
/*n = write(fd, p, headerssize+bodysize);*/
@ -96,7 +96,7 @@ int soapPostSubmit(int fd,
headerssize = snprintf(headerbuf, sizeof(headerbuf),
"POST %s HTTP/%s\r\n"
"Host: %s%s\r\n"
"User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
"User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
"Content-Length: %d\r\n"
"Content-Type: text/xml\r\n"
"SOAPAction: \"%s\"\r\n"
@ -105,6 +105,8 @@ int soapPostSubmit(int fd,
"Pragma: no-cache\r\n"
"\r\n",
url, httpversion, host, portstr, bodysize, action);
if ((unsigned int)headerssize >= sizeof(headerbuf))
return -1;
#ifdef DEBUG
/*printf("SOAP request : headersize=%d bodysize=%d\n",
headerssize, bodysize);

View file

@ -1,67 +1,194 @@
/* $Id: minissdpc.c,v 1.15 2012/01/21 13:30:31 nanard Exp $ */
/* $Id: minissdpc.c,v 1.28 2015/09/18 13:05:39 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2012 Thomas Bernard
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
/*#include <syslog.h>*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#if defined(_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)
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error)
{
struct UPNPDev * tmp;
struct UPNPDev * devlist = NULL;
unsigned char buffer[4*1024]; /* is that enough ? */
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;
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
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;
}
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
/* setting a 3 seconds timeout */
timeout.tv_sec = 3;
timeout.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
{
perror("setsockopt");
}
timeout.tv_sec = 3;
timeout.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
{
perror("setsockopt");
}
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
if(!socketpath)
socketpath = "/var/run/minissdpd.sock";
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path));
/* TODO : check if we need to handle the EINTR */
@ -69,17 +196,45 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
{
/*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/
close(s);
return NULL;
return MINISSDPC_SOCKET_ERROR;
}
return s;
}
int
disconnectFromMiniSSDPD(int s)
{
if (close(s) < 0)
return MINISSDPC_SOCKET_ERROR;
return MINISSDPC_SUCCESS;
}
int
requestDevicesFromMiniSSDPD(int s, const char * devtype)
{
unsigned char buffer[256];
unsigned char * p;
unsigned int stsize, l;
stsize = strlen(devtype);
buffer[0] = 1; /* request type 1 : request devices/services by type */
if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8))
{
buffer[0] = 3; /* request type 3 : everything */
}
else
{
buffer[0] = 1; /* request type 1 : request devices/services by type */
}
p = buffer + 1;
l = stsize; CODELENGTH(l, p);
if(p + stsize > buffer + sizeof(buffer))
{
/* devtype is too long ! */
close(s);
return NULL;
#ifdef DEBUG
fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n",
stsize, (unsigned)sizeof(buffer));
#endif /* DEBUG */
return MINISSDPC_INVALID_INPUT;
}
memcpy(p, devtype, stsize);
p += stsize;
@ -87,47 +242,608 @@ 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))
break;
}
close(s);
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;
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);
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");
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;
}

View file

@ -1,15 +1,58 @@
/* $Id: minissdpc.h,v 1.1 2007/08/31 15:15:33 nanard Exp $ */
/* $Id: minissdpc.h,v 1.6 2015/09/18 12:45:16 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author: Thomas Bernard
* Copyright (c) 2005-2007 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINISSDPC_H_INCLUDED
#define MINISSDPC_H_INCLUDED
struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath);
#include "miniupnpc_declspec.h"
#include "upnpdev.h"
/* error codes : */
#define MINISSDPC_SUCCESS (0)
#define MINISSDPC_UNKNOWN_ERROR (-1)
#define MINISSDPC_SOCKET_ERROR (-101)
#define MINISSDPC_MEMORY_ERROR (-102)
#define MINISSDPC_INVALID_INPUT (-103)
#define MINISSDPC_INVALID_SERVER_REPLY (-104)
#ifdef __cplusplus
extern "C" {
#endif
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
MINIUPNP_LIBSPEC struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error);
MINIUPNP_LIBSPEC int
connectToMiniSSDPD(const char * socketpath);
MINIUPNP_LIBSPEC int
disconnectFromMiniSSDPD(int fd);
MINIUPNP_LIBSPEC int
requestDevicesFromMiniSSDPD(int fd, const char * devtype);
MINIUPNP_LIBSPEC struct UPNPDev *
receiveDevicesFromMiniSSDPD(int fd, int * error);
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
MINIUPNP_LIBSPEC struct UPNPDev *
ssdpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
int localport,
int ipv6, unsigned char ttl,
int * error,
int searchalltypes);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,26 +1,11 @@
/* $Id: miniupnpc.c,v 1.116 2014/01/31 14:09:03 nanard Exp $ */
/* $Id: miniupnpc.c,v 1.135 2015/07/23 20:40:08 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2014 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,28 +48,11 @@
#include <errno.h>
#define closesocket close
#endif /* #else _WIN32 */
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
#include <sys/time.h>
#endif
#if defined(__amigaos__) || defined(__amigaos4__)
/* Amiga OS specific stuff */
#define TIMEVAL struct timeval
#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"
@ -92,13 +60,9 @@ struct ip_mreqn
#include "minixml.h"
#include "upnpcommands.h"
#include "connecthostport.h"
#include "receivedata.h"
#ifdef _WIN32
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
#else
#define PRINT_SOCKET_ERROR(x) perror(x)
#endif
/* compare the begining of a string with a constant string */
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
@ -140,73 +104,93 @@ 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;
*bufsize = 0;
snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
if(args==NULL)
{
/*soapbodylen = */snprintf(soapbody, sizeof(soapbody),
"<?xml version=\"1.0\"?>\r\n"
"<" SOAPPREFIX ":Envelope "
soapbodylen = snprintf(soapbody, sizeof(soapbody),
"<?xml version=\"1.0\"?>\r\n"
"<" SOAPPREFIX ":Envelope "
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
"<" SOAPPREFIX ":Body>"
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
"</" SERVICEPREFIX ":%s>"
"</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
"\r\n", action, service, action);
"\r\n", action, service, action);
if ((unsigned int)soapbodylen >= sizeof(soapbody))
return NULL;
}
else
{
char * p;
const char * pe, * pv;
int soapbodylen;
const char * const pend = soapbody + sizeof(soapbody);
soapbodylen = snprintf(soapbody, sizeof(soapbody),
"<?xml version=\"1.0\"?>\r\n"
"<" SOAPPREFIX ":Envelope "
"<" SOAPPREFIX ":Envelope "
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
"<" SOAPPREFIX ":Body>"
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">",
action, service);
if ((unsigned int)soapbodylen >= sizeof(soapbody))
return NULL;
p = soapbody + soapbodylen;
while(args->elt)
{
/* check that we are never overflowing the string... */
if(soapbody + sizeof(soapbody) <= p + 100)
{
/* we keep a margin of at least 100 bytes */
if(p >= pend) /* check for space to write next byte */
return NULL;
}
*(p++) = '<';
pe = args->elt;
while(*pe)
while(p < pend && *pe)
*(p++) = *(pe++);
if(p >= pend) /* check for space to write next byte */
return NULL;
*(p++) = '>';
if((pv = args->val))
{
while(*pv)
while(p < pend && *pv)
*(p++) = *(pv++);
}
if((p+2) > pend) /* check for space to write next 2 bytes */
return NULL;
*(p++) = '<';
*(p++) = '/';
pe = args->elt;
while(*pe)
while(p < pend && *pe)
*(p++) = *(pe++);
if(p >= pend) /* check for space to write next byte */
return NULL;
*(p++) = '>';
args++;
}
if((p+4) > pend) /* check for space to write next 4 bytes */
return NULL;
*(p++) = '<';
*(p++) = '/';
*(p++) = SERVICEPREFIX2;
*(p++) = ':';
pe = action;
while(*pe)
while(p < pend && *pe)
*(p++) = *(pe++);
strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
soapbody + sizeof(soapbody) - p);
pend - p);
if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */
return NULL;
}
if(!parseURL(url, hostname, &port, &path, NULL)) return NULL;
if(s < 0) {
@ -263,98 +247,92 @@ char * simpleUPnPcommand(int s, const char * url, const char * service,
return buf;
}
/* parseMSEARCHReply()
* the last 4 arguments are filled during the parsing :
* - location/locationsize : "location:" field of the SSDP reply packet
* - st/stsize : "st:" field of the SSDP reply packet.
* The strings are NOT null terminated */
static void
parseMSEARCHReply(const char * reply, int size,
const char * * location, int * locationsize,
const char * * st, int * stsize)
{
int a, b, i;
i = 0;
a = i; /* start of the line */
b = 0; /* end of the "header" (position of the colon) */
while(i<size)
{
switch(reply[i])
{
case ':':
if(b==0)
{
b = i; /* end of the "header" */
/*for(j=a; j<b; j++)
{
putchar(reply[j]);
}
*/
}
break;
case '\x0a':
case '\x0d':
if(b!=0)
{
/*for(j=b+1; j<i; j++)
{
putchar(reply[j]);
}
putchar('\n');*/
/* skip the colon and white spaces */
do { b++; } while(reply[b]==' ');
if(0==strncasecmp(reply+a, "location", 8))
{
*location = reply+b;
*locationsize = i-b;
}
else if(0==strncasecmp(reply+a, "st", 2))
{
*st = reply+b;
*stsize = i-b;
}
b = 0;
}
a = i+1;
break;
default:
break;
}
i++;
}
}
/* port upnp discover : SSDP protocol */
#define PORT 1900
#define XSTR(s) STR(s)
#define STR(s) #s
#define UPNP_MCAST_ADDR "239.255.255.250"
/* for IPv6 */
#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
/* upnpDiscover() :
/* upnpDiscoverDevices() :
* return a chained list of all devices found or NULL if
* no devices was found.
* It is up to the caller to free the chained list
* delay is in millisecond (poll) */
* 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 *
upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
int ipv6,
int * error)
upnpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6, unsigned char ttl,
int * error,
int searchalltypes)
{
struct UPNPDev * tmp;
struct UPNPDev * devlist = 0;
unsigned int scope_id = 0;
int opt = 1;
static const char MSearchMsgFmt[] =
"M-SEARCH * HTTP/1.1\r\n"
"HOST: %s:" XSTR(PORT) "\r\n"
"ST: %s\r\n"
"MAN: \"ssdp:discover\"\r\n"
"MX: %u\r\n"
"\r\n";
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
int deviceIndex;
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
if(error)
*error = UPNPDISCOVER_UNKNOWN_ERROR;
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
/* first try to get infos from minissdpd ! */
if(!minissdpdsock)
minissdpdsock = "/var/run/minissdpd.sock";
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
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("returned by MiniSSDPD: %s\t%s\n",
tmp->pNext->st, tmp->pNext->descURL);
#endif /* DEBUG */
if(!strstr(tmp->st, "rootdevice"))
only_rootdevice = 0;
}
tmp->pNext = devlist;
devlist = minissdpd_devlist;
if(!searchalltypes && !only_rootdevice)
break;
}
}
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__) */
/* direct discovery if minissdpd responses are not sufficient */
{
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;
}
}
return 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)
{
static const char * const deviceList[] = {
#if 0
"urn:schemas-upnp-org:device:InternetGatewayDevice:2",
@ -364,395 +342,117 @@ upnpDiscover(int delay, const char * multicastif,
"urn:schemas-upnp-org:service:WANIPConnection:1",
"urn:schemas-upnp-org:service:WANPPPConnection:1",
"upnp:rootdevice",
/*"ssdp:all",*/
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(error)
*error = UPNPDISCOVER_UNKNOWN_ERROR;
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
/* first try to get infos from minissdpd ! */
if(!minissdpdsock)
minissdpdsock = "/var/run/minissdpd.sock";
while(!devlist && deviceList[deviceIndex]) {
devlist = getDevicesFromMiniSSDPD(deviceList[deviceIndex],
minissdpdsock);
/* We return what we have found if it was not only a rootdevice */
if(devlist && !strstr(deviceList[deviceIndex], "rootdevice")) {
if(error)
*error = UPNPDISCOVER_SUCCESS;
return devlist;
}
deviceIndex++;
}
deviceIndex = 0;
#endif
/* fallback to direct discovery */
#ifdef _WIN32
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
#else
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
#endif
if(sudp < 0)
{
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
PRINT_SOCKET_ERROR("socket");
return NULL;
}
/* reception */
memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
if(ipv6) {
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
p->sin6_family = AF_INET6;
if(sameport)
p->sin6_port = htons(PORT);
p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
} else {
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
p->sin_family = AF_INET;
if(sameport)
p->sin_port = htons(PORT);
p->sin_addr.s_addr = INADDR_ANY;
}
#ifdef _WIN32
/* This code could help us to use the right Network interface for
* SSDP multicast traffic */
/* Get IP associated with the index given in the ip_forward struct
* in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
if(!ipv6
&& (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
DWORD dwRetVal = 0;
PMIB_IPADDRTABLE pIPAddrTable;
DWORD dwSize = 0;
#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 );
#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
#ifdef _WIN32
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
#else
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
#endif
{
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
PRINT_SOCKET_ERROR("setsockopt");
return NULL;
}
if(multicastif)
{
if(ipv6) {
#if !defined(_WIN32)
/* according to MSDN, if_nametoindex() is supported since
* MS Windows Vista and MS Windows Server 2008.
* http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(&ifindex)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#else
#ifdef DEBUG
printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
#endif
#endif
} else {
struct in_addr mc_if;
mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
if(mc_if.s_addr != INADDR_NONE)
{
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
} else {
#ifdef HAS_IP_MREQN
/* was not an ip address, try with an interface name */
struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
memset(&reqn, 0, sizeof(struct ip_mreqn));
reqn.imr_ifindex = if_nametoindex(multicastif);
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#else
#ifdef DEBUG
printf("Setting of multicast interface not supported with interface name.\n");
#endif
#endif
}
}
}
/* 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(n = 0; deviceList[deviceIndex]; deviceIndex++)
{
if(n == 0)
{
/* sending the SSDP M-SEARCH packet */
n = snprintf(bufr, sizeof(bufr),
MSearchMsgFmt,
ipv6 ?
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
: UPNP_MCAST_ADDR,
deviceList[deviceIndex], mx);
#ifdef DEBUG
printf("Sending %s", bufr);
#endif
#ifdef NO_GETADDRINFO
/* the following code is not using getaddrinfo */
/* emission */
memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
if(ipv6) {
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
p->sin6_family = AF_INET6;
p->sin6_port = htons(PORT);
inet_pton(AF_INET6,
linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
&(p->sin6_addr));
} else {
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
p->sin_family = AF_INET;
p->sin_port = htons(PORT);
p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
}
n = sendto(sudp, bufr, n, 0,
&sockudp_w,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
if (n < 0) {
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
PRINT_SOCKET_ERROR("sendto");
break;
}
#else /* #ifdef NO_GETADDRINFO */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */
hints.ai_socktype = SOCK_DGRAM;
/*hints.ai_flags = */
if ((rv = getaddrinfo(ipv6
? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
: UPNP_MCAST_ADDR,
XSTR(PORT), &hints, &servinfo)) != 0) {
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
#ifdef _WIN32
fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
#else
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
#endif
break;
}
for(p = servinfo; p; p = p->ai_next) {
n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen);
if (n < 0) {
#ifdef DEBUG
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
}
#endif
PRINT_SOCKET_ERROR("sendto");
continue;
}
}
freeaddrinfo(servinfo);
if(n < 0) {
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
break;
}
#endif /* #ifdef NO_GETADDRINFO */
}
/* Waiting for SSDP REPLY packet to M-SEARCH */
n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
if (n < 0) {
/* error */
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
break;
} else if (n == 0) {
/* no data or Time Out */
if (devlist) {
/* no more device type to look for... */
if(error)
*error = UPNPDISCOVER_SUCCESS;
break;
}
if(ipv6) {
if(linklocal) {
linklocal = 0;
--deviceIndex;
} else {
linklocal = 1;
}
}
} else {
const char * descURL=NULL;
int urlsize=0;
const char * st=NULL;
int stsize=0;
/*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
if(st&&descURL)
{
#ifdef DEBUG
printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
stsize, st, urlsize, descURL);
#endif
for(tmp=devlist; tmp; tmp = tmp->pNext) {
if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
tmp->descURL[urlsize] == '\0' &&
memcmp(tmp->st, st, stsize) == 0 &&
tmp->st[stsize] == '\0')
break;
}
/* at the exit of the loop above, tmp is null if
* no duplicate device was found */
if(tmp)
continue;
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
if(!tmp) {
/* memory allocation error */
if(error)
*error = UPNPDISCOVER_MEMORY_ERROR;
break;
}
tmp->pNext = devlist;
tmp->descURL = tmp->buffer;
tmp->st = tmp->buffer + 1 + urlsize;
memcpy(tmp->buffer, descURL, urlsize);
tmp->buffer[urlsize] = '\0';
memcpy(tmp->buffer + urlsize + 1, st, stsize);
tmp->buffer[urlsize+1+stsize] = '\0';
tmp->scope_id = scope_id;
devlist = tmp;
}
}
}
closesocket(sudp);
return devlist;
return upnpDiscoverDevices(deviceList,
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)
/* 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)
{
struct UPNPDev * next;
while(devlist)
{
next = devlist->pNext;
free(devlist);
devlist = next;
}
static const char * const deviceList[] = {
/*"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)
/* 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)
{
if( (src[0] == 'h')
&&(src[1] == 't')
&&(src[2] == 't')
&&(src[3] == 'p')
&&(src[4] == ':')
&&(src[5] == '/')
&&(src[6] == '/'))
{
strncpy(dst, src, n);
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...
@ -761,89 +461,24 @@ MINIUPNP_LIBSPEC void
GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
const char * descURL, unsigned int scope_id)
{
char * p;
int n1, n2, n3, n4;
#ifdef IF_NAMESIZE
char ifname[IF_NAMESIZE];
#else
char scope_str[8];
#endif
n1 = strlen(data->urlbase);
if(n1==0)
n1 = strlen(descURL);
if(scope_id != 0) {
#ifdef IF_NAMESIZE
if(if_indextoname(scope_id, ifname)) {
n1 += 3 + strlen(ifname); /* 3 == strlen(%25) */
}
#else
/* under windows, scope is numerical */
snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
#endif
}
n1 += 2; /* 1 byte more for Null terminator, 1 byte for '/' if needed */
n2 = n1; n3 = n1; n4 = n1;
n1 += strlen(data->first.scpdurl);
n2 += strlen(data->first.controlurl);
n3 += strlen(data->CIF.controlurl);
n4 += strlen(data->IPv6FC.controlurl);
/* allocate memory to store URLs */
urls->ipcondescURL = (char *)malloc(n1);
urls->controlURL = (char *)malloc(n2);
urls->controlURL_CIF = (char *)malloc(n3);
urls->controlURL_6FC = (char *)malloc(n4);
/* strdup descURL */
urls->rootdescURL = strdup(descURL);
/* get description of WANIPConnection */
if(data->urlbase[0] != '\0')
strncpy(urls->ipcondescURL, data->urlbase, n1);
else
strncpy(urls->ipcondescURL, descURL, n1);
p = strchr(urls->ipcondescURL+7, '/');
if(p) p[0] = '\0';
if(scope_id != 0) {
if(0 == memcmp(urls->ipcondescURL, "http://[fe80:", 13)) {
/* this is a linklocal IPv6 address */
p = strchr(urls->ipcondescURL, ']');
if(p) {
/* insert %25<scope> into URL */
#ifdef IF_NAMESIZE
memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
memcpy(p, "%25", 3);
memcpy(p + 3, ifname, strlen(ifname));
#else
memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
memcpy(p, "%25", 3);
memcpy(p + 3, scope_str, strlen(scope_str));
#endif
}
}
}
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);
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
}
@ -873,9 +508,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;
}
@ -911,6 +546,7 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
int n_igd = 0;
char extIpAddr[16];
char myLanAddr[40];
if(!devlist)
{
#ifdef DEBUG
@ -933,7 +569,7 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
/* we should choose an internet gateway device.
* with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size),
lanaddr, lanaddrlen,
myLanAddr, sizeof(myLanAddr),
dev->scope_id);
#ifdef DEBUG
if(!desc[i].xml)
@ -946,11 +582,13 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
memset(data, 0, sizeof(struct IGDdatas));
memset(urls, 0, sizeof(struct UPNPUrls));
parserootdesc(desc[i].xml, desc[i].size, data);
if(0==strcmp(data->CIF.servicetype,
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"))
if(COMPARE(data->CIF.servicetype,
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:"))
{
desc[i].is_igd = 1;
n_igd++;
if(lanaddr)
strncpy(lanaddr, myLanAddr, lanaddrlen);
}
}
}

View file

@ -1,15 +1,16 @@
/* $Id: miniupnpc.h,v 1.34 2014/01/31 13:18:25 nanard Exp $ */
/* $Id: miniupnpc.h,v 1.44 2015/07/23 20:40:10 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/
* Author: Thomas Bernard
* Copyright (c) 2005-2012 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 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)
@ -19,7 +20,13 @@
/* versions : */
#define MINIUPNPC_VERSION "1.9"
#define MINIUPNPC_API_VERSION 10
#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,14 +40,6 @@ simpleUPnPcommand(int, const char *, const char *,
const char *, struct UPNParg *,
int *);
struct UPNPDev {
struct UPNPDev * pNext;
char * descURL;
char * st;
unsigned int scope_id;
char buffer[2];
};
/* upnpDiscover()
* discover UPnP devices on the network.
* The discovered devices are returned as a chained list.
@ -52,16 +51,38 @@ 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. */
* 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() */
MINIUPNP_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
@ -102,6 +123,7 @@ 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 */

View file

@ -42,6 +42,7 @@ typedef struct {
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,21 +55,62 @@ static PyMemberDef UPnP_members[] = {
{"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"
},
{"minissdpdsocket", T_STRING, offsetof(UPnPObject, multicastif),
{"minissdpdsocket", T_STRING, offsetof(UPnPObject, minissdpdsocket),
0, "path of the MiniSSDPd unix socket"
},
{NULL}
};
static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds)
{
char* multicastif = NULL;
char* minissdpdsocket = NULL;
static char *kwlist[] = {
"multicastif", "minissdpdsocket", "discoverdelay",
"localport", NULL
};
if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist,
&multicastif,
&minissdpdsocket,
&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)
self->minissdpdsocket = strdup(minissdpdsocket);
return 0;
}
static void
UPnPObject_dealloc(UPnPObject *self)
{
freeUPNPDevlist(self->devlist);
FreeUPNPUrls(&self->urls);
free(self->multicastif);
free(self->minissdpdsocket);
Py_TYPE(self)->tp_free((PyObject*)self);
}
@ -85,10 +127,11 @@ UPnP_discover(UPnPObject *self)
}
Py_BEGIN_ALLOW_THREADS
self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
0/* multicast if*/,
0/*minissdpd socket*/,
0/*sameport flag*/,
self->multicastif,
self->minissdpdsocket,
(int)self->localport,
0/*ip v6*/,
2/* TTL */,
0/*error */);
Py_END_ALLOW_THREADS
/* Py_RETURN_NONE ??? */
@ -126,7 +169,11 @@ Py_BEGIN_ALLOW_THREADS
i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
self->data.CIF.servicetype);
Py_END_ALLOW_THREADS
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("I", i);
#else
return Py_BuildValue("i", (int)i);
#endif
}
static PyObject *
@ -137,7 +184,11 @@ Py_BEGIN_ALLOW_THREADS
i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
self->data.CIF.servicetype);
Py_END_ALLOW_THREADS
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("I", i);
#else
return Py_BuildValue("i", (int)i);
#endif
}
static PyObject *
@ -148,7 +199,11 @@ Py_BEGIN_ALLOW_THREADS
i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
self->data.CIF.servicetype);
Py_END_ALLOW_THREADS
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("I", i);
#else
return Py_BuildValue("i", (int)i);
#endif
}
static PyObject *
@ -159,7 +214,11 @@ Py_BEGIN_ALLOW_THREADS
i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
self->data.CIF.servicetype);
Py_END_ALLOW_THREADS
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("I", i);
#else
return Py_BuildValue("i", (int)i);
#endif
}
static PyObject *
@ -176,7 +235,11 @@ Py_BEGIN_ALLOW_THREADS
status, &uptime, lastconnerror);
Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS) {
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);
#else
return Py_BuildValue("(s,i,s)", status, (int)uptime, lastconnerror);
#endif
} else {
/* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, strupnperror(r));
@ -369,7 +432,11 @@ Py_BEGIN_ALLOW_THREADS
&n);
Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS) {
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("I", n);
#else
return Py_BuildValue("i", (int)n);
#endif
} else {
/* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, strupnperror(r));
@ -454,9 +521,15 @@ Py_END_ALLOW_THREADS
ePort = (unsigned short)atoi(extPort);
iPort = (unsigned short)atoi(intPort);
dur = (unsigned int)strtoul(duration, 0, 0);
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("(H,s,(s,H),s,s,s,I)",
ePort, protocol, intClient, iPort,
desc, enabled, rHost, dur);
#else
return Py_BuildValue("(i,s,(s,i),s,s,s,i)",
(int)ePort, protocol, intClient, (int)iPort,
desc, enabled, rHost, (int)dur);
#endif
}
else
{
@ -554,7 +627,7 @@ static PyTypeObject UPnPType = {
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0,/*(initproc)UPnP_init,*/ /* tp_init */
(initproc)UPnP_init, /* tp_init */
0, /* tp_alloc */
#ifndef _WIN32
PyType_GenericNew,/*UPnP_new,*/ /* tp_new */

View file

@ -4,4 +4,12 @@
#define OS_STRING "${CMAKE_SYSTEM_NAME}"
#define MINIUPNPC_VERSION_STRING "${MINIUPNPC_VERSION}"
#if 0
/* according to "UPnP Device Architecture 1.0" */
#define UPNP_VERSION_STRING "UPnP/1.0"
#else
/* according to "UPnP Device Architecture 1.1" */
#define UPNP_VERSION_STRING "UPnP/1.1"
#endif
#endif

View file

@ -1,8 +1,8 @@
/* $Id: miniupnpcstrings.h.in,v 1.4 2011/01/04 11:41:53 nanard Exp $ */
/* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author: Thomas Bernard
* Copyright (c) 2005-2011 Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINIUPNPCSTRINGS_H_INCLUDED
@ -11,5 +11,13 @@
#define OS_STRING "OS/version"
#define MINIUPNPC_VERSION_STRING "version"
#if 0
/* according to "UPnP Device Architecture 1.0" */
#define UPNP_VERSION_STRING "UPnP/1.0"
#else
/* according to "UPnP Device Architecture 1.1" */
#define UPNP_VERSION_STRING "UPnP/1.1"
#endif
#endif

View file

@ -1,8 +1,8 @@
/* $Id: miniwget.c,v 1.61 2014/02/05 17:27:48 nanard Exp $ */
/* $Id: miniwget.c,v 1.70 2015/07/15 12:41:13 nanard Exp $ */
/* Project : miniupnp
* Website : 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. */
@ -38,6 +38,7 @@
#include <net/if.h>
#include <netdb.h>
#define closesocket close
#include <strings.h>
#endif /* #else _WIN32 */
#ifdef __GNU__
#define MAXHOSTNAMELEN 64
@ -84,7 +85,24 @@ getHTTPResponse(int s, int * size)
unsigned int chunksize_buf_index;
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;
@ -97,7 +115,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);
@ -232,13 +258,21 @@ getHTTPResponse(int s, int * size)
bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i);
if((content_buf_used + bytestocopy) > content_buf_len)
{
char * tmp;
if(content_length >= (int)(content_buf_used + bytestocopy)) {
content_buf_len = content_length;
} else {
content_buf_len = content_buf_used + bytestocopy;
}
content_buf = (char *)realloc((void *)content_buf,
content_buf_len);
tmp = realloc(content_buf, content_buf_len);
if(tmp == NULL) {
/* memory allocation error */
free(content_buf);
free(header_buf);
*size = -1;
return NULL;
}
content_buf = tmp;
}
memcpy(content_buf + content_buf_used, buf + i, bytestocopy);
content_buf_used += bytestocopy;
@ -256,13 +290,21 @@ getHTTPResponse(int s, int * size)
}
if(content_buf_used + n > content_buf_len)
{
char * tmp;
if(content_length >= (int)(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;
@ -368,10 +410,15 @@ miniwget3(const char * host,
"GET %s HTTP/%s\r\n"
"Host: %s:%d\r\n"
"Connection: Close\r\n"
"User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
"User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
"\r\n",
path, httpversion, host, port);
if ((unsigned int)len >= sizeof(buf))
{
closesocket(s);
return NULL;
}
sent = 0;
/* sending the HTTP request */
while(sent < len)

View file

@ -1,14 +1,14 @@
/* $Id: miniwget.h,v 1.7 2012/06/23 22:35:59 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
#ifndef MINIWGET_H_INCLUDED
#define MINIWGET_H_INCLUDED
#include "declspec.h"
#include "miniupnpc_declspec.h"
#ifdef __cplusplus
extern "C" {

View file

@ -1,4 +1,4 @@
/* $Id: minixmlvalid.c,v 1.6 2012/05/01 16:24:07 nanard Exp $ */
/* $Id: minixmlvalid.c,v 1.7 2015/07/15 12:41:15 nanard Exp $ */
/* MiniUPnP Project
* http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
* minixmlvalid.c :
@ -128,6 +128,11 @@ int testxmlparser(const char * xml, int size)
struct xmlparser parser;
evtlist.n = 0;
evtlist.events = malloc(sizeof(struct event)*100);
if(evtlist.events == NULL)
{
fprintf(stderr, "Memory allocation error.\n");
return -1;
}
memset(&parser, 0, sizeof(parser));
parser.xmlstart = xml;
parser.xmlsize = size;

View file

@ -160,6 +160,10 @@
RelativePath="..\minisoap.c"
>
</File>
<File
RelativePath="..\minissdpc.c"
>
</File>
<File
RelativePath="..\miniupnpc.c"
>
@ -184,6 +188,10 @@
RelativePath="..\upnpcommands.c"
>
</File>
<File
RelativePath="..\upnpdev.c"
>
</File>
<File
RelativePath="..\upnperrors.c"
>
@ -198,10 +206,6 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\bsdqueue.h"
>
</File>
<File
RelativePath="..\connecthostport.h"
>
@ -218,6 +222,10 @@
RelativePath="..\minisoap.h"
>
</File>
<File
RelativePath="..\minissdpc.h"
>
</File>
<File
RelativePath="..\miniupnpc.h"
>
@ -250,6 +258,10 @@
RelativePath="..\upnpcommands.h"
>
</File>
<File
RelativePath="..\upnpdev.h"
>
</File>
<File
RelativePath="..\upnperrors.h"
>

View file

@ -1,11 +1,14 @@
/* $Id: portlistingparse.c,v 1.6 2012/05/29 10:26:51 nanard Exp $ */
/* $Id: portlistingparse.c,v 1.9 2015/07/15 12:41:13 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 */
#include <string.h>
#include <stdlib.h>
#ifdef DEBUG
#include <stdio.h>
#endif /* DEBUG */
#include "portlistingparse.h"
#include "minixml.h"
@ -62,7 +65,17 @@ startelt(void * d, const char * name, int l)
{
struct PortMapping * pm;
pm = calloc(1, sizeof(struct PortMapping));
LIST_INSERT_HEAD( &(pdata->head), pm, entries);
if(pm == NULL)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"startelt");
#endif /* DEBUG */
return;
}
pm->l_next = pdata->l_head; /* insert in list */
pdata->l_head = pm;
}
}
@ -82,7 +95,7 @@ data(void * d, const char * data, int l)
{
struct PortMapping * pm;
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
pm = pdata->head.lh_first;
pm = pdata->l_head;
if(!pm)
return;
if(l > 63)
@ -134,7 +147,6 @@ ParsePortListing(const char * buffer, int bufsize,
struct xmlparser parser;
memset(pdata, 0, sizeof(struct PortMappingParserData));
LIST_INIT(&(pdata->head));
/* init xmlparser */
parser.xmlstart = buffer;
parser.xmlsize = bufsize;
@ -150,9 +162,10 @@ void
FreePortListing(struct PortMappingParserData * pdata)
{
struct PortMapping * pm;
while((pm = pdata->head.lh_first) != NULL)
while((pm = pdata->l_head) != NULL)
{
LIST_REMOVE(pm, entries);
/* remove from list */
pdata->l_head = pm->l_next;
free(pm);
}
}

View file

@ -1,22 +1,16 @@
/* $Id: portlistingparse.h,v 1.5 2012/01/21 13:30:33 nanard Exp $ */
/* $Id: portlistingparse.h,v 1.10 2014/11/01 10:37:32 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011-2012 Thomas Bernard
* (c) 2011-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef PORTLISTINGPARSE_H_INCLUDED
#define PORTLISTINGPARSE_H_INCLUDED
#include "declspec.h"
#include "miniupnpc_declspec.h"
/* for the definition of UNSIGNED_INTEGER */
#include "miniupnpctypes.h"
#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__)
#include "bsdqueue.h"
#else
#include <sys/queue.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -41,7 +35,7 @@ typedef enum { PortMappingEltNone,
NewLeaseTime } portMappingElt;
struct PortMapping {
LIST_ENTRY(PortMapping) entries;
struct PortMapping * l_next; /* list next element */
UNSIGNED_INTEGER leaseTime;
unsigned short externalPort;
unsigned short internalPort;
@ -53,7 +47,7 @@ struct PortMapping {
};
struct PortMappingParserData {
LIST_HEAD(portmappinglisthead, PortMapping) head;
struct PortMapping * l_head; /* list head */
portMappingElt curelt;
};

View file

@ -1,4 +1,5 @@
#! /usr/bin/python
# vim: tabstop=2 shiftwidth=2 expandtab
# MiniUPnP project
# Author : Thomas Bernard
# This Sample code is public domain.
@ -8,14 +9,43 @@
import miniupnpc
import sys
# create the object
u = miniupnpc.UPnP()
try:
import argparse
parser = argparse.ArgumentParser()
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()))
except:
print 'argparse not available'
i = 1
multicastif = None
minissdpdsocket = None
discoverdelay = 200
localport = 0
while i < len(sys.argv):
print sys.argv[i]
if sys.argv[i] == '-m' or sys.argv[i] == '--multicastif':
multicastif = sys.argv[i+1]
elif sys.argv[i] == '-p' or sys.argv[i] == '--minissdpdsocket':
minissdpdsocket = sys.argv[i+1]
elif sys.argv[i] == '-d' or sys.argv[i] == '--discoverdelay':
discoverdelay = int(sys.argv[i+1])
elif sys.argv[i] == '-z' or sys.argv[i] == '--localport':
localport = int(sys.argv[i+1])
else:
raise Exception('invalid argument %s' % sys.argv[i])
i += 2
# create the object
u = miniupnpc.UPnP(multicastif, minissdpdsocket, discoverdelay, localport)
print 'inital(default) values :'
print ' discoverdelay', u.discoverdelay
print ' lanaddr', u.lanaddr
print ' multicastif', u.multicastif
print ' minissdpdsocket', u.minissdpdsocket
u.discoverdelay = 200;
#u.minissdpdsocket = '../minissdpd/minissdpd.sock'
# discovery process, it usualy takes several seconds (2 seconds or more)
print 'Discovering... delay=%ums' % u.discoverdelay
@ -30,6 +60,8 @@ except Exception, e:
print 'local ip address :', u.lanaddr
print 'external ip address :', u.externalipaddress()
print u.statusinfo(), u.connectiontype()
print 'total bytes : sent', u.totalbytesent(), 'received', u.totalbytereceived()
print 'total packets : sent', u.totalpacketsent(), 'received', u.totalpacketreceived()
#print u.addportmapping(64000, 'TCP',
# '192.168.1.166', 63000, 'port mapping test', '')
@ -49,4 +81,8 @@ while True:
i = i + 1
print u.getspecificportmapping(port, proto)
try:
print u.getportmappingnumberofentries()
except Exception, e:
print 'GetPortMappingNumberOfEntries() is not supported :', e

View file

@ -1,16 +1,17 @@
/* $Id: receivedata.c,v 1.4 2012/06/23 22:34:47 nanard Exp $ */
/* $Id: receivedata.c,v 1.7 2015/11/09 21:51:41 nanard Exp $ */
/* Project : miniupnp
* Website : http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2011-2012 Thomas Bernard
* Copyright (c) 2011-2014 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#else /* _WIN32 */
#include <unistd.h>
#if defined(__amigaos__) && !defined(__amigaos4__)
#define socklen_t int
@ -21,10 +22,10 @@
#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());
@ -39,23 +40,23 @@ receivedata(int socket,
char * data, int length,
int timeout, unsigned int * scope_id)
{
#if MINIUPNPC_GET_SRC_ADDR
#ifdef MINIUPNPC_GET_SRC_ADDR
struct sockaddr_storage src_addr;
socklen_t src_addr_len = sizeof(src_addr);
#endif
#endif /* MINIUPNPC_GET_SRC_ADDR */
int n;
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
/* using poll */
struct pollfd fds[1]; /* for the poll */
#ifdef MINIUPNPC_IGNORE_EINTR
do {
#endif
#endif /* MINIUPNPC_IGNORE_EINTR */
fds[0].fd = socket;
fds[0].events = POLLIN;
n = poll(fds, 1, timeout);
#ifdef MINIUPNPC_IGNORE_EINTR
} while(n < 0 && errno == EINTR);
#endif
#endif /* MINIUPNPC_IGNORE_EINTR */
if(n < 0) {
PRINT_SOCKET_ERROR("poll");
return -1;
@ -63,7 +64,7 @@ receivedata(int socket,
/* timeout */
return 0;
}
#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
/* using select under _WIN32 and amigaos */
fd_set socketSet;
TIMEVAL timeval;
@ -78,27 +79,27 @@ receivedata(int socket,
} else if(n == 0) {
return 0;
}
#endif
#if MINIUPNPC_GET_SRC_ADDR
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
#ifdef MINIUPNPC_GET_SRC_ADDR
memset(&src_addr, 0, sizeof(src_addr));
n = recvfrom(socket, data, length, 0,
(struct sockaddr *)&src_addr, &src_addr_len);
#else
#else /* MINIUPNPC_GET_SRC_ADDR */
n = recv(socket, data, length, 0);
#endif
#endif /* MINIUPNPC_GET_SRC_ADDR */
if(n<0) {
PRINT_SOCKET_ERROR("recv");
}
#if MINIUPNPC_GET_SRC_ADDR
#ifdef MINIUPNPC_GET_SRC_ADDR
if (src_addr.ss_family == AF_INET6) {
const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr;
#ifdef DEBUG
printf("scope_id=%u\n", src_addr6->sin6_scope_id);
#endif
#endif /* DEBUG */
if(scope_id)
*scope_id = src_addr6->sin6_scope_id;
}
#endif
#endif /* MINIUPNPC_GET_SRC_ADDR */
return n;
}

6
external/miniupnpc/setup.py vendored Normal file → Executable file
View file

@ -1,4 +1,5 @@
#! /usr/bin/python
# vim: tabstop=8 shiftwidth=8 expandtab
# $Id: setup.py,v 1.9 2012/05/23 08:50:10 nanard Exp $
# the MiniUPnP Project (c) 2007-2014 Thomas Bernard
# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
@ -6,7 +7,10 @@
# python script to build the miniupnpc module under unix
#
# replace libminiupnpc.a by libminiupnpc.so for shared library usage
from distutils.core import setup, Extension
try:
from setuptools import setup, Extension
except ImportError:
from distutils.core import setup, Extension
from distutils import sysconfig
sysconfig.get_config_vars()["OPT"] = ''
sysconfig.get_config_vars()["CFLAGS"] = ''

6
external/miniupnpc/setupmingw32.py vendored Normal file → Executable file
View file

@ -1,11 +1,15 @@
#! /usr/bin/python
# vim: tabstop=8 shiftwidth=8 expandtab
# $Id: setupmingw32.py,v 1.8 2012/05/23 08:50:10 nanard Exp $
# the MiniUPnP Project (c) 2007-2014 Thomas Bernard
# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
#
# python script to build the miniupnpc module under windows (using mingw32)
#
from distutils.core import setup, Extension
try:
from setuptools import setup, Extension
except ImportError:
from distutils.core import setup, Extension
from distutils import sysconfig
sysconfig.get_config_vars()["OPT"] = ''
sysconfig.get_config_vars()["CFLAGS"] = ''

View file

@ -1,8 +1,8 @@
/* $Id: testigddescparse.c,v 1.4 2012/06/28 18:52:12 nanard Exp $ */
/* $Id: testigddescparse.c,v 1.8 2015/02/08 08:46:06 nanard Exp $ */
/* Project : miniupnp
* http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2008-2012 Thomas Bernard
* Copyright (c) 2008-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
@ -13,11 +13,108 @@
#include "minixml.h"
#include "miniupnpc.h"
int test_igd_desc_parse(char * buffer, int len)
/* count number of differences */
int compare_service(struct IGDdatas_service * s, FILE * f)
{
int n = 0;
char line[1024];
while(fgets(line, sizeof(line), f)) {
char * value;
char * equal;
char * name;
char * parsedvalue;
int l;
l = strlen(line);
while((l > 0) && ((line[l-1] == '\r') || (line[l-1] == '\n') || (line[l-1] == ' ')))
line[--l] = '\0';
if(l == 0)
break; /* end on blank line */
if(line[0] == '#')
continue; /* skip comments */
equal = strchr(line, '=');
if(equal == NULL) {
fprintf(stderr, "Warning, line does not contain '=' : %s\n", line);
continue;
}
*equal = '\0';
name = line;
while(*name == ' ' || *name == '\t')
name++;
l = strlen(name);
while((l > 0) && (name[l-1] == ' ' || name[l-1] == '\t'))
name[--l] = '\0';
value = equal + 1;
while(*value == ' ' || *value == '\t')
value++;
if(strcmp(name, "controlurl") == 0)
parsedvalue = s->controlurl;
else if(strcmp(name, "eventsuburl") == 0)
parsedvalue = s->eventsuburl;
else if(strcmp(name, "scpdurl") == 0)
parsedvalue = s->scpdurl;
else if(strcmp(name, "servicetype") == 0)
parsedvalue = s->servicetype;
else {
fprintf(stderr, "unknown field '%s'\n", name);
continue;
}
if(0 != strcmp(parsedvalue, value)) {
fprintf(stderr, "difference : '%s' != '%s'\n", parsedvalue, value);
n++;
}
}
return n;
}
int compare_igd(struct IGDdatas * p, FILE * f)
{
int n = 0;
char line[1024];
struct IGDdatas_service * s;
while(fgets(line, sizeof(line), f)) {
char * colon;
int l = (int)strlen(line);
while((l > 0) && (line[l-1] == '\r' || (line[l-1] == '\n')))
line[--l] = '\0';
if(l == 0 || line[0] == '#')
continue; /* skip blank lines and comments */
colon = strchr(line, ':');
if(colon == NULL) {
fprintf(stderr, "Warning, no ':' : %s\n", line);
continue;
}
s = NULL;
*colon = '\0';
if(strcmp(line, "CIF") == 0)
s = &p->CIF;
else if(strcmp(line, "first") == 0)
s = &p->first;
else if(strcmp(line, "second") == 0)
s = &p->second;
else if(strcmp(line, "IPv6FC") == 0)
s = &p->IPv6FC;
else {
s = NULL;
fprintf(stderr, "*** unknown service '%s' ***\n", line);
n++;
continue;
}
n += compare_service(s, f);
}
if(n > 0)
fprintf(stderr, "*** %d difference%s ***\n", n, (n > 1) ? "s" : "");
return n;
}
int test_igd_desc_parse(char * buffer, int len, FILE * f)
{
int n;
struct IGDdatas igd;
struct xmlparser parser;
struct UPNPUrls urls;
memset(&igd, 0, sizeof(struct IGDdatas));
memset(&parser, 0, sizeof(struct xmlparser));
parser.xmlstart = buffer;
@ -27,13 +124,16 @@ int test_igd_desc_parse(char * buffer, int len)
parser.endeltfunc = IGDendelt;
parser.datafunc = IGDdata;
parsexml(&parser);
#ifdef DEBUG
printIGD(&igd);
#endif /* DEBUG */
GetUPNPUrls(&urls, &igd, "http://fake/desc/url/file.xml", 0);
printf("ipcondescURL='%s'\n", urls.ipcondescURL);
printf("controlURL='%s'\n", urls.controlURL);
printf("controlURL_CIF='%s'\n", urls.controlURL_CIF);
n = f ? compare_igd(&igd, f) : 0;
FreeUPNPUrls(&urls);
return 0;
return n;
}
int main(int argc, char * * argv)
@ -41,9 +141,9 @@ int main(int argc, char * * argv)
FILE * f;
char * buffer;
int len;
int r = 0;
int r;
if(argc<2) {
fprintf(stderr, "Usage: %s file.xml\n", argv[0]);
fprintf(stderr, "Usage: %s file.xml [file.values]\n", argv[0]);
return 1;
}
f = fopen(argv[1], "r");
@ -55,10 +155,33 @@ int main(int argc, char * * argv)
len = ftell(f);
fseek(f, 0, SEEK_SET);
buffer = malloc(len);
fread(buffer, 1, len, f);
if(!buffer) {
fprintf(stderr, "Memory allocation error.\n");
fclose(f);
return 1;
}
r = (int)fread(buffer, 1, len, f);
if(r != len) {
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);
r = test_igd_desc_parse(buffer, len);
f = NULL;
if(argc > 2) {
f = fopen(argv[2], "r");
if(!f) {
fprintf(stderr, "Cannot open %s for reading.\n", argv[2]);
free(buffer);
return 1;
}
}
r = test_igd_desc_parse(buffer, len, f);
free(buffer);
if(f)
fclose(f);
return r;
}

View file

@ -1,7 +1,7 @@
#!/bin/sh
# $Id: testminiwget.sh,v 1.10 2013/11/13 15:08:08 nanard Exp $
# $Id: testminiwget.sh,v 1.13 2015/09/03 17:57:44 nanard Exp $
# project miniupnp : http://miniupnp.free.fr/
# (c) 2011-2012 Thomas Bernard
# (c) 2011-2015 Thomas Bernard
#
# test program for miniwget.c
# is usually invoked by "make check"
@ -15,7 +15,7 @@
# The script was tested and works with ksh, bash
# it should now also run with dash
TMPD=`mktemp -d miniwgetXXXXXXXXXX`
TMPD=`mktemp -d -t miniwgetXXXXXXXXXX`
HTTPSERVEROUT="${TMPD}/httpserverout"
EXPECTEDFILE="${TMPD}/expectedfile"
DOWNLOADEDFILE="${TMPD}/downloadedfile"

View file

@ -1,8 +1,8 @@
/* $Id: testminixml.c,v 1.9 2013/05/14 19:50:49 nanard Exp $
/* $Id: testminixml.c,v 1.10 2014/11/17 17:19:13 nanard Exp $
* MiniUPnP project
* Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author : Thomas Bernard.
* Copyright (c) 2005-2013 Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard
*
* testminixml.c
* test program for the "minixml" functions.
@ -58,7 +58,9 @@ void burptest(const char * buffer, int bufsize)
parser.endeltfunc = IGDendelt;
parser.datafunc = IGDdata;
parsexml(&parser);
#ifdef DEBUG
printIGD(&data);
#endif /* DEBUG */
}
/* ----- main ---- */

View file

@ -1,7 +1,7 @@
/* $Id: upnpc.c,v 1.104 2014/09/11 14:13:30 nanard Exp $ */
/* $Id: upnpc.c,v 1.111 2015/07/23 20:40:10 nanard Exp $ */
/* Project : miniupnp
* 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. */
@ -16,10 +16,12 @@
/* for IPPROTO_TCP / IPPROTO_UDP */
#include <netinet/in.h>
#endif
#include <ctype.h>
#include "miniwget.h"
#include "miniupnpc.h"
#include "upnpcommands.h"
#include "upnperrors.h"
#include "miniupnpcstrings.h"
/* protofix() checks if protocol is "UDP" or "TCP"
* returns NULL if not */
@ -41,6 +43,22 @@ const char * protofix(const char * proto)
return 0;
}
/* is_int() checks if parameter is an integer or not
* 1 for integer
* 0 for not an integer */
int is_int(char const* s)
{
if(s == NULL)
return 0;
while(*s) {
/* #define isdigit(c) ((c) >= '0' && (c) <= '9') */
if(!isdigit(*s))
return 0;
s++;
}
return 1;
}
static void DisplayInfos(struct UPNPUrls * urls,
struct IGDdatas * data)
{
@ -174,7 +192,7 @@ static void NewListRedirections(struct UPNPUrls * urls,
if(r == UPNPCOMMAND_SUCCESS)
{
printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next)
for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
{
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
i, pm->protocol, pm->externalPort, pm->internalClient,
@ -199,7 +217,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,
@ -525,9 +543,11 @@ int main(int argc, char ** argv)
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
@ -539,7 +559,8 @@ int main(int argc, char ** argv)
return -1;
}
#endif
printf("upnpc : miniupnpc library test client. (c) 2005-2014 Thomas Bernard\n");
printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
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 */
@ -556,12 +577,26 @@ int main(int argc, char ** argv)
rootdescurl = argv[++i];
else if(argv[i][1] == 'm')
multicastif = argv[++i];
else if(argv[i][1] == 'z')
{
char junk;
if(sscanf(argv[++i], "%d%c", &localport, &junk)!=1 ||
localport<0 || localport>65535 ||
(localport >1 && localport < 1024))
{
fprintf(stderr, "Invalid localport '%s'\n", argv[i]);
localport = UPNP_LOCAL_PORT_ANY;
break;
}
}
else if(argv[i][1] == 'p')
minissdpdpath = argv[++i];
else if(argv[i][1] == '6')
ipv6 = 1;
else if(argv[i][1] == 'e')
description = argv[++i];
else if(argv[i][1] == 't')
ttl = (unsigned char)atoi(argv[++i]);
else
{
command = argv[i][1];
@ -577,7 +612,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)
@ -591,7 +627,7 @@ int main(int argc, char ** argv)
fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]);
fprintf(stderr, " \t%s [options] -n ip port external_port protocol [duration]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]);
fprintf(stderr, " \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port redirections (for IGD:2 only)\n", argv[0]);
fprintf(stderr, " \t%s [options] -r port1 protocol1 [port2 protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]);
fprintf(stderr, " \t%s [options] -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]);
@ -606,13 +642,15 @@ int main(int argc, char ** argv)
fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n");
fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n");
fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n");
fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n");
fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n");
fprintf(stderr, " -t ttl : set multicast TTL. Default value is 2.\n");
return 1;
}
if( rootdescurl
|| (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
0/*sameport*/, ipv6, &error)))
localport, ipv6, ttl, &error)))
{
struct UPNPDev * device;
struct UPNPUrls urls;
@ -626,7 +664,7 @@ int main(int argc, char ** argv)
device->descURL, device->st);
}
}
else
else if(!rootdescurl)
{
printf("upnpDiscover() error code=%d\n", error);
}
@ -699,13 +737,29 @@ int main(int argc, char ** argv)
GetConnectionStatus(&urls, &data);
break;
case 'r':
for(i=0; i<commandargc; i+=2)
i = 0;
while(i<commandargc)
{
/*printf("port %s protocol %s\n", argv[i], argv[i+1]);*/
SetRedirectAndTest(&urls, &data,
lanaddr, commandargv[i],
commandargv[i], commandargv[i+1], "0",
description, 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> */
SetRedirectAndTest(&urls, &data,
lanaddr, commandargv[i],
commandargv[i+1], commandargv[i+2], "0",
description, 0);
i+=3; /* 3 parameters parsed */
} else {
/* 2nd parameter not an integer : <port> <protocol> */
SetRedirectAndTest(&urls, &data,
lanaddr, commandargv[i],
commandargv[i], commandargv[i+1], "0",
description, 0);
i+=2; /* 2 parameters parsed */
}
}
break;
case 'A':
@ -768,6 +822,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;
}

View file

@ -1,7 +1,7 @@
/* $Id: upnpcommands.c,v 1.42 2014/01/31 13:18:25 nanard Exp $ */
/* $Id: upnpcommands.c,v 1.46 2015/07/15 12:19:00 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
@ -159,7 +159,7 @@ UPNP_GetStatusInfo(const char * controlURL,
if(up)
sscanf(up,"%u",uptime);
else
uptime = 0;
*uptime = 0;
}
if(lastconnerror) {
@ -354,6 +354,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";
@ -416,6 +418,8 @@ UPNP_AddAnyPortMapping(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";
@ -478,6 +482,8 @@ 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";
@ -522,6 +528,8 @@ UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
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";
@ -575,6 +583,8 @@ 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,
@ -710,6 +720,8 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
return UPNPCOMMAND_INVALID_ARGS;
GetPortMappingArgs = calloc(4, sizeof(struct UPNParg));
if(GetPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetPortMappingArgs[0].elt = "NewRemoteHost";
GetPortMappingArgs[0].val = remoteHost;
GetPortMappingArgs[1].elt = "NewExternalPort";
@ -799,6 +811,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";
@ -926,6 +940,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";
@ -982,6 +998,8 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS;
AddPinholeArgs = calloc(7, sizeof(struct UPNParg));
if(AddPinholeArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
/* RemoteHost can be wilcarded */
if(strncmp(remoteHost, "empty", 5)==0)
{
@ -1055,6 +1073,8 @@ 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";
@ -1096,6 +1116,8 @@ 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,
@ -1135,6 +1157,8 @@ 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,
@ -1180,6 +1204,8 @@ 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,

View file

@ -1,7 +1,7 @@
/* $Id: upnpcommands.h,v 1.27 2014/02/17 15:38:26 nanard Exp $ */
/* $Id: upnpcommands.h,v 1.30 2015/07/15 12:21:28 nanard Exp $ */
/* Miniupnp project : 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 within this distribution */
#ifndef UPNPCOMMANDS_H_INCLUDED
@ -9,7 +9,7 @@
#include "upnpreplyparse.h"
#include "portlistingparse.h"
#include "declspec.h"
#include "miniupnpc_declspec.h"
#include "miniupnpctypes.h"
/* MiniUPnPc return codes : */
@ -18,6 +18,7 @@
#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" {

View file

@ -1,5 +1,5 @@
/* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 nanard Exp $ */
/* (c) 2007 Thomas Bernard
/* (c) 2007-2015 Thomas Bernard
* All rights reserved.
* MiniUPnP Project.
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -8,7 +8,7 @@
#ifndef UPNPERRORS_H_INCLUDED
#define UPNPERRORS_H_INCLUDED
#include "declspec.h"
#include "miniupnpc_declspec.h"
#ifdef __cplusplus
extern "C" {

View file

@ -1,7 +1,7 @@
/* $Id: upnpreplyparse.c,v 1.15 2013/06/06 21:36:40 nanard Exp $ */
/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2013 Thomas Bernard
* (c) 2006-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -40,6 +40,15 @@ NameValueParserEndElt(void * d, const char * name, int l)
/* standard case. Limited to n chars strings */
l = data->cdatalen;
nv = malloc(sizeof(struct NameValue));
if(nv == NULL)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserEndElt");
#endif /* DEBUG */
return;
}
if(l>=(int)sizeof(nv->value))
l = sizeof(nv->value) - 1;
strncpy(nv->name, data->curelt, 64);
@ -53,7 +62,8 @@ NameValueParserEndElt(void * d, const char * name, int l)
{
nv->value[0] = '\0';
}
LIST_INSERT_HEAD( &(data->head), nv, entries);
nv->l_next = data->l_head; /* insert in list */
data->l_head = nv;
}
data->cdata = NULL;
data->cdatalen = 0;
@ -71,6 +81,10 @@ NameValueParserGetData(void * d, const char * datas, int l)
if(!data->portListing)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserGetData");
#endif /* DEBUG */
return;
}
memcpy(data->portListing, datas, l);
@ -89,19 +103,19 @@ void
ParseNameValue(const char * buffer, int bufsize,
struct NameValueParserData * data)
{
struct xmlparser parser;
LIST_INIT(&(data->head));
struct xmlparser parser;
data->l_head = NULL;
data->portListing = NULL;
data->portListingLength = 0;
/* init xmlparser object */
parser.xmlstart = buffer;
parser.xmlsize = bufsize;
parser.data = data;
parser.starteltfunc = NameValueParserStartElt;
parser.endeltfunc = NameValueParserEndElt;
parser.datafunc = NameValueParserGetData;
/* init xmlparser object */
parser.xmlstart = buffer;
parser.xmlsize = bufsize;
parser.data = data;
parser.starteltfunc = NameValueParserStartElt;
parser.endeltfunc = NameValueParserEndElt;
parser.datafunc = NameValueParserGetData;
parser.attfunc = 0;
parsexml(&parser);
parsexml(&parser);
}
void
@ -114,9 +128,9 @@ ClearNameValueList(struct NameValueParserData * pdata)
pdata->portListing = NULL;
pdata->portListingLength = 0;
}
while((nv = pdata->head.lh_first) != NULL)
while((nv = pdata->l_head) != NULL)
{
LIST_REMOVE(nv, entries);
pdata->l_head = nv->l_next;
free(nv);
}
}
@ -127,9 +141,9 @@ GetValueFromNameValueList(struct NameValueParserData * pdata,
{
struct NameValue * nv;
char * p = NULL;
for(nv = pdata->head.lh_first;
for(nv = pdata->l_head;
(nv != NULL) && (p == NULL);
nv = nv->entries.le_next)
nv = nv->l_next)
{
if(strcmp(nv->name, Name) == 0)
p = nv->value;
@ -171,13 +185,13 @@ DisplayNameValueList(char * buffer, int bufsize)
struct NameValueParserData pdata;
struct NameValue * nv;
ParseNameValue(buffer, bufsize, &pdata);
for(nv = pdata.head.lh_first;
for(nv = pdata.l_head;
nv != NULL;
nv = nv->entries.le_next)
nv = nv->l_next)
{
printf("%s = %s\n", nv->name, nv->value);
}
ClearNameValueList(&pdata);
}
#endif
#endif /* DEBUG */

View file

@ -1,4 +1,4 @@
/* $Id: upnpreplyparse.h,v 1.17 2013/06/06 21:36:40 nanard Exp $ */
/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2013 Thomas Bernard
@ -8,25 +8,19 @@
#ifndef UPNPREPLYPARSE_H_INCLUDED
#define UPNPREPLYPARSE_H_INCLUDED
#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__)
#include "bsdqueue.h"
#else
#include <sys/queue.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct NameValue {
LIST_ENTRY(NameValue) entries;
char name[64];
char value[128];
struct NameValue * l_next;
char name[64];
char value[128];
};
struct NameValueParserData {
LIST_HEAD(listhead, NameValue) head;
char curelt[64];
struct NameValue * l_head;
char curelt[64];
char * portListing;
int portListingLength;
int topelt;

View file

@ -1,8 +1,8 @@
/* $Id: wingenminiupnpcstrings.c,v 1.2 2011/01/11 15:31:13 nanard Exp $ */
/* $Id: wingenminiupnpcstrings.c,v 1.4 2015/02/08 08:46:06 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author: Thomas Bernard
* Copyright (c) 2005-2009 Thomas Bernard
* Copyright (c) 2005-2015 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENSE file provided within this distribution */
#include <stdio.h>
@ -59,6 +59,7 @@ int main(int argc, char * * argv) {
fout = fopen(argv[2], "w");
if(!fout) {
fprintf(stderr, "Cannot open %s for writing.\n", argv[2]);
fclose(fin);
return 1;
}
n = 0;