Port mapping with UPnP
This commit is contained in:
parent
a401a02ddb
commit
9682a15400
|
@ -7,7 +7,7 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
set(CMAKE_CONFIGURATION_TYPES "Debug;Release")
|
set(CMAKE_CONFIGURATION_TYPES "Debug;Release")
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
include_directories(src contrib/epee/include "${CMAKE_BINARY_DIR}/version")
|
include_directories(src contrib/epee/include external "${CMAKE_BINARY_DIR}/version")
|
||||||
|
|
||||||
set(STATIC ${MSVC} CACHE BOOL "Link libraries statically")
|
set(STATIC ${MSVC} CACHE BOOL "Link libraries statically")
|
||||||
|
|
||||||
|
@ -110,5 +110,6 @@ else()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(external)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
|
|
2
README
2
README
|
@ -1,4 +1,4 @@
|
||||||
-= Building CryptoNote =-
|
-= Building CyberNote =-
|
||||||
|
|
||||||
On *nix:
|
On *nix:
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
Release notes 0.8.5
|
||||||
|
|
||||||
|
- Port mapping for daemon using UPnP
|
||||||
|
- Improvements for daemon JSON RPC API
|
||||||
|
|
||||||
Release notes 0.8.4
|
Release notes 0.8.4
|
||||||
|
|
||||||
- Formalization of high level API
|
- Formalization of high level API
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
set(UPNPC_BUILD_STATIC ON CACHE BOOL "Build static library")
|
||||||
|
set(UPNPC_BUILD_SHARED OFF CACHE BOOL "Build shared library")
|
||||||
|
set(UPNPC_BUILD_TESTS OFF CACHE BOOL "Build test executables")
|
||||||
|
add_subdirectory(miniupnpc)
|
||||||
|
|
||||||
|
set_property(TARGET upnpc-static PROPERTY FOLDER "external")
|
||||||
|
if(MSVC)
|
||||||
|
set_property(TARGET upnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -wd4244 -wd4267")
|
||||||
|
elseif(NOT MSVC)
|
||||||
|
set_property(TARGET upnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-undef -Wno-unused-result -Wno-unused-value")
|
||||||
|
endif()
|
|
@ -0,0 +1,176 @@
|
||||||
|
cmake_minimum_required (VERSION 2.6)
|
||||||
|
|
||||||
|
project (miniupnpc C)
|
||||||
|
set (MINIUPNPC_VERSION 1.9)
|
||||||
|
set (MINIUPNPC_API_VERSION 10)
|
||||||
|
|
||||||
|
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 (NO_GETADDRINFO)
|
||||||
|
|
||||||
|
if (NOT WIN32)
|
||||||
|
add_definitions (-DMINIUPNPC_SET_SOCKET_TIMEOUT)
|
||||||
|
add_definitions (-D_BSD_SOURCE -D_POSIX_C_SOURCE=1)
|
||||||
|
else (NOT WIN32)
|
||||||
|
add_definitions (-D_WIN32_WINNT=0x0501) # XP or higher for getnameinfo and friends
|
||||||
|
endif (NOT WIN32)
|
||||||
|
|
||||||
|
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||||
|
add_definitions (-DMACOSX -D_DARWIN_C_SOURCE)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# 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 (miniupnpcstrings.h.cmake ${CMAKE_BINARY_DIR}/miniupnpcstrings.h)
|
||||||
|
include_directories (${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
|
set (MINIUPNPC_SOURCES
|
||||||
|
igd_desc_parse.c
|
||||||
|
miniupnpc.c
|
||||||
|
minixml.c
|
||||||
|
minisoap.c
|
||||||
|
miniwget.c
|
||||||
|
upnpc.c
|
||||||
|
upnpcommands.c
|
||||||
|
upnpreplyparse.c
|
||||||
|
upnperrors.c
|
||||||
|
connecthostport.c
|
||||||
|
portlistingparse.c
|
||||||
|
receivedata.c
|
||||||
|
)
|
||||||
|
|
||||||
|
if (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
|
||||||
|
set (MINIUPNPC_SOURCES ${MINIUPNPC_SOURCES} minissdpc.c)
|
||||||
|
endif (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
set_source_files_properties (${MINIUPNPC_SOURCES} PROPERTIES
|
||||||
|
COMPILE_DEFINITIONS STATICLIB
|
||||||
|
COMPILE_DEFINITIONS MINIUPNP_EXPORTS
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
set (LDLIBS ${WINSOCK2_LIBRARY} ${IPHLPAPI_LIBRARY} ${LDLIBS})
|
||||||
|
#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 (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 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 (UPNPC_BUILD_STATIC)
|
||||||
|
|
||||||
|
if (UPNPC_BUILD_SHARED)
|
||||||
|
add_library (upnpc-shared SHARED ${MINIUPNPC_SOURCES})
|
||||||
|
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 (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
|
||||||
|
LIBRARY DESTINATION lib${LIB_SUFFIX}
|
||||||
|
ARCHIVE DESTINATION lib${LIB_SUFFIX}
|
||||||
|
)
|
||||||
|
install (FILES
|
||||||
|
miniupnpc.h
|
||||||
|
miniwget.h
|
||||||
|
upnpcommands.h
|
||||||
|
igd_desc_parse.h
|
||||||
|
upnpreplyparse.h
|
||||||
|
upnperrors.h
|
||||||
|
declspec.h
|
||||||
|
DESTINATION include/miniupnpc
|
||||||
|
)
|
||||||
|
|
||||||
|
set (CONFIGURED YES CACHE INTERNAL "")
|
||||||
|
|
||||||
|
# vim: ts=2:sw=2
|
|
@ -0,0 +1,585 @@
|
||||||
|
$Id: Changelog.txt,v 1.193 2014/02/05 17:26:45 nanard Exp $
|
||||||
|
miniUPnP client Changelog.
|
||||||
|
|
||||||
|
2014/02/05:
|
||||||
|
handle EINPROGRESS after connect()
|
||||||
|
|
||||||
|
2014/02/03:
|
||||||
|
minixml now handle XML comments
|
||||||
|
|
||||||
|
VERSION 1.9 : released 2014/01/31
|
||||||
|
|
||||||
|
2014/01/31:
|
||||||
|
added argument remoteHost to UPNP_GetSpecificPortMappingEntry()
|
||||||
|
increment API_VERSION to 10
|
||||||
|
|
||||||
|
2013/12/09:
|
||||||
|
--help and -h arguments in upnpc.c
|
||||||
|
|
||||||
|
2013/10/07:
|
||||||
|
fixed potential buffer overrun in miniwget.c
|
||||||
|
Modified UPNP_GetValidIGD() to check for ExternalIpAddress
|
||||||
|
|
||||||
|
2013/08/01:
|
||||||
|
define MAXHOSTNAMELEN if not already done
|
||||||
|
|
||||||
|
2013/06/06:
|
||||||
|
update upnpreplyparse to allow larger values (128 chars instead of 64)
|
||||||
|
|
||||||
|
2013/05/14:
|
||||||
|
Update upnpreplyparse to take into account "empty" elements
|
||||||
|
validate upnpreplyparse.c code with "make check"
|
||||||
|
|
||||||
|
2013/05/03:
|
||||||
|
Fix Solaris build thanks to Maciej Małecki
|
||||||
|
|
||||||
|
2013/04/27:
|
||||||
|
Fix testminiwget.sh for BSD
|
||||||
|
|
||||||
|
2013/03/23:
|
||||||
|
Fixed Makefile for *BSD
|
||||||
|
|
||||||
|
2013/03/11:
|
||||||
|
Update Makefile to use JNAerator version 0.11
|
||||||
|
|
||||||
|
2013/02/11:
|
||||||
|
Fix testminiwget.sh for use with dash
|
||||||
|
Use $(DESTDIR) in Makefile
|
||||||
|
|
||||||
|
VERSION 1.8 : released 2013/02/06
|
||||||
|
|
||||||
|
2012/10/16:
|
||||||
|
fix testminiwget with no IPv6 support
|
||||||
|
|
||||||
|
2012/09/27:
|
||||||
|
Rename all include guards to not clash with C99
|
||||||
|
(7.1.3 Reserved identifiers).
|
||||||
|
|
||||||
|
2012/08/30:
|
||||||
|
Added -e option to upnpc program (set description for port mappings)
|
||||||
|
|
||||||
|
2012/08/29:
|
||||||
|
Python 3 support (thanks to Christopher Foo)
|
||||||
|
|
||||||
|
2012/08/11:
|
||||||
|
Fix a memory link in UPNP_GetValidIGD()
|
||||||
|
Try to handle scope id in link local IPv6 URL under MS Windows
|
||||||
|
|
||||||
|
2012/07/20:
|
||||||
|
Disable HAS_IP_MREQN on DragonFly BSD
|
||||||
|
|
||||||
|
2012/06/28:
|
||||||
|
GetUPNPUrls() now inserts scope into link-local IPv6 addresses
|
||||||
|
|
||||||
|
2012/06/23:
|
||||||
|
More error return checks in upnpc.c
|
||||||
|
#define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id
|
||||||
|
parseURL() now parses IPv6 addresses scope
|
||||||
|
new parameter for miniwget() : IPv6 address scope
|
||||||
|
increment API_VERSION to 9
|
||||||
|
|
||||||
|
2012/06/20:
|
||||||
|
fixed CMakeLists.txt
|
||||||
|
|
||||||
|
2012/05/29
|
||||||
|
Improvements in testminiwget.sh
|
||||||
|
|
||||||
|
VERSION 1.7 : released 2012/05/24
|
||||||
|
|
||||||
|
2012/05/01:
|
||||||
|
Cleanup settings of CFLAGS in Makefile
|
||||||
|
Fix signed/unsigned integer comparaisons
|
||||||
|
|
||||||
|
2012/04/20:
|
||||||
|
Allow to specify protocol with TCP or UDP for -A option
|
||||||
|
|
||||||
|
2012/04/09:
|
||||||
|
Only try to fetch XML description once in UPNP_GetValidIGD()
|
||||||
|
Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments.
|
||||||
|
|
||||||
|
2012/04/05:
|
||||||
|
minor improvements to minihttptestserver.c
|
||||||
|
|
||||||
|
2012/03/15:
|
||||||
|
upnperrors.c returns valid error string for unrecognized error codes
|
||||||
|
|
||||||
|
2012/03/08:
|
||||||
|
make minihttptestserver listen on loopback interface instead of 0.0.0.0
|
||||||
|
|
||||||
|
2012/01/25:
|
||||||
|
Maven installation thanks to Alexey Kuznetsov
|
||||||
|
|
||||||
|
2012/01/21:
|
||||||
|
Replace WIN32 macro by _WIN32
|
||||||
|
|
||||||
|
2012/01/19:
|
||||||
|
Fixes in java wrappers thanks to Alexey Kuznetsov :
|
||||||
|
https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc
|
||||||
|
Make and install .deb packages (python) thanks to Alexey Kuznetsov :
|
||||||
|
https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc
|
||||||
|
|
||||||
|
2012/01/07:
|
||||||
|
The multicast interface can now be specified by name with IPv4.
|
||||||
|
|
||||||
|
2012/01/02:
|
||||||
|
Install man page
|
||||||
|
|
||||||
|
2011/11/25:
|
||||||
|
added header to Port Mappings list in upnpc.c
|
||||||
|
|
||||||
|
2011/10/09:
|
||||||
|
Makefile : make clean now removes jnaerator generated files.
|
||||||
|
MINIUPNPC_VERSION in miniupnpc.h (updated by make)
|
||||||
|
|
||||||
|
2011/09/12:
|
||||||
|
added rootdescURL to UPNPUrls structure.
|
||||||
|
|
||||||
|
VERSION 1.6 : released 2011/07/25
|
||||||
|
|
||||||
|
2011/07/25:
|
||||||
|
Update doc for version 1.6 release
|
||||||
|
|
||||||
|
2011/06/18:
|
||||||
|
Fix for windows in miniwget.c
|
||||||
|
|
||||||
|
2011/06/04:
|
||||||
|
display remote host in port mapping listing
|
||||||
|
|
||||||
|
2011/06/03:
|
||||||
|
Fix in make install : there were missing headers
|
||||||
|
|
||||||
|
2011/05/26:
|
||||||
|
Fix the socket leak in miniwget thanks to Richard Marsh.
|
||||||
|
Permit to add leaseduration in -a command. Display lease duration.
|
||||||
|
|
||||||
|
2011/05/15:
|
||||||
|
Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6
|
||||||
|
|
||||||
|
2011/05/09:
|
||||||
|
add a test in testminiwget.sh.
|
||||||
|
more error checking in miniwget.c
|
||||||
|
|
||||||
|
2011/05/06:
|
||||||
|
Adding some tool to test and validate miniwget.c
|
||||||
|
simplified and debugged miniwget.c
|
||||||
|
|
||||||
|
2011/04/11:
|
||||||
|
moving ReceiveData() to a receivedata.c file.
|
||||||
|
parsing presentation url
|
||||||
|
adding IGD v2 WANIPv6FirewallControl commands
|
||||||
|
|
||||||
|
2011/04/10:
|
||||||
|
update of miniupnpcmodule.c
|
||||||
|
comments in miniwget.c, update in testminiwget
|
||||||
|
Adding errors codes from IGD v2
|
||||||
|
new functions in upnpc.c for IGD v2
|
||||||
|
|
||||||
|
2011/04/09:
|
||||||
|
Support for litteral ip v6 address in miniwget
|
||||||
|
|
||||||
|
2011/04/08:
|
||||||
|
Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
|
||||||
|
Updating APIVERSION
|
||||||
|
Supporting IPV6 in upnpDiscover()
|
||||||
|
Adding a -6 option to upnpc command line tool
|
||||||
|
|
||||||
|
2011/03/18:
|
||||||
|
miniwget/parseURL() : return an error when url param is null.
|
||||||
|
fixing GetListOfPortMappings()
|
||||||
|
|
||||||
|
2011/03/14:
|
||||||
|
upnpDiscover() now reporting an error code.
|
||||||
|
improvements in comments.
|
||||||
|
|
||||||
|
2011/03/11:
|
||||||
|
adding miniupnpcstrings.h.cmake and CMakeLists.txt files.
|
||||||
|
|
||||||
|
2011/02/15:
|
||||||
|
Implementation of GetListOfPortMappings()
|
||||||
|
|
||||||
|
2011/02/07:
|
||||||
|
updates to minixml to support character data starting with spaces
|
||||||
|
minixml now support CDATA
|
||||||
|
upnpreplyparse treats <NewPortListing> specificaly
|
||||||
|
change in simpleUPnPcommand to return the buffer (simplification)
|
||||||
|
|
||||||
|
2011/02/06:
|
||||||
|
Added leaseDuration argument to AddPortMapping()
|
||||||
|
Starting to implement GetListOfPortMappings()
|
||||||
|
|
||||||
|
2011/01/11:
|
||||||
|
updating wingenminiupnpcstrings.c
|
||||||
|
|
||||||
|
2011/01/04:
|
||||||
|
improving updateminiupnpcstrings.sh
|
||||||
|
|
||||||
|
VERSION 1.5 : released 2011/01/01
|
||||||
|
|
||||||
|
2010/12/21:
|
||||||
|
use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo
|
||||||
|
|
||||||
|
2010/12/11:
|
||||||
|
Improvements on getHTTPResponse() code.
|
||||||
|
|
||||||
|
2010/12/09:
|
||||||
|
new code for miniwget that handle Chunked transfer encoding
|
||||||
|
using getHTTPResponse() in SOAP call code
|
||||||
|
Adding MANIFEST.in for 'python setup.py bdist_rpm'
|
||||||
|
|
||||||
|
2010/11/25:
|
||||||
|
changes to minissdpc.c to compile under Win32.
|
||||||
|
see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729
|
||||||
|
|
||||||
|
2010/09/17:
|
||||||
|
Various improvement to Makefile from Michał Górny
|
||||||
|
|
||||||
|
2010/08/05:
|
||||||
|
Adding the script "external-ip.sh" from Reuben Hawkins
|
||||||
|
|
||||||
|
2010/06/09:
|
||||||
|
update to python module to match modification made on 2010/04/05
|
||||||
|
update to Java test code to match modification made on 2010/04/05
|
||||||
|
all UPNP_* function now return an error if the SOAP request failed
|
||||||
|
at HTTP level.
|
||||||
|
|
||||||
|
2010/04/17:
|
||||||
|
Using GetBestRoute() under win32 in order to find the
|
||||||
|
right interface to use.
|
||||||
|
|
||||||
|
2010/04/12:
|
||||||
|
Retrying with HTTP/1.1 if HTTP/1.0 failed. see
|
||||||
|
http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703
|
||||||
|
|
||||||
|
2010/04/07:
|
||||||
|
avoid returning duplicates in upnpDiscover()
|
||||||
|
|
||||||
|
2010/04/05:
|
||||||
|
Create a connecthostport.h/.c with connecthostport() function
|
||||||
|
and use it in miniwget and miniupnpc.
|
||||||
|
Use getnameinfo() instead of inet_ntop or inet_ntoa
|
||||||
|
Work to make miniupnpc IPV6 compatible...
|
||||||
|
Add java test code.
|
||||||
|
Big changes in order to support device having both WANIPConnection
|
||||||
|
and WANPPPConnection.
|
||||||
|
|
||||||
|
2010/04/04:
|
||||||
|
Use getaddrinfo() instead of gethostbyname() in miniwget.
|
||||||
|
|
||||||
|
2010/01/06:
|
||||||
|
#define _DARWIN_C_SOURCE for Mac OS X
|
||||||
|
|
||||||
|
2009/12/19:
|
||||||
|
Improve MinGW32 build
|
||||||
|
|
||||||
|
2009/12/11:
|
||||||
|
adding a MSVC9 project to build the static library and executable
|
||||||
|
|
||||||
|
2009/12/10:
|
||||||
|
Fixing some compilation stuff for Windows/MinGW
|
||||||
|
|
||||||
|
2009/12/07:
|
||||||
|
adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS
|
||||||
|
some fixes for Windows when using virtual ethernet adapters (it is the
|
||||||
|
case with VMWare installed).
|
||||||
|
|
||||||
|
2009/12/04:
|
||||||
|
some fixes for AmigaOS compilation
|
||||||
|
Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked
|
||||||
|
transfer encoding)
|
||||||
|
|
||||||
|
2009/12/03:
|
||||||
|
updating printIDG and testigddescparse.c for debug.
|
||||||
|
modifications to compile under AmigaOS
|
||||||
|
adding a testminiwget program
|
||||||
|
Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked
|
||||||
|
transfer encoding
|
||||||
|
|
||||||
|
2009/11/26:
|
||||||
|
fixing updateminiupnpcstrings.sh to take into account
|
||||||
|
which command that does not return an error code.
|
||||||
|
|
||||||
|
VERSION 1.4 : released 2009/10/30
|
||||||
|
|
||||||
|
2009/10/16:
|
||||||
|
using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module.
|
||||||
|
|
||||||
|
2009/10/10:
|
||||||
|
Some fixes for compilation under Solaris
|
||||||
|
compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464
|
||||||
|
|
||||||
|
2009/09/21:
|
||||||
|
fixing the code to ignore EINTR during connect() calls.
|
||||||
|
|
||||||
|
2009/08/07:
|
||||||
|
Set socket timeout for connect()
|
||||||
|
Some cleanup in miniwget.c
|
||||||
|
|
||||||
|
2009/08/04:
|
||||||
|
remove multiple redirections with -d in upnpc.c
|
||||||
|
Print textual error code in upnpc.c
|
||||||
|
Ignore EINTR during the connect() and poll() calls.
|
||||||
|
|
||||||
|
2009/07/29:
|
||||||
|
fix in updateminiupnpcstrings.sh if OS name contains "/"
|
||||||
|
Sending a correct value for MX: field in SSDP request
|
||||||
|
|
||||||
|
2009/07/20:
|
||||||
|
Change the Makefile to compile under Mac OS X
|
||||||
|
Fixed a stackoverflow in getDevicesFromMiniSSDPD()
|
||||||
|
|
||||||
|
2009/07/09:
|
||||||
|
Compile under Haiku
|
||||||
|
generate miniupnpcstrings.h.in from miniupnpcstrings.h
|
||||||
|
|
||||||
|
2009/06/04:
|
||||||
|
patching to compile under CygWin and cross compile for minGW
|
||||||
|
|
||||||
|
VERSION 1.3 :
|
||||||
|
|
||||||
|
2009/04/17:
|
||||||
|
updating python module
|
||||||
|
Use strtoull() when using C99
|
||||||
|
|
||||||
|
2009/02/28:
|
||||||
|
Fixed miniwget.c for compiling under sun
|
||||||
|
|
||||||
|
2008/12/18:
|
||||||
|
cleanup in Makefile (thanks to Paul de Weerd)
|
||||||
|
minissdpc.c : win32 compatibility
|
||||||
|
miniupnpc.c : changed xmlns prefix from 'm' to 'u'
|
||||||
|
Removed NDEBUG (using DEBUG)
|
||||||
|
|
||||||
|
2008/10/14:
|
||||||
|
Added the ExternalHost argument to DeletePortMapping()
|
||||||
|
|
||||||
|
2008/10/11:
|
||||||
|
Added the ExternalHost argument to AddPortMapping()
|
||||||
|
Put a correct User-Agent: header in HTTP requests.
|
||||||
|
|
||||||
|
VERSION 1.2 :
|
||||||
|
|
||||||
|
2008/10/07:
|
||||||
|
Update docs
|
||||||
|
|
||||||
|
2008/09/25:
|
||||||
|
Integrated sameport patch from Dario Meloni : Added a "sameport"
|
||||||
|
argument to upnpDiscover().
|
||||||
|
|
||||||
|
2008/07/18:
|
||||||
|
small modif to make Clang happy :)
|
||||||
|
|
||||||
|
2008/07/17:
|
||||||
|
#define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV...
|
||||||
|
|
||||||
|
2008/07/14:
|
||||||
|
include declspec.h in installation (to /usr/include/miniupnpc)
|
||||||
|
|
||||||
|
VERSION 1.1 :
|
||||||
|
|
||||||
|
2008/07/04:
|
||||||
|
standard options for install/ln instead of gnu-specific stuff.
|
||||||
|
|
||||||
|
2008/07/03:
|
||||||
|
now builds a .dll and .lib with win32. (mingw32)
|
||||||
|
|
||||||
|
2008/04/28:
|
||||||
|
make install now install the binary of the upnpc tool
|
||||||
|
|
||||||
|
2008/04/27:
|
||||||
|
added testupnpigd.py
|
||||||
|
added error strings for miniupnpc "internal" errors
|
||||||
|
improved python module error/exception reporting.
|
||||||
|
|
||||||
|
2008/04/23:
|
||||||
|
Completely rewrite igd_desc_parse.c in order to be compatible with
|
||||||
|
Linksys WAG200G
|
||||||
|
Added testigddescparse
|
||||||
|
updated python module
|
||||||
|
|
||||||
|
VERSION 1.0 :
|
||||||
|
|
||||||
|
2008/02/21:
|
||||||
|
put some #ifdef DEBUG around DisplayNameValueList()
|
||||||
|
|
||||||
|
2008/02/18:
|
||||||
|
Improved error reporting in upnpcommands.c
|
||||||
|
UPNP_GetStatusInfo() returns LastConnectionError
|
||||||
|
|
||||||
|
2008/02/16:
|
||||||
|
better error handling in minisoap.c
|
||||||
|
improving display of "valid IGD found" in upnpc.c
|
||||||
|
|
||||||
|
2008/02/03:
|
||||||
|
Fixing UPNP_GetValidIGD()
|
||||||
|
improved make install :)
|
||||||
|
|
||||||
|
2007/12/22:
|
||||||
|
Adding upnperrors.c/h to provide a strupnperror() function
|
||||||
|
used to translate UPnP error codes to string.
|
||||||
|
|
||||||
|
2007/12/19:
|
||||||
|
Fixing getDevicesFromMiniSSDPD()
|
||||||
|
improved error reporting of UPnP functions
|
||||||
|
|
||||||
|
2007/12/18:
|
||||||
|
It is now possible to specify a different location for MiniSSDPd socket.
|
||||||
|
working with MiniSSDPd is now more efficient.
|
||||||
|
python module improved.
|
||||||
|
|
||||||
|
2007/12/16:
|
||||||
|
improving error reporting
|
||||||
|
|
||||||
|
2007/12/13:
|
||||||
|
Try to improve compatibility by using HTTP/1.0 instead of 1.1 and
|
||||||
|
XML a bit different for SOAP.
|
||||||
|
|
||||||
|
2007/11/25:
|
||||||
|
fixed select() call for linux
|
||||||
|
|
||||||
|
2007/11/15:
|
||||||
|
Added -fPIC to CFLAG for better shared library code.
|
||||||
|
|
||||||
|
2007/11/02:
|
||||||
|
Fixed a potential socket leak in miniwget2()
|
||||||
|
|
||||||
|
2007/10/16:
|
||||||
|
added a parameter to upnpDiscover() in order to allow the use of another
|
||||||
|
interface than the default multicast interface.
|
||||||
|
|
||||||
|
2007/10/12:
|
||||||
|
Fixed the creation of symbolic link in Makefile
|
||||||
|
|
||||||
|
2007/10/08:
|
||||||
|
Added man page
|
||||||
|
|
||||||
|
2007/10/02:
|
||||||
|
fixed memory bug in GetUPNPUrls()
|
||||||
|
|
||||||
|
2007/10/01:
|
||||||
|
fixes in the Makefile
|
||||||
|
Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly.
|
||||||
|
Added SONAME in the shared library to please debian :)
|
||||||
|
fixed MS Windows compilation (minissdpd is not available under MS Windows).
|
||||||
|
|
||||||
|
2007/09/25:
|
||||||
|
small change to Makefile to be able to install in a different location
|
||||||
|
(default is /usr)
|
||||||
|
|
||||||
|
2007/09/24:
|
||||||
|
now compiling both shared and static library
|
||||||
|
|
||||||
|
2007/09/19:
|
||||||
|
Cosmetic changes on upnpc.c
|
||||||
|
|
||||||
|
2007/09/02:
|
||||||
|
adapting to new miniSSDPd (release version ?)
|
||||||
|
|
||||||
|
2007/08/31:
|
||||||
|
Usage of miniSSDPd to skip discovery process.
|
||||||
|
|
||||||
|
2007/08/27:
|
||||||
|
fixed python module to allow compilation with Python older than Python 2.4
|
||||||
|
|
||||||
|
2007/06/12:
|
||||||
|
Added a python module.
|
||||||
|
|
||||||
|
2007/05/19:
|
||||||
|
Fixed compilation under MinGW
|
||||||
|
|
||||||
|
2007/05/15:
|
||||||
|
fixed a memory leak in AddPortMapping()
|
||||||
|
Added testupnpreplyparse executable to check the parsing of
|
||||||
|
upnp soap messages
|
||||||
|
minixml now ignore namespace prefixes.
|
||||||
|
|
||||||
|
2007/04/26:
|
||||||
|
upnpc now displays external ip address with -s or -l
|
||||||
|
|
||||||
|
2007/04/11:
|
||||||
|
changed MINIUPNPC_URL_MAXSIZE to 128 to accomodate the "BT Voyager 210"
|
||||||
|
|
||||||
|
2007/03/19:
|
||||||
|
cleanup in miniwget.c
|
||||||
|
|
||||||
|
2007/03/01:
|
||||||
|
Small typo fix...
|
||||||
|
|
||||||
|
2007/01/30:
|
||||||
|
Now parsing the HTTP header from SOAP responses in order to
|
||||||
|
get content-length value.
|
||||||
|
|
||||||
|
2007/01/29:
|
||||||
|
Fixed the Soap Query to speedup the HTTP request.
|
||||||
|
added some Win32 DLL stuff...
|
||||||
|
|
||||||
|
2007/01/27:
|
||||||
|
Fixed some WIN32 compatibility issues
|
||||||
|
|
||||||
|
2006/12/14:
|
||||||
|
Added UPNPIGD_IsConnected() function in miniupnp.c/.h
|
||||||
|
Added UPNP_GetValidIGD() in miniupnp.c/.h
|
||||||
|
cleaned upnpc.c main(). now using UPNP_GetValidIGD()
|
||||||
|
|
||||||
|
2006/12/07:
|
||||||
|
Version 1.0-RC1 released
|
||||||
|
|
||||||
|
2006/12/03:
|
||||||
|
Minor changes to compile under SunOS/Solaris
|
||||||
|
|
||||||
|
2006/11/30:
|
||||||
|
made a minixml parser validator program
|
||||||
|
updated minixml to handle attributes correctly
|
||||||
|
|
||||||
|
2006/11/22:
|
||||||
|
Added a -r option to the upnpc sample thanks to Alexander Hubmann.
|
||||||
|
|
||||||
|
2006/11/19:
|
||||||
|
Cleanup code to make it more ANSI C compliant
|
||||||
|
|
||||||
|
2006/11/10:
|
||||||
|
detect and display local lan address.
|
||||||
|
|
||||||
|
2006/11/04:
|
||||||
|
Packets and Bytes Sent/Received are now unsigned int.
|
||||||
|
|
||||||
|
2006/11/01:
|
||||||
|
Bug fix thanks to Giuseppe D'Angelo
|
||||||
|
|
||||||
|
2006/10/31:
|
||||||
|
C++ compatibility for .h files.
|
||||||
|
Added a way to get ip Address on the LAN used to reach the IGD.
|
||||||
|
|
||||||
|
2006/10/25:
|
||||||
|
Added M-SEARCH to the services in the discovery process.
|
||||||
|
|
||||||
|
2006/10/22:
|
||||||
|
updated the Makefile to use makedepend, added a "make install"
|
||||||
|
update Makefile
|
||||||
|
|
||||||
|
2006/10/20:
|
||||||
|
fixing the description url parsing thanks to patch sent by
|
||||||
|
Wayne Dawe.
|
||||||
|
Fixed/translated some comments.
|
||||||
|
Implemented a better discover process, first looking
|
||||||
|
for IGD then for root devices (as some devices only reply to
|
||||||
|
M-SEARCH for root devices).
|
||||||
|
|
||||||
|
2006/09/02:
|
||||||
|
added freeUPNPDevlist() function.
|
||||||
|
|
||||||
|
2006/08/04:
|
||||||
|
More command line arguments checking
|
||||||
|
|
||||||
|
2006/08/01:
|
||||||
|
Added the .bat file to compile under Win32 with minGW32
|
||||||
|
|
||||||
|
2006/07/31:
|
||||||
|
Fixed the rootdesc parser (igd_desc_parse.c)
|
||||||
|
|
||||||
|
2006/07/20:
|
||||||
|
parseMSEARCHReply() is now returning the ST: line as well
|
||||||
|
starting changes to detect several UPnP devices on the network
|
||||||
|
|
||||||
|
2006/07/19:
|
||||||
|
using GetCommonLinkProperties to get down/upload bitrate
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
MiniUPnPc
|
||||||
|
Copyright (c) 2005-2011, Thomas BERNARD
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
include README
|
||||||
|
include miniupnpcmodule.c
|
||||||
|
include setup.py
|
||||||
|
include *.h
|
||||||
|
include libminiupnpc.a
|
|
@ -0,0 +1,319 @@
|
||||||
|
# $Id: Makefile,v 1.107 2014/01/31 14:19:12 nanard Exp $
|
||||||
|
# MiniUPnP Project
|
||||||
|
# http://miniupnp.free.fr/
|
||||||
|
# http://miniupnp.tuxfamily.org/
|
||||||
|
# https://github.com/miniupnp/miniupnp
|
||||||
|
# (c) 2005-2014 Thomas Bernard
|
||||||
|
# to install use :
|
||||||
|
# $ make DESTDIR=/tmp/dummylocation install
|
||||||
|
# or
|
||||||
|
# $ INSTALLPREFIX=/usr/local make install
|
||||||
|
# or
|
||||||
|
# $ make install (default INSTALLPREFIX is /usr)
|
||||||
|
OS = $(shell uname -s)
|
||||||
|
VERSION = $(shell cat VERSION)
|
||||||
|
|
||||||
|
ifeq ($(OS), Darwin)
|
||||||
|
JARSUFFIX=mac
|
||||||
|
endif
|
||||||
|
ifeq ($(OS), Linux)
|
||||||
|
JARSUFFIX=linux
|
||||||
|
endif
|
||||||
|
ifneq (,$(findstring NT-5.1,$(OS)))
|
||||||
|
JARSUFFIX=win32
|
||||||
|
endif
|
||||||
|
|
||||||
|
HAVE_IPV6 ?= yes
|
||||||
|
export HAVE_IPV6
|
||||||
|
|
||||||
|
CC ?= gcc
|
||||||
|
#AR = gar
|
||||||
|
#CFLAGS = -O -g -DDEBUG
|
||||||
|
CFLAGS ?= -O
|
||||||
|
CFLAGS += -Wall
|
||||||
|
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
|
||||||
|
# -DNO_GETADDRINFO
|
||||||
|
INSTALL = install
|
||||||
|
SH = /bin/sh
|
||||||
|
JAVA = java
|
||||||
|
# see http://code.google.com/p/jnaerator/
|
||||||
|
#JNAERATOR = jnaerator-0.9.7.jar
|
||||||
|
#JNAERATOR = jnaerator-0.9.8-shaded.jar
|
||||||
|
#JNAERATORARGS = -library miniupnpc
|
||||||
|
#JNAERATOR = jnaerator-0.10-shaded.jar
|
||||||
|
JNAERATOR = jnaerator-0.11-shaded.jar
|
||||||
|
JNAERATORARGS = -mode StandaloneJar -runtime JNAerator -library miniupnpc
|
||||||
|
JNAERATORBASEURL = http://jnaerator.googlecode.com/files/
|
||||||
|
|
||||||
|
ifeq (SunOS, $(OS))
|
||||||
|
LDFLAGS=-lsocket -lnsl -lresolv
|
||||||
|
endif
|
||||||
|
|
||||||
|
# APIVERSION is used to build SONAME
|
||||||
|
APIVERSION = 10
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ifneq ($(OS), AmigaOS)
|
||||||
|
CFLAGS := -fPIC $(CFLAGS)
|
||||||
|
LIBOBJS := $(LIBOBJS) minissdpc.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||||
|
|
||||||
|
# HEADERS to install
|
||||||
|
HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \
|
||||||
|
upnpreplyparse.h upnperrors.h miniupnpctypes.h \
|
||||||
|
portlistingparse.h \
|
||||||
|
declspec.h
|
||||||
|
|
||||||
|
# library names
|
||||||
|
LIBRARY = libminiupnpc.a
|
||||||
|
ifeq ($(OS), Darwin)
|
||||||
|
SHAREDLIBRARY = libminiupnpc.dylib
|
||||||
|
SONAME = $(basename $(SHAREDLIBRARY)).$(APIVERSION).dylib
|
||||||
|
CFLAGS := -DMACOSX -D_DARWIN_C_SOURCE $(CFLAGS)
|
||||||
|
else
|
||||||
|
ifeq ($(JARSUFFIX), win32)
|
||||||
|
SHAREDLIBRARY = miniupnpc.dll
|
||||||
|
else
|
||||||
|
# Linux/BSD/etc.
|
||||||
|
SHAREDLIBRARY = libminiupnpc.so
|
||||||
|
SONAME = $(SHAREDLIBRARY).$(APIVERSION)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
EXECUTABLES = upnpc-static
|
||||||
|
EXECUTABLES_ADDTESTS = testminixml minixmlvalid testupnpreplyparse \
|
||||||
|
testigddescparse testminiwget
|
||||||
|
|
||||||
|
TESTMINIXMLOBJS = minixml.o igd_desc_parse.o testminixml.o
|
||||||
|
|
||||||
|
TESTMINIWGETOBJS = miniwget.o testminiwget.o connecthostport.o receivedata.o
|
||||||
|
|
||||||
|
TESTUPNPREPLYPARSE = testupnpreplyparse.o minixml.o upnpreplyparse.o
|
||||||
|
|
||||||
|
TESTIGDDESCPARSE = testigddescparse.o igd_desc_parse.o minixml.o \
|
||||||
|
miniupnpc.o miniwget.o upnpcommands.o upnpreplyparse.o \
|
||||||
|
minisoap.o connecthostport.o receivedata.o \
|
||||||
|
portlistingparse.o
|
||||||
|
|
||||||
|
ifneq ($(OS), AmigaOS)
|
||||||
|
EXECUTABLES := $(EXECUTABLES) upnpc-shared
|
||||||
|
TESTMINIWGETOBJS := $(TESTMINIWGETOBJS) minissdpc.o
|
||||||
|
TESTIGDDESCPARSE := $(TESTIGDDESCPARSE) minissdpc.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
LIBDIR ?= lib
|
||||||
|
# install directories
|
||||||
|
INSTALLPREFIX ?= $(PREFIX)/usr
|
||||||
|
INSTALLDIRINC = $(INSTALLPREFIX)/include/miniupnpc
|
||||||
|
INSTALLDIRLIB = $(INSTALLPREFIX)/$(LIBDIR)
|
||||||
|
INSTALLDIRBIN = $(INSTALLPREFIX)/bin
|
||||||
|
INSTALLDIRMAN = $(INSTALLPREFIX)/share/man
|
||||||
|
|
||||||
|
FILESTOINSTALL = $(LIBRARY) $(EXECUTABLES)
|
||||||
|
ifneq ($(OS), AmigaOS)
|
||||||
|
FILESTOINSTALL := $(FILESTOINSTALL) $(SHAREDLIBRARY)
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: install clean depend all check test everything \
|
||||||
|
installpythonmodule updateversion
|
||||||
|
# validateminixml validateminiwget
|
||||||
|
|
||||||
|
all: $(LIBRARY) $(EXECUTABLES)
|
||||||
|
|
||||||
|
test: check
|
||||||
|
|
||||||
|
check: validateminixml validateminiwget validateupnpreplyparse
|
||||||
|
|
||||||
|
everything: all $(EXECUTABLES_ADDTESTS)
|
||||||
|
|
||||||
|
pythonmodule: $(LIBRARY) miniupnpcmodule.c setup.py
|
||||||
|
python setup.py build
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
installpythonmodule: pythonmodule
|
||||||
|
python setup.py install
|
||||||
|
|
||||||
|
pythonmodule3: $(LIBRARY) miniupnpcmodule.c setup.py
|
||||||
|
python3 setup.py build
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
installpythonmodule3: pythonmodule3
|
||||||
|
python3 setup.py install
|
||||||
|
|
||||||
|
validateminixml: minixmlvalid
|
||||||
|
@echo "minixml validation test"
|
||||||
|
./minixmlvalid
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
validateminiwget: testminiwget minihttptestserver testminiwget.sh
|
||||||
|
@echo "miniwget validation test"
|
||||||
|
./testminiwget.sh
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
validateupnpreplyparse: testupnpreplyparse testupnpreplyparse.sh
|
||||||
|
@echo "upnpreplyparse validation test"
|
||||||
|
./testupnpreplyparse.sh
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h
|
||||||
|
# clean python stuff
|
||||||
|
$(RM) pythonmodule pythonmodule3
|
||||||
|
$(RM) validateminixml validateminiwget validateupnpreplyparse
|
||||||
|
$(RM) -r build/ dist/
|
||||||
|
#python setup.py clean
|
||||||
|
# clean jnaerator stuff
|
||||||
|
$(RM) _jnaerator.* java/miniupnpc_$(OS).jar
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
$(RM) $(JNAERATOR) java/*.jar java/*.class out.errors.txt
|
||||||
|
|
||||||
|
updateversion: miniupnpc.h
|
||||||
|
cp miniupnpc.h miniupnpc.h.bak
|
||||||
|
sed 's/\(.*MINIUPNPC_API_VERSION\s\+\)[0-9]\+/\1$(APIVERSION)/' < miniupnpc.h.bak > miniupnpc.h
|
||||||
|
|
||||||
|
install: updateversion $(FILESTOINSTALL)
|
||||||
|
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC)
|
||||||
|
$(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC)
|
||||||
|
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB)
|
||||||
|
$(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB)
|
||||||
|
ifneq ($(OS), AmigaOS)
|
||||||
|
$(INSTALL) -m 644 $(SHAREDLIBRARY) $(DESTDIR)$(INSTALLDIRLIB)/$(SONAME)
|
||||||
|
ln -fs $(SONAME) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY)
|
||||||
|
endif
|
||||||
|
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN)
|
||||||
|
ifeq ($(OS), AmigaOS)
|
||||||
|
$(INSTALL) -m 755 upnpc-static $(DESTDIR)$(INSTALLDIRBIN)/upnpc
|
||||||
|
else
|
||||||
|
$(INSTALL) -m 755 upnpc-shared $(DESTDIR)$(INSTALLDIRBIN)/upnpc
|
||||||
|
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
|
||||||
|
ifeq ($(OS), Linux)
|
||||||
|
gzip $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
cleaninstall:
|
||||||
|
$(RM) -r $(DESTDIR)$(INSTALLDIRINC)
|
||||||
|
$(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(LIBRARY)
|
||||||
|
$(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY)
|
||||||
|
|
||||||
|
depend:
|
||||||
|
makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null
|
||||||
|
|
||||||
|
$(LIBRARY): $(LIBOBJS)
|
||||||
|
$(AR) crs $@ $?
|
||||||
|
|
||||||
|
$(SHAREDLIBRARY): $(LIBOBJS)
|
||||||
|
ifeq ($(OS), Darwin)
|
||||||
|
# $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(SONAME) -o $@ $^
|
||||||
|
$(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(INSTALLDIRLIB)/$(SONAME) -o $@ $^
|
||||||
|
else
|
||||||
|
$(CC) -shared $(LDFLAGS) -Wl,-soname,$(SONAME) -o $@ $^
|
||||||
|
endif
|
||||||
|
|
||||||
|
upnpc-static: upnpc.o $(LIBRARY)
|
||||||
|
$(CC) $(LDFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
upnpc-shared: upnpc.o $(SHAREDLIBRARY)
|
||||||
|
$(CC) $(LDFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
testminixml: $(TESTMINIXMLOBJS)
|
||||||
|
|
||||||
|
testminiwget: $(TESTMINIWGETOBJS)
|
||||||
|
|
||||||
|
minixmlvalid: minixml.o minixmlvalid.o
|
||||||
|
|
||||||
|
testupnpreplyparse: $(TESTUPNPREPLYPARSE)
|
||||||
|
|
||||||
|
testigddescparse: $(TESTIGDDESCPARSE)
|
||||||
|
|
||||||
|
miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh VERSION
|
||||||
|
$(SH) updateminiupnpcstrings.sh
|
||||||
|
|
||||||
|
# ftp tool supplied with OpenBSD can download files from http.
|
||||||
|
jnaerator-%.jar:
|
||||||
|
wget $(JNAERATORBASEURL)/$@ || \
|
||||||
|
curl -o $@ $(JNAERATORBASEURL)/$@ || \
|
||||||
|
ftp $(JNAERATORBASEURL)/$@
|
||||||
|
|
||||||
|
jar: $(SHAREDLIBRARY) $(JNAERATOR)
|
||||||
|
$(JAVA) -jar $(JNAERATOR) $(JNAERATORARGS) \
|
||||||
|
miniupnpc.h 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
|
||||||
|
|
||||||
|
mvn_install:
|
||||||
|
mvn install:install-file -Dfile=java/miniupnpc_$(JARSUFFIX).jar \
|
||||||
|
-DgroupId=com.github \
|
||||||
|
-DartifactId=miniupnp \
|
||||||
|
-Dversion=$(VERSION) \
|
||||||
|
-Dpackaging=jar \
|
||||||
|
-Dclassifier=$(JARSUFFIX) \
|
||||||
|
-DgeneratePom=true \
|
||||||
|
-DcreateChecksum=true
|
||||||
|
|
||||||
|
# make .deb packages
|
||||||
|
deb: /usr/share/pyshared/stdeb all
|
||||||
|
(python setup.py --command-packages=stdeb.command bdist_deb)
|
||||||
|
|
||||||
|
# install .deb packages
|
||||||
|
ideb:
|
||||||
|
(sudo dpkg -i deb_dist/*.deb)
|
||||||
|
|
||||||
|
/usr/share/pyshared/stdeb: /usr/share/doc/python-all-dev
|
||||||
|
(sudo apt-get install python-stdeb)
|
||||||
|
|
||||||
|
/usr/share/doc/python-all-dev:
|
||||||
|
(sudo apt-get install python-all-dev)
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
||||||
|
connecthostport.o: connecthostport.h
|
||||||
|
receivedata.o: receivedata.h
|
|
@ -0,0 +1,91 @@
|
||||||
|
# $Id: Makefile.mingw,v 1.18 2014/01/17 09:04:01 nanard Exp $
|
||||||
|
# Miniupnp project.
|
||||||
|
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
# (c) 2005-2014 Thomas Bernard
|
||||||
|
# This Makefile is made for MinGW
|
||||||
|
#
|
||||||
|
CC = gcc
|
||||||
|
#CFLAGS = -Wall -g -DDEBUG -D_WIN32_WINNT=0X501
|
||||||
|
CFLAGS = -Wall -Os -DNDEBUG -D_WIN32_WINNT=0X501
|
||||||
|
LDLIBS = -lws2_32 -liphlpapi
|
||||||
|
# -lwsock32
|
||||||
|
# -liphlpapi is needed for GetBestRoute() and GetIpAddrTable()
|
||||||
|
PYTHON=\utils\python25\python
|
||||||
|
OBJS=miniwget.o minixml.o igd_desc_parse.o minisoap.o \
|
||||||
|
miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \
|
||||||
|
connecthostport.o portlistingparse.o receivedata.o
|
||||||
|
OBJSDLL=$(addprefix dll/, $(OBJS))
|
||||||
|
|
||||||
|
all: init upnpc-static upnpc-shared testminixml libminiupnpc.a miniupnpc.dll
|
||||||
|
|
||||||
|
init:
|
||||||
|
mkdir dll
|
||||||
|
echo init > init
|
||||||
|
|
||||||
|
clean:
|
||||||
|
del upnpc testminixml *.o
|
||||||
|
del dll\*.o
|
||||||
|
del *.exe
|
||||||
|
del miniupnpc.dll
|
||||||
|
del libminiupnpc.a
|
||||||
|
|
||||||
|
libminiupnpc.a: $(OBJS)
|
||||||
|
$(AR) cr $@ $?
|
||||||
|
|
||||||
|
pythonmodule: libminiupnpc.a
|
||||||
|
$(PYTHON) setupmingw32.py build --compiler=mingw32
|
||||||
|
$(PYTHON) setupmingw32.py install --skip-build
|
||||||
|
|
||||||
|
miniupnpc.dll: libminiupnpc.a $(OBJSDLL)
|
||||||
|
dllwrap -k --driver-name gcc \
|
||||||
|
--def miniupnpc.def \
|
||||||
|
--output-def miniupnpc.dll.def \
|
||||||
|
--implib miniupnpc.lib -o $@ \
|
||||||
|
$(OBJSDLL) $(LDLIBS)
|
||||||
|
|
||||||
|
miniupnpc.lib: miniupnpc.dll
|
||||||
|
echo $@ generated with $<
|
||||||
|
|
||||||
|
dll/upnpc.o: upnpc.o
|
||||||
|
echo $@ generated with $<
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) $(CFLAGS) -DSTATICLIB -c -o $@ $<
|
||||||
|
$(CC) $(CFLAGS) -DMINIUPNP_EXPORTS -c -o dll/$@ $<
|
||||||
|
|
||||||
|
upnpc.o:
|
||||||
|
$(CC) $(CFLAGS) -DSTATICLIB -c -o $@ $<
|
||||||
|
$(CC) $(CFLAGS) -c -o dll/$@ $<
|
||||||
|
|
||||||
|
# --enable-stdcall-fixup
|
||||||
|
upnpc-static: upnpc.o libminiupnpc.a
|
||||||
|
$(CC) -o $@ $^ $(LDLIBS)
|
||||||
|
|
||||||
|
upnpc-shared: dll/upnpc.o miniupnpc.lib
|
||||||
|
$(CC) -o $@ $^ $(LDLIBS)
|
||||||
|
|
||||||
|
wingenminiupnpcstrings: wingenminiupnpcstrings.o
|
||||||
|
|
||||||
|
wingenminiupnpcstrings.o: wingenminiupnpcstrings.c
|
||||||
|
|
||||||
|
miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings
|
||||||
|
wingenminiupnpcstrings $< $@
|
||||||
|
|
||||||
|
minixml.o: minixml.c minixml.h miniupnpcstrings.h
|
||||||
|
|
||||||
|
upnpc.o: upnpc.c miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h upnpreplyparse.h upnpcommands.h upnperrors.h
|
||||||
|
|
||||||
|
miniwget.o: miniwget.c miniwget.h miniupnpcstrings.h connecthostport.h
|
||||||
|
|
||||||
|
minisoap.o: minisoap.c minisoap.h miniupnpcstrings.h
|
||||||
|
|
||||||
|
miniupnpc.o: miniupnpc.c miniupnpc.h minisoap.h miniwget.h minixml.h
|
||||||
|
|
||||||
|
igd_desc_parse.o: igd_desc_parse.c igd_desc_parse.h
|
||||||
|
|
||||||
|
testminixml: minixml.o igd_desc_parse.o testminixml.c
|
||||||
|
|
||||||
|
upnpreplyparse.o: upnpreplyparse.c upnpreplyparse.h minixml.h
|
||||||
|
|
||||||
|
upnpcommands.o: upnpcommands.c upnpcommands.h upnpreplyparse.h miniupnpc.h portlistingparse.h
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
Project: miniupnp
|
||||||
|
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
|
||||||
|
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).
|
||||||
|
Under win32, to compile with MinGW, type "mingw32make.bat".
|
||||||
|
MS Visual C solution and project files are supplied in the msvc/ subdirectory.
|
||||||
|
|
||||||
|
The compilation is known to work under linux, FreeBSD,
|
||||||
|
OpenBSD, MacOS X, AmigaOS and cygwin.
|
||||||
|
The official AmigaOS4.1 SDK was used for AmigaOS4 and GeekGadgets for AmigaOS3.
|
||||||
|
upx (http://upx.sourceforge.net) is used to compress the win32 .exe files.
|
||||||
|
|
||||||
|
To install the library and headers on the system use :
|
||||||
|
> su
|
||||||
|
> make install
|
||||||
|
> exit
|
||||||
|
|
||||||
|
alternatively, to install into a specific location, use :
|
||||||
|
> INSTALLPREFIX=/usr/local make install
|
||||||
|
|
||||||
|
upnpc.c is a sample client using the libminiupnpc.
|
||||||
|
To use the libminiupnpc in your application, link it with
|
||||||
|
libminiupnpc.a (or .so) and use the following functions found in miniupnpc.h,
|
||||||
|
upnpcommands.h and miniwget.h :
|
||||||
|
- upnpDiscover()
|
||||||
|
- miniwget()
|
||||||
|
- parserootdesc()
|
||||||
|
- GetUPNPUrls()
|
||||||
|
- UPNP_* (calling UPNP methods)
|
||||||
|
|
||||||
|
Note : use #include <miniupnpc/miniupnpc.h> etc... for the includes
|
||||||
|
and -lminiupnpc for the link
|
||||||
|
|
||||||
|
Discovery process is speeded up when MiniSSDPd is running on the machine.
|
||||||
|
|
||||||
|
|
||||||
|
* Python module *
|
||||||
|
|
||||||
|
you can build a python module with 'make pythonmodule'
|
||||||
|
and install it with 'make installpythonmodule'.
|
||||||
|
setup.py (and setupmingw32.py) are included in the distribution.
|
||||||
|
|
||||||
|
|
||||||
|
Feel free to contact me if you have any problem :
|
||||||
|
e-mail : miniupnp@free.fr
|
||||||
|
|
||||||
|
If you are using libminiupnpc in your application, please
|
||||||
|
send me an email !
|
||||||
|
|
||||||
|
For any question, you can use the web forum :
|
||||||
|
http://miniupnp.tuxfamily.org/forum/
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
1.9
|
|
@ -0,0 +1,127 @@
|
||||||
|
$Id: apiversions.txt,v 1.3 2014/01/31 13:14:32 nanard Exp $
|
||||||
|
|
||||||
|
Differences in API between miniUPnPc versions
|
||||||
|
|
||||||
|
====================== miniUPnPc version 1.9 ======================
|
||||||
|
API version 10
|
||||||
|
|
||||||
|
upnpcommands.h:
|
||||||
|
added argument remoteHost to UPNP_GetSpecificPortMappingEntry()
|
||||||
|
|
||||||
|
miniupnpc.h:
|
||||||
|
updated macros :
|
||||||
|
#define MINIUPNPC_VERSION "1.9"
|
||||||
|
#define MINIUPNPC_API_VERSION 10
|
||||||
|
|
||||||
|
====================== miniUPnPc version 1.8 ======================
|
||||||
|
API version 9
|
||||||
|
|
||||||
|
miniupnpc.h:
|
||||||
|
updated macros :
|
||||||
|
#define MINIUPNPC_VERSION "1.8"
|
||||||
|
#define MINIUPNPC_API_VERSION 9
|
||||||
|
added "unsigned int scope_id;" to struct UPNPDev
|
||||||
|
added scope_id argument to GetUPNPUrls()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
====================== miniUPnPc version 1.7 ======================
|
||||||
|
API version 8
|
||||||
|
|
||||||
|
miniupnpc.h :
|
||||||
|
add new macros :
|
||||||
|
#define MINIUPNPC_VERSION "1.7"
|
||||||
|
#define MINIUPNPC_API_VERSION 8
|
||||||
|
add rootdescURL to struct UPNPUrls
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
====================== miniUPnPc version 1.6 ======================
|
||||||
|
API version 8
|
||||||
|
|
||||||
|
Adding support for IPv6.
|
||||||
|
igd_desc_parse.h :
|
||||||
|
struct IGDdatas_service :
|
||||||
|
add char presentationurl[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
struct IGDdatas :
|
||||||
|
add struct IGDdatas_service IPv6FC;
|
||||||
|
miniupnpc.h :
|
||||||
|
new macros :
|
||||||
|
#define UPNPDISCOVER_SUCCESS (0)
|
||||||
|
#define UPNPDISCOVER_UNKNOWN_ERROR (-1)
|
||||||
|
#define UPNPDISCOVER_SOCKET_ERROR (-101)
|
||||||
|
#define UPNPDISCOVER_MEMORY_ERROR (-102)
|
||||||
|
simpleUPnPcommand() prototype changed (but is normaly not used by API users)
|
||||||
|
add arguments ipv6 and error to upnpDiscover() :
|
||||||
|
struct UPNPDev *
|
||||||
|
upnpDiscover(int delay, const char * multicastif,
|
||||||
|
const char * minissdpdsock, int sameport,
|
||||||
|
int ipv6,
|
||||||
|
int * error);
|
||||||
|
add controlURL_6FC member to struct UPNPUrls :
|
||||||
|
struct UPNPUrls {
|
||||||
|
char * controlURL;
|
||||||
|
char * ipcondescURL;
|
||||||
|
char * controlURL_CIF;
|
||||||
|
char * controlURL_6FC;
|
||||||
|
};
|
||||||
|
|
||||||
|
upnpcommands.h :
|
||||||
|
add leaseDuration argument to UPNP_AddPortMapping()
|
||||||
|
add desc, enabled and leaseDuration arguments to UPNP_GetSpecificPortMappingEntry()
|
||||||
|
add UPNP_GetListOfPortMappings() function (IGDv2)
|
||||||
|
add IGDv2 IPv6 related functions :
|
||||||
|
UPNP_GetFirewallStatus()
|
||||||
|
UPNP_GetOutboundPinholeTimeout()
|
||||||
|
UPNP_AddPinhole()
|
||||||
|
UPNP_UpdatePinhole()
|
||||||
|
UPNP_DeletePinhole()
|
||||||
|
UPNP_CheckPinholeWorking()
|
||||||
|
UPNP_GetPinholePackets()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
====================== miniUPnPc version 1.5 ======================
|
||||||
|
API version 5
|
||||||
|
|
||||||
|
new function :
|
||||||
|
int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
|
||||||
|
new macro in upnpcommands.h :
|
||||||
|
#define UPNPCOMMAND_HTTP_ERROR
|
||||||
|
|
||||||
|
====================== miniUPnPc version 1.4 ======================
|
||||||
|
Same API as version 1.3
|
||||||
|
|
||||||
|
====================== miniUPnPc version 1.3 ======================
|
||||||
|
API version 4
|
||||||
|
|
||||||
|
Use UNSIGNED_INTEGER type for
|
||||||
|
UPNP_GetTotalBytesSent(), UPNP_GetTotalBytesReceived(),
|
||||||
|
UPNP_GetTotalPacketsSent(), UPNP_GetTotalPacketsReceived()
|
||||||
|
Add remoteHost argument to UPNP_AddPortMapping() and UPNP_DeletePortMapping()
|
||||||
|
|
||||||
|
====================== miniUPnPc version 1.2 ======================
|
||||||
|
API version 3
|
||||||
|
|
||||||
|
added sameport argument to upnpDiscover()
|
||||||
|
struct UPNPDev *
|
||||||
|
upnpDiscover(int delay, const char * multicastif,
|
||||||
|
const char * minissdpdsock, int sameport);
|
||||||
|
|
||||||
|
====================== miniUPnPc Version 1.1 ======================
|
||||||
|
Same API as 1.0
|
||||||
|
|
||||||
|
|
||||||
|
====================== miniUPnPc Version 1.0 ======================
|
||||||
|
API version 2
|
||||||
|
|
||||||
|
|
||||||
|
struct UPNPDev {
|
||||||
|
struct UPNPDev * pNext;
|
||||||
|
char * descURL;
|
||||||
|
char * st;
|
||||||
|
char buffer[2];
|
||||||
|
};
|
||||||
|
struct UPNPDev * upnpDiscover(int delay, const char * multicastif,
|
||||||
|
const char * minissdpdsock);
|
||||||
|
|
|
@ -0,0 +1,531 @@
|
||||||
|
/* $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_ */
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* $Id: codelength.h,v 1.4 2012/09/27 15:40:29 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas BERNARD
|
||||||
|
* copyright (c) 2005-2011 Thomas Bernard
|
||||||
|
* This software is subjet to the conditions detailed in the
|
||||||
|
* provided LICENCE file. */
|
||||||
|
#ifndef CODELENGTH_H_INCLUDED
|
||||||
|
#define CODELENGTH_H_INCLUDED
|
||||||
|
|
||||||
|
/* Encode length by using 7bit per Byte :
|
||||||
|
* Most significant bit of each byte specifies that the
|
||||||
|
* following byte is part of the code */
|
||||||
|
#define DECODELENGTH(n, p) n = 0; \
|
||||||
|
do { n = (n << 7) | (*p & 0x7f); } \
|
||||||
|
while((*(p++)&0x80) && (n<(1<<25)));
|
||||||
|
|
||||||
|
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
|
||||||
|
n = 0; \
|
||||||
|
do { \
|
||||||
|
if((p) >= (p_limit)) break; \
|
||||||
|
n = (n << 7) | (*(p) & 0x7f); \
|
||||||
|
} while((*((p)++)&0x80) && (n<(1<<25)));
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
|
@ -0,0 +1,261 @@
|
||||||
|
/* $Id: connecthostport.c,v 1.13 2014/03/31 12:36:36 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2010-2014 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution. */
|
||||||
|
|
||||||
|
/* use getaddrinfo() or gethostbyname()
|
||||||
|
* uncomment the following line in order to use gethostbyname() */
|
||||||
|
#ifdef NO_GETADDRINFO
|
||||||
|
#define USE_GETHOSTBYNAME
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <io.h>
|
||||||
|
#define MAXHOSTNAMELEN 64
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define herror
|
||||||
|
#define socklen_t int
|
||||||
|
#else /* #ifdef _WIN32 */
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#define closesocket close
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
|
||||||
|
* during the connect() call */
|
||||||
|
#define MINIUPNPC_IGNORE_EINTR
|
||||||
|
#ifndef USE_GETHOSTBYNAME
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#endif /* #ifndef USE_GETHOSTBYNAME */
|
||||||
|
#endif /* #else _WIN32 */
|
||||||
|
|
||||||
|
/* definition of PRINT_SOCKET_ERROR */
|
||||||
|
#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(__amigaos__) || defined(__amigaos4__)
|
||||||
|
#define herror(A) printf("%s\n", A)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "connecthostport.h"
|
||||||
|
|
||||||
|
#ifndef MAXHOSTNAMELEN
|
||||||
|
#define MAXHOSTNAMELEN 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* connecthostport()
|
||||||
|
* return a socket connected (TCP) to the host and port
|
||||||
|
* or -1 in case of error */
|
||||||
|
int connecthostport(const char * host, unsigned short port,
|
||||||
|
unsigned int scope_id)
|
||||||
|
{
|
||||||
|
int s, n;
|
||||||
|
#ifdef USE_GETHOSTBYNAME
|
||||||
|
struct sockaddr_in dest;
|
||||||
|
struct hostent *hp;
|
||||||
|
#else /* #ifdef USE_GETHOSTBYNAME */
|
||||||
|
char tmp_host[MAXHOSTNAMELEN+1];
|
||||||
|
char port_str[8];
|
||||||
|
struct addrinfo *ai, *p;
|
||||||
|
struct addrinfo hints;
|
||||||
|
#endif /* #ifdef USE_GETHOSTBYNAME */
|
||||||
|
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||||
|
struct timeval timeout;
|
||||||
|
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||||
|
|
||||||
|
#ifdef USE_GETHOSTBYNAME
|
||||||
|
hp = gethostbyname(host);
|
||||||
|
if(hp == NULL)
|
||||||
|
{
|
||||||
|
herror(host);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr));
|
||||||
|
memset(dest.sin_zero, 0, sizeof(dest.sin_zero));
|
||||||
|
s = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
if(s < 0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||||
|
/* setting a 3 seconds timeout for the connect() call */
|
||||||
|
timeout.tv_sec = 3;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("setsockopt");
|
||||||
|
}
|
||||||
|
timeout.tv_sec = 3;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("setsockopt");
|
||||||
|
}
|
||||||
|
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||||
|
dest.sin_family = AF_INET;
|
||||||
|
dest.sin_port = htons(port);
|
||||||
|
n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
|
||||||
|
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||||
|
/* EINTR The system call was interrupted by a signal that was caught
|
||||||
|
* EINPROGRESS The socket is nonblocking and the connection cannot
|
||||||
|
* be completed immediately. */
|
||||||
|
while(n < 0 && (errno == EINTR || errno = EINPROGRESS))
|
||||||
|
{
|
||||||
|
socklen_t len;
|
||||||
|
fd_set wset;
|
||||||
|
int err;
|
||||||
|
FD_ZERO(&wset);
|
||||||
|
FD_SET(s, &wset);
|
||||||
|
if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
/*len = 0;*/
|
||||||
|
/*n = getpeername(s, NULL, &len);*/
|
||||||
|
len = sizeof(err);
|
||||||
|
if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
|
||||||
|
PRINT_SOCKET_ERROR("getsockopt");
|
||||||
|
closesocket(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(err != 0) {
|
||||||
|
errno = err;
|
||||||
|
n = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
|
||||||
|
if(n<0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("connect");
|
||||||
|
closesocket(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else /* #ifdef USE_GETHOSTBYNAME */
|
||||||
|
/* use getaddrinfo() instead of gethostbyname() */
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
/* hints.ai_flags = AI_ADDRCONFIG; */
|
||||||
|
#ifdef AI_NUMERICSERV
|
||||||
|
hints.ai_flags = AI_NUMERICSERV;
|
||||||
|
#endif
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
|
||||||
|
/* hints.ai_protocol = IPPROTO_TCP; */
|
||||||
|
snprintf(port_str, sizeof(port_str), "%hu", port);
|
||||||
|
if(host[0] == '[')
|
||||||
|
{
|
||||||
|
/* literal ip v6 address */
|
||||||
|
int i, j;
|
||||||
|
for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++)
|
||||||
|
{
|
||||||
|
tmp_host[i] = host[j];
|
||||||
|
if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */
|
||||||
|
j+=2; /* skip "25" */
|
||||||
|
}
|
||||||
|
tmp_host[i] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strncpy(tmp_host, host, MAXHOSTNAMELEN);
|
||||||
|
}
|
||||||
|
tmp_host[MAXHOSTNAMELEN] = '\0';
|
||||||
|
n = getaddrinfo(tmp_host, port_str, &hints, &ai);
|
||||||
|
if(n != 0)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
fprintf(stderr, "getaddrinfo() error : %d\n", n);
|
||||||
|
#else
|
||||||
|
fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
s = -1;
|
||||||
|
for(p = ai; p; p = p->ai_next)
|
||||||
|
{
|
||||||
|
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||||
|
if(s < 0)
|
||||||
|
continue;
|
||||||
|
if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) {
|
||||||
|
struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr;
|
||||||
|
addr6->sin6_scope_id = scope_id;
|
||||||
|
}
|
||||||
|
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
|
||||||
|
/* setting a 3 seconds timeout for the connect() call */
|
||||||
|
timeout.tv_sec = 3;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("setsockopt");
|
||||||
|
}
|
||||||
|
timeout.tv_sec = 3;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("setsockopt");
|
||||||
|
}
|
||||||
|
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||||
|
n = connect(s, p->ai_addr, p->ai_addrlen);
|
||||||
|
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||||
|
/* EINTR The system call was interrupted by a signal that was caught
|
||||||
|
* EINPROGRESS The socket is nonblocking and the connection cannot
|
||||||
|
* be completed immediately. */
|
||||||
|
while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
|
||||||
|
{
|
||||||
|
socklen_t len;
|
||||||
|
fd_set wset;
|
||||||
|
int err;
|
||||||
|
FD_ZERO(&wset);
|
||||||
|
FD_SET(s, &wset);
|
||||||
|
if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
/*len = 0;*/
|
||||||
|
/*n = getpeername(s, NULL, &len);*/
|
||||||
|
len = sizeof(err);
|
||||||
|
if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
|
||||||
|
PRINT_SOCKET_ERROR("getsockopt");
|
||||||
|
closesocket(s);
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(err != 0) {
|
||||||
|
errno = err;
|
||||||
|
n = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
|
||||||
|
if(n < 0)
|
||||||
|
{
|
||||||
|
closesocket(s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
if(s < 0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(n < 0)
|
||||||
|
{
|
||||||
|
PRINT_SOCKET_ERROR("connect");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif /* #ifdef USE_GETHOSTBYNAME */
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/* $Id: connecthostport.h,v 1.3 2012/09/27 15:42:10 nanard Exp $ */
|
||||||
|
/* Project: miniupnp
|
||||||
|
* http://miniupnp.free.fr/
|
||||||
|
* Author: Thomas Bernard
|
||||||
|
* Copyright (c) 2010-2012 Thomas Bernard
|
||||||
|
* This software is subjects to the conditions detailed
|
||||||
|
* in the LICENCE file provided within this distribution */
|
||||||
|
#ifndef CONNECTHOSTPORT_H_INCLUDED
|
||||||
|
#define CONNECTHOSTPORT_H_INCLUDED
|
||||||
|
|
||||||
|
/* connecthostport()
|
||||||
|
* return a socket connected (TCP) to the host and port
|
||||||
|
* or -1 in case of error */
|
||||||
|
int connecthostport(const char * host, unsigned short port,
|
||||||
|
unsigned int scope_id);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef DECLSPEC_H_INCLUDED
|
||||||
|
#define DECLSPEC_H_INCLUDED
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(STATICLIB)
|
||||||
|
/* for windows dll */
|
||||||
|
#ifdef MINIUPNP_EXPORTS
|
||||||
|
#define LIBSPEC __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define 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 LIBSPEC __attribute__ ((visibility ("default")))
|
||||||
|
#else
|
||||||
|
#define LIBSPEC
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# $Id: external-ip.sh,v 1.1 2010/08/05 12:57:41 nanard Exp $
|
||||||
|
# (c) 2010 Reuben Hawkins
|
||||||
|
upnpc -s | grep ExternalIPAddress | sed 's/[^0-9\.]//g'
|
|
@ -0,0 +1,125 @@
|
||||||
|
/* $Id: igd_desc_parse.c,v 1.14 2011/04/11 09:19:24 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* http://miniupnp.free.fr/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2010 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution. */
|
||||||
|
|
||||||
|
#include "igd_desc_parse.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Start element handler :
|
||||||
|
* update nesting level counter and copy element name */
|
||||||
|
void IGDstartelt(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||||
|
memcpy( datas->cureltname, name, l);
|
||||||
|
datas->cureltname[l] = '\0';
|
||||||
|
datas->level++;
|
||||||
|
if( (l==7) && !memcmp(name, "service", l) ) {
|
||||||
|
datas->tmp.controlurl[0] = '\0';
|
||||||
|
datas->tmp.eventsuburl[0] = '\0';
|
||||||
|
datas->tmp.scpdurl[0] = '\0';
|
||||||
|
datas->tmp.servicetype[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End element handler :
|
||||||
|
* update nesting level counter and update parser state if
|
||||||
|
* service element is parsed */
|
||||||
|
void IGDendelt(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||||
|
datas->level--;
|
||||||
|
/*printf("endelt %2d %.*s\n", datas->level, l, name);*/
|
||||||
|
if( (l==7) && !memcmp(name, "service", l) )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if( datas->state < 1
|
||||||
|
&& !strcmp(datas->servicetype,
|
||||||
|
// "urn:schemas-upnp-org:service:WANIPConnection:1") )
|
||||||
|
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"))
|
||||||
|
datas->state ++;
|
||||||
|
*/
|
||||||
|
if(0==strcmp(datas->tmp.servicetype,
|
||||||
|
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) {
|
||||||
|
memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||||
|
} else if(0==strcmp(datas->tmp.servicetype,
|
||||||
|
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1")) {
|
||||||
|
memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||||
|
} else if(0==strcmp(datas->tmp.servicetype,
|
||||||
|
"urn:schemas-upnp-org:service:WANIPConnection:1")
|
||||||
|
|| 0==strcmp(datas->tmp.servicetype,
|
||||||
|
"urn:schemas-upnp-org:service:WANPPPConnection:1") ) {
|
||||||
|
if(datas->first.servicetype[0] == '\0') {
|
||||||
|
memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||||
|
} else {
|
||||||
|
memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Data handler :
|
||||||
|
* copy data depending on the current element name and state */
|
||||||
|
void IGDdata(void * d, const char * data, int l)
|
||||||
|
{
|
||||||
|
struct IGDdatas * datas = (struct IGDdatas *)d;
|
||||||
|
char * dstmember = 0;
|
||||||
|
/*printf("%2d %s : %.*s\n",
|
||||||
|
datas->level, datas->cureltname, l, data); */
|
||||||
|
if( !strcmp(datas->cureltname, "URLBase") )
|
||||||
|
dstmember = datas->urlbase;
|
||||||
|
else if( !strcmp(datas->cureltname, "presentationURL") )
|
||||||
|
dstmember = datas->presentationurl;
|
||||||
|
else if( !strcmp(datas->cureltname, "serviceType") )
|
||||||
|
dstmember = datas->tmp.servicetype;
|
||||||
|
else if( !strcmp(datas->cureltname, "controlURL") )
|
||||||
|
dstmember = datas->tmp.controlurl;
|
||||||
|
else if( !strcmp(datas->cureltname, "eventSubURL") )
|
||||||
|
dstmember = datas->tmp.eventsuburl;
|
||||||
|
else if( !strcmp(datas->cureltname, "SCPDURL") )
|
||||||
|
dstmember = datas->tmp.scpdurl;
|
||||||
|
/* else if( !strcmp(datas->cureltname, "deviceType") )
|
||||||
|
dstmember = datas->devicetype_tmp;*/
|
||||||
|
if(dstmember)
|
||||||
|
{
|
||||||
|
if(l>=MINIUPNPC_URL_MAXSIZE)
|
||||||
|
l = MINIUPNPC_URL_MAXSIZE-1;
|
||||||
|
memcpy(dstmember, data, l);
|
||||||
|
dstmember[l] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printIGD(struct IGDdatas * d)
|
||||||
|
{
|
||||||
|
printf("urlbase = '%s'\n", d->urlbase);
|
||||||
|
printf("WAN Device (Common interface config) :\n");
|
||||||
|
/*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/
|
||||||
|
printf(" serviceType = '%s'\n", d->CIF.servicetype);
|
||||||
|
printf(" controlURL = '%s'\n", d->CIF.controlurl);
|
||||||
|
printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl);
|
||||||
|
printf(" SCPDURL = '%s'\n", d->CIF.scpdurl);
|
||||||
|
printf("primary WAN Connection Device (IP or PPP Connection):\n");
|
||||||
|
/*printf(" deviceType = '%s'\n", d->first.devicetype);*/
|
||||||
|
printf(" servicetype = '%s'\n", d->first.servicetype);
|
||||||
|
printf(" controlURL = '%s'\n", d->first.controlurl);
|
||||||
|
printf(" eventSubURL = '%s'\n", d->first.eventsuburl);
|
||||||
|
printf(" SCPDURL = '%s'\n", d->first.scpdurl);
|
||||||
|
printf("secondary WAN Connection Device (IP or PPP Connection):\n");
|
||||||
|
/*printf(" deviceType = '%s'\n", d->second.devicetype);*/
|
||||||
|
printf(" servicetype = '%s'\n", d->second.servicetype);
|
||||||
|
printf(" controlURL = '%s'\n", d->second.controlurl);
|
||||||
|
printf(" eventSubURL = '%s'\n", d->second.eventsuburl);
|
||||||
|
printf(" SCPDURL = '%s'\n", d->second.scpdurl);
|
||||||
|
printf("WAN IPv6 Firewall Control :\n");
|
||||||
|
/*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/
|
||||||
|
printf(" servicetype = '%s'\n", d->IPv6FC.servicetype);
|
||||||
|
printf(" controlURL = '%s'\n", d->IPv6FC.controlurl);
|
||||||
|
printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl);
|
||||||
|
printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* $Id: igd_desc_parse.h,v 1.11 2012/10/16 16:49:02 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* http://miniupnp.free.fr/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2010 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
* */
|
||||||
|
#ifndef IGD_DESC_PARSE_H_INCLUDED
|
||||||
|
#define IGD_DESC_PARSE_H_INCLUDED
|
||||||
|
|
||||||
|
/* Structure to store the result of the parsing of UPnP
|
||||||
|
* descriptions of Internet Gateway Devices */
|
||||||
|
#define MINIUPNPC_URL_MAXSIZE (128)
|
||||||
|
struct IGDdatas_service {
|
||||||
|
char controlurl[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char eventsuburl[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char scpdurl[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char servicetype[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
/*char devicetype[MINIUPNPC_URL_MAXSIZE];*/
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IGDdatas {
|
||||||
|
char cureltname[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char urlbase[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
char presentationurl[MINIUPNPC_URL_MAXSIZE];
|
||||||
|
int level;
|
||||||
|
/*int state;*/
|
||||||
|
/* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
|
||||||
|
struct IGDdatas_service CIF;
|
||||||
|
/* "urn:schemas-upnp-org:service:WANIPConnection:1"
|
||||||
|
* "urn:schemas-upnp-org:service:WANPPPConnection:1" */
|
||||||
|
struct IGDdatas_service first;
|
||||||
|
/* if both WANIPConnection and WANPPPConnection are present */
|
||||||
|
struct IGDdatas_service second;
|
||||||
|
/* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */
|
||||||
|
struct IGDdatas_service IPv6FC;
|
||||||
|
/* tmp */
|
||||||
|
struct IGDdatas_service tmp;
|
||||||
|
};
|
||||||
|
|
||||||
|
void IGDstartelt(void *, const char *, int);
|
||||||
|
void IGDendelt(void *, const char *, int);
|
||||||
|
void IGDdata(void *, const char *, int);
|
||||||
|
void printIGD(struct IGDdatas *);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
|
import fr.free.miniupnp.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author syuu
|
||||||
|
*/
|
||||||
|
public class JavaBridgeTest {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
int UPNP_DELAY = 2000;
|
||||||
|
MiniupnpcLibrary miniupnpc = MiniupnpcLibrary.INSTANCE;
|
||||||
|
UPNPDev devlist = null;
|
||||||
|
UPNPUrls urls = new UPNPUrls();
|
||||||
|
IGDdatas data = new IGDdatas();
|
||||||
|
ByteBuffer lanaddr = ByteBuffer.allocate(16);
|
||||||
|
ByteBuffer intClient = ByteBuffer.allocate(16);
|
||||||
|
ByteBuffer intPort = ByteBuffer.allocate(6);
|
||||||
|
ByteBuffer desc = ByteBuffer.allocate(80);
|
||||||
|
ByteBuffer enabled = ByteBuffer.allocate(4);
|
||||||
|
ByteBuffer leaseDuration = ByteBuffer.allocate(16);
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(args.length < 2) {
|
||||||
|
System.err.println("Usage : java [...] JavaBridgeTest port protocol");
|
||||||
|
System.out.println(" port is numeric, protocol is TCP or UDP");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
devlist = miniupnpc.upnpDiscover(UPNP_DELAY, (String) null, (String) null, 0, 0, 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) {
|
||||||
|
System.out.println("desc: " + device.descURL.getString(0) + " st: " + device.st.getString(0));
|
||||||
|
}
|
||||||
|
if ((i = miniupnpc.UPNP_GetValidIGD(devlist, urls, data, lanaddr, 16)) != 0) {
|
||||||
|
switch (i) {
|
||||||
|
case 1:
|
||||||
|
System.out.println("Found valid IGD : " + urls.controlURL.getString(0));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
System.out.println("Found a (not connected?) IGD : " + urls.controlURL.getString(0));
|
||||||
|
System.out.println("Trying to continue anyway");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
System.out.println("UPnP device found. Is it an IGD ? : " + urls.controlURL.getString(0));
|
||||||
|
System.out.println("Trying to continue anyway");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
System.out.println("Found device (igd ?) : " + urls.controlURL.getString(0));
|
||||||
|
System.out.println("Trying to continue anyway");
|
||||||
|
|
||||||
|
}
|
||||||
|
System.out.println("Local LAN ip address : " + new String(lanaddr.array()));
|
||||||
|
ByteBuffer externalAddress = ByteBuffer.allocate(16);
|
||||||
|
miniupnpc.UPNP_GetExternalIPAddress(urls.controlURL.getString(0),
|
||||||
|
new String(data.first.servicetype), externalAddress);
|
||||||
|
System.out.println("ExternalIPAddress = " + new String(externalAddress.array()));
|
||||||
|
ret = miniupnpc.UPNP_AddPortMapping(
|
||||||
|
urls.controlURL.getString(0), // controlURL
|
||||||
|
new String(data.first.servicetype), // servicetype
|
||||||
|
args[0], // external Port
|
||||||
|
args[0], // internal Port
|
||||||
|
new String(lanaddr.array()), // internal client
|
||||||
|
"added via miniupnpc/JAVA !", // description
|
||||||
|
args[1], // protocol UDP or TCP
|
||||||
|
null, // remote host (useless)
|
||||||
|
"0"); // leaseDuration
|
||||||
|
if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS)
|
||||||
|
System.out.println("AddPortMapping() failed with code " + ret);
|
||||||
|
ret = miniupnpc.UPNP_GetSpecificPortMappingEntry(
|
||||||
|
urls.controlURL.getString(0), new String(data.first.servicetype),
|
||||||
|
args[0], args[1], null, intClient, intPort,
|
||||||
|
desc, enabled, leaseDuration);
|
||||||
|
if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS)
|
||||||
|
System.out.println("GetSpecificPortMappingEntry() failed with code " + ret);
|
||||||
|
System.out.println("InternalIP:Port = " +
|
||||||
|
new String(intClient.array()) + ":" + new String(intPort.array()) +
|
||||||
|
" (" + new String(desc.array()) + ")");
|
||||||
|
ret = miniupnpc.UPNP_DeletePortMapping(
|
||||||
|
urls.controlURL.getString(0),
|
||||||
|
new String(data.first.servicetype),
|
||||||
|
args[0], args[1], null);
|
||||||
|
if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS)
|
||||||
|
System.out.println("DelPortMapping() failed with code " + ret);
|
||||||
|
miniupnpc.FreeUPNPUrls(urls);
|
||||||
|
} else {
|
||||||
|
System.out.println("No valid UPNP Internet Gateway Device found.");
|
||||||
|
}
|
||||||
|
miniupnpc.freeUPNPDevlist(devlist);
|
||||||
|
} else {
|
||||||
|
System.out.println("No IGD UPnP Device found on the network !\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
@echo off
|
||||||
|
set JAVA=java
|
||||||
|
set JAVAC=javac
|
||||||
|
REM notice the semicolon for Windows. Write once, run ... oh nevermind
|
||||||
|
set CP=miniupnpc_win32.jar;.
|
||||||
|
|
||||||
|
%JAVAC% -cp "%CP%" JavaBridgeTest.java || exit 1
|
||||||
|
%JAVA% -cp "%CP%" JavaBridgeTest 12345 UDP || exit 1
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
JAVA=java
|
||||||
|
JAVAC=javac
|
||||||
|
CP=$(for i in *.jar; do echo -n $i:; done).
|
||||||
|
|
||||||
|
$JAVAC -cp $CP JavaBridgeTest.java || exit 1
|
||||||
|
$JAVA -cp $CP JavaBridgeTest 12345 UDP || exit 1
|
|
@ -0,0 +1,52 @@
|
||||||
|
.TH MINIUPNPC 3
|
||||||
|
.SH NAME
|
||||||
|
miniupnpc \- UPnP client library
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.SH DESCRIPTION
|
||||||
|
The miniupnpc library implement the UPnP protocol defined
|
||||||
|
to dialog with Internet Gateway Devices. It also has
|
||||||
|
the ability to use data gathered by minissdpd(1) about
|
||||||
|
UPnP devices up on the network in order to skip the
|
||||||
|
long UPnP device discovery process.
|
||||||
|
.PP
|
||||||
|
At first, upnpDiscover(3) has to be used to discover UPnP IGD present
|
||||||
|
on the network. Then UPNP_GetValidIGD(3) to select the right one.
|
||||||
|
Alternatively, UPNP_GetIGDFromUrl(3) could be used to bypass discovery
|
||||||
|
process if the root description url of the device to use is known.
|
||||||
|
Then all the UPNP_* functions can be used, such as
|
||||||
|
UPNP_GetConnectionTypeInfo(3), UPNP_AddPortMapping(3), etc...
|
||||||
|
.SH "HEADER FILES"
|
||||||
|
.IP miniupnpc.h
|
||||||
|
That's the main header file for the miniupnpc library API.
|
||||||
|
It contains all the functions and structures related to device discovery.
|
||||||
|
.IP upnpcommands.h
|
||||||
|
This header file contain the UPnP IGD methods that are accessible
|
||||||
|
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);"
|
||||||
|
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 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().
|
||||||
|
.IP "int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen);"
|
||||||
|
browse the list of device returned by upnpDiscover(), find
|
||||||
|
a live UPnP internet gateway device and fill structures passed as arguments
|
||||||
|
with data used for UPNP methods invokation.
|
||||||
|
.IP "int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen);"
|
||||||
|
permit to bypass the upnpDiscover() call if the xml root description
|
||||||
|
URL of the UPnP IGD is known.
|
||||||
|
Fill structures passed as arguments
|
||||||
|
with data used for UPNP methods invokation.
|
||||||
|
.IP "void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *);"
|
||||||
|
.IP "void FreeUPNPUrls(struct UPNPUrls *);"
|
||||||
|
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
minissdpd(1)
|
||||||
|
.SH BUGS
|
|
@ -0,0 +1,8 @@
|
||||||
|
@mingw32-make -f Makefile.mingw %1
|
||||||
|
@if errorlevel 1 goto end
|
||||||
|
@if not exist upnpc-static.exe goto end
|
||||||
|
@strip upnpc-static.exe
|
||||||
|
@upx --best upnpc-static.exe
|
||||||
|
@strip upnpc-shared.exe
|
||||||
|
@upx --best upnpc-shared.exe
|
||||||
|
:end
|
|
@ -0,0 +1,486 @@
|
||||||
|
/* $Id: minihttptestserver.c,v 1.13 2012/05/29 13:03:07 nanard Exp $ */
|
||||||
|
/* Project : miniUPnP
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2011-2012 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
* */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define CRAP_LENGTH (2048)
|
||||||
|
|
||||||
|
volatile sig_atomic_t quit = 0;
|
||||||
|
volatile sig_atomic_t child_to_wait_for = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* signal handler for SIGCHLD (child status has changed)
|
||||||
|
*/
|
||||||
|
void handle_signal_chld(int sig)
|
||||||
|
{
|
||||||
|
printf("handle_signal_chld(%d)\n", sig);
|
||||||
|
++child_to_wait_for;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* signal handler for SIGINT (CRTL C)
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
void handle_signal_int(int sig)
|
||||||
|
{
|
||||||
|
printf("handle_signal_int(%d)\n", sig);
|
||||||
|
quit = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build a text/plain content of the specified length
|
||||||
|
*/
|
||||||
|
void build_content(char * p, int n)
|
||||||
|
{
|
||||||
|
char line_buffer[80];
|
||||||
|
int k;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while(n > 0) {
|
||||||
|
k = snprintf(line_buffer, sizeof(line_buffer),
|
||||||
|
"%04d_ABCDEFGHIJKL_This_line_is_64_bytes_long_ABCDEFGHIJKL_%04d\r\n",
|
||||||
|
i, i);
|
||||||
|
if(k != 64) {
|
||||||
|
fprintf(stderr, "snprintf() returned %d in build_content()\n", k);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
if(n >= 64) {
|
||||||
|
memcpy(p, line_buffer, 64);
|
||||||
|
p += 64;
|
||||||
|
n -= 64;
|
||||||
|
} else {
|
||||||
|
memcpy(p, line_buffer, n);
|
||||||
|
p += n;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build crappy content
|
||||||
|
*/
|
||||||
|
void build_crap(char * p, int n)
|
||||||
|
{
|
||||||
|
static const char crap[] = "_CRAP_\r\n";
|
||||||
|
int i;
|
||||||
|
|
||||||
|
while(n > 0) {
|
||||||
|
i = sizeof(crap) - 1;
|
||||||
|
if(i > n)
|
||||||
|
i = n;
|
||||||
|
memcpy(p, crap, i);
|
||||||
|
p += i;
|
||||||
|
n -= i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build chunked response.
|
||||||
|
* return a malloc'ed buffer
|
||||||
|
*/
|
||||||
|
char * build_chunked_response(int content_length, int * response_len) {
|
||||||
|
char * response_buffer;
|
||||||
|
char * content_buffer;
|
||||||
|
int buffer_length;
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
/* allocate to have some margin */
|
||||||
|
buffer_length = 256 + content_length + (content_length >> 4);
|
||||||
|
response_buffer = malloc(buffer_length);
|
||||||
|
*response_len = snprintf(response_buffer, buffer_length,
|
||||||
|
"HTTP/1.1 200 OK\r\n"
|
||||||
|
"Content-Type: text/plain\r\n"
|
||||||
|
"Transfer-Encoding: chunked\r\n"
|
||||||
|
"\r\n");
|
||||||
|
|
||||||
|
/* build the content */
|
||||||
|
content_buffer = malloc(content_length);
|
||||||
|
build_content(content_buffer, content_length);
|
||||||
|
|
||||||
|
/* chunk it */
|
||||||
|
i = 0;
|
||||||
|
while(i < content_length) {
|
||||||
|
n = (rand() % 199) + 1;
|
||||||
|
if(i + n > content_length) {
|
||||||
|
n = content_length - i;
|
||||||
|
}
|
||||||
|
/* TODO : check buffer size ! */
|
||||||
|
*response_len += snprintf(response_buffer + *response_len,
|
||||||
|
buffer_length - *response_len,
|
||||||
|
"%x\r\n", n);
|
||||||
|
memcpy(response_buffer + *response_len, content_buffer + i, n);
|
||||||
|
*response_len += n;
|
||||||
|
i += n;
|
||||||
|
response_buffer[(*response_len)++] = '\r';
|
||||||
|
response_buffer[(*response_len)++] = '\n';
|
||||||
|
}
|
||||||
|
/* the last chunk : "0\r\n" a empty body and then
|
||||||
|
* the final "\r\n" */
|
||||||
|
memcpy(response_buffer + *response_len, "0\r\n\r\n", 5);
|
||||||
|
*response_len += 5;
|
||||||
|
free(content_buffer);
|
||||||
|
|
||||||
|
printf("resp_length=%d buffer_length=%d content_length=%d\n",
|
||||||
|
*response_len, buffer_length, content_length);
|
||||||
|
return response_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum modes { MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL };
|
||||||
|
const struct {
|
||||||
|
const enum modes mode;
|
||||||
|
const char * text;
|
||||||
|
} modes_array[] = {
|
||||||
|
{MODE_CHUNKED, "chunked"},
|
||||||
|
{MODE_ADDCRAP, "addcrap"},
|
||||||
|
{MODE_NORMAL, "normal"},
|
||||||
|
{MODE_INVALID, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* write the response with random behaviour !
|
||||||
|
*/
|
||||||
|
void send_response(int c, const char * buffer, int len)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
while(len > 0) {
|
||||||
|
n = (rand() % 99) + 1;
|
||||||
|
if(n > len)
|
||||||
|
n = len;
|
||||||
|
n = write(c, buffer, n);
|
||||||
|
if(n < 0) {
|
||||||
|
if(errno != EINTR) {
|
||||||
|
perror("write");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* if errno == EINTR, try again */
|
||||||
|
} else {
|
||||||
|
len -= n;
|
||||||
|
buffer += n;
|
||||||
|
}
|
||||||
|
usleep(10000); /* 10ms */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle the HTTP connection
|
||||||
|
*/
|
||||||
|
void handle_http_connection(int c)
|
||||||
|
{
|
||||||
|
char request_buffer[2048];
|
||||||
|
int request_len = 0;
|
||||||
|
int headers_found = 0;
|
||||||
|
int n, i;
|
||||||
|
char request_method[16];
|
||||||
|
char request_uri[256];
|
||||||
|
char http_version[16];
|
||||||
|
char * p;
|
||||||
|
char * response_buffer;
|
||||||
|
int response_len;
|
||||||
|
enum modes mode;
|
||||||
|
int content_length = 16*1024;
|
||||||
|
|
||||||
|
/* read the request */
|
||||||
|
while(request_len < (int)sizeof(request_buffer) && !headers_found) {
|
||||||
|
n = read(c,
|
||||||
|
request_buffer + request_len,
|
||||||
|
sizeof(request_buffer) - request_len);
|
||||||
|
if(n < 0) {
|
||||||
|
perror("read");
|
||||||
|
return;
|
||||||
|
} else if(n==0) {
|
||||||
|
/* remote host closed the connection */
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
request_len += n;
|
||||||
|
for(i = 0; i < request_len - 3; i++) {
|
||||||
|
if(0 == memcmp(request_buffer + i, "\r\n\r\n", 4)) {
|
||||||
|
/* found the end of headers */
|
||||||
|
headers_found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!headers_found) {
|
||||||
|
/* error */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("headers :\n%.*s", request_len, request_buffer);
|
||||||
|
/* the request have been received, now parse the request line */
|
||||||
|
p = request_buffer;
|
||||||
|
for(i = 0; i < (int)sizeof(request_method) - 1; i++) {
|
||||||
|
if(*p == ' ' || *p == '\r')
|
||||||
|
break;
|
||||||
|
request_method[i] = *p;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
request_method[i] = '\0';
|
||||||
|
while(*p == ' ')
|
||||||
|
p++;
|
||||||
|
for(i = 0; i < (int)sizeof(request_uri) - 1; i++) {
|
||||||
|
if(*p == ' ' || *p == '\r')
|
||||||
|
break;
|
||||||
|
request_uri[i] = *p;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
request_uri[i] = '\0';
|
||||||
|
while(*p == ' ')
|
||||||
|
p++;
|
||||||
|
for(i = 0; i < (int)sizeof(http_version) - 1; i++) {
|
||||||
|
if(*p == ' ' || *p == '\r')
|
||||||
|
break;
|
||||||
|
http_version[i] = *p;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
http_version[i] = '\0';
|
||||||
|
printf("Method = %s, URI = %s, %s\n",
|
||||||
|
request_method, request_uri, http_version);
|
||||||
|
/* check if the request method is allowed */
|
||||||
|
if(0 != strcmp(request_method, "GET")) {
|
||||||
|
const char response405[] = "HTTP/1.1 405 Method Not Allowed\r\n"
|
||||||
|
"Allow: GET\r\n\r\n";
|
||||||
|
const char * pc;
|
||||||
|
/* 405 Method Not Allowed */
|
||||||
|
/* The response MUST include an Allow header containing a list
|
||||||
|
* of valid methods for the requested resource. */
|
||||||
|
n = sizeof(response405) - 1;
|
||||||
|
pc = response405;
|
||||||
|
while(n > 0) {
|
||||||
|
i = write(c, pc, n);
|
||||||
|
if(i<0) {
|
||||||
|
if(errno != EINTR) {
|
||||||
|
perror("write");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n -= i;
|
||||||
|
pc += i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode = MODE_INVALID;
|
||||||
|
/* use the request URI to know what to do */
|
||||||
|
for(i = 0; modes_array[i].mode != MODE_INVALID; i++) {
|
||||||
|
if(strstr(request_uri, modes_array[i].text)) {
|
||||||
|
mode = modes_array[i].mode; /* found */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(mode) {
|
||||||
|
case MODE_CHUNKED:
|
||||||
|
response_buffer = build_chunked_response(content_length, &response_len);
|
||||||
|
break;
|
||||||
|
case MODE_ADDCRAP:
|
||||||
|
response_len = content_length+256;
|
||||||
|
response_buffer = malloc(response_len);
|
||||||
|
n = snprintf(response_buffer, response_len,
|
||||||
|
"HTTP/1.1 200 OK\r\n"
|
||||||
|
"Server: minihttptestserver\r\n"
|
||||||
|
"Content-Type: text/plain\r\n"
|
||||||
|
"Content-Length: %d\r\n"
|
||||||
|
"\r\n", content_length);
|
||||||
|
response_len = content_length+n+CRAP_LENGTH;
|
||||||
|
response_buffer = realloc(response_buffer, response_len);
|
||||||
|
build_content(response_buffer + n, content_length);
|
||||||
|
build_crap(response_buffer + n + content_length, CRAP_LENGTH);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
response_len = content_length+256;
|
||||||
|
response_buffer = malloc(response_len);
|
||||||
|
n = snprintf(response_buffer, response_len,
|
||||||
|
"HTTP/1.1 200 OK\r\n"
|
||||||
|
"Server: minihttptestserver\r\n"
|
||||||
|
"Content-Type: text/plain\r\n"
|
||||||
|
"\r\n");
|
||||||
|
response_len = content_length+n;
|
||||||
|
response_buffer = realloc(response_buffer, response_len);
|
||||||
|
build_content(response_buffer + n, response_len - n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(response_buffer) {
|
||||||
|
send_response(c, response_buffer, response_len);
|
||||||
|
free(response_buffer);
|
||||||
|
} else {
|
||||||
|
/* Error 500 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
int main(int argc, char * * argv) {
|
||||||
|
int ipv6 = 0;
|
||||||
|
int s, c, i;
|
||||||
|
unsigned short port = 0;
|
||||||
|
struct sockaddr_storage server_addr;
|
||||||
|
socklen_t server_addrlen;
|
||||||
|
struct sockaddr_storage client_addr;
|
||||||
|
socklen_t client_addrlen;
|
||||||
|
pid_t pid;
|
||||||
|
int child = 0;
|
||||||
|
int status;
|
||||||
|
const char * expected_file_name = NULL;
|
||||||
|
|
||||||
|
for(i = 1; i < argc; i++) {
|
||||||
|
if(argv[i][0] == '-') {
|
||||||
|
switch(argv[i][1]) {
|
||||||
|
case '6':
|
||||||
|
ipv6 = 1;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
/* write expected file ! */
|
||||||
|
expected_file_name = argv[++i];
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
/* port */
|
||||||
|
if(++i < argc) {
|
||||||
|
port = (unsigned short)atoi(argv[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "unknown command line switch '%s'\n", argv[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "unkown command line argument '%s'\n", argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
srand(time(NULL));
|
||||||
|
signal(SIGCHLD, handle_signal_chld);
|
||||||
|
#if 0
|
||||||
|
signal(SIGINT, handle_signal_int);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
s = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
|
||||||
|
if(s < 0) {
|
||||||
|
perror("socket");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
memset(&server_addr, 0, sizeof(struct sockaddr_storage));
|
||||||
|
memset(&client_addr, 0, sizeof(struct sockaddr_storage));
|
||||||
|
if(ipv6) {
|
||||||
|
struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr;
|
||||||
|
addr->sin6_family = AF_INET6;
|
||||||
|
addr->sin6_port = htons(port);
|
||||||
|
addr->sin6_addr = in6addr_loopback;
|
||||||
|
} else {
|
||||||
|
struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr;
|
||||||
|
addr->sin_family = AF_INET;
|
||||||
|
addr->sin_port = htons(port);
|
||||||
|
addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
}
|
||||||
|
if(bind(s, (struct sockaddr *)&server_addr,
|
||||||
|
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) < 0) {
|
||||||
|
perror("bind");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(listen(s, 5) < 0) {
|
||||||
|
perror("listen");
|
||||||
|
}
|
||||||
|
if(port == 0) {
|
||||||
|
server_addrlen = sizeof(struct sockaddr_storage);
|
||||||
|
if(getsockname(s, (struct sockaddr *)&server_addr, &server_addrlen) < 0) {
|
||||||
|
perror("getsockname");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(ipv6) {
|
||||||
|
struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr;
|
||||||
|
port = ntohs(addr->sin6_port);
|
||||||
|
} else {
|
||||||
|
struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr;
|
||||||
|
port = ntohs(addr->sin_port);
|
||||||
|
}
|
||||||
|
printf("Listening on port %hu\n", port);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write expected file */
|
||||||
|
if(expected_file_name) {
|
||||||
|
FILE * f;
|
||||||
|
f = fopen(expected_file_name, "wb");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
free(buffer);
|
||||||
|
fclose(f);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "error opening file %s for writing\n", expected_file_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fork() loop */
|
||||||
|
while(!child && !quit) {
|
||||||
|
while(child_to_wait_for > 0) {
|
||||||
|
pid = wait(&status);
|
||||||
|
if(pid < 0) {
|
||||||
|
perror("wait");
|
||||||
|
} else {
|
||||||
|
printf("child(%d) terminated with status %d\n", pid, status);
|
||||||
|
}
|
||||||
|
--child_to_wait_for;
|
||||||
|
}
|
||||||
|
/* TODO : add a select() call in order to handle the case
|
||||||
|
* when a signal is caught */
|
||||||
|
client_addrlen = sizeof(struct sockaddr_storage);
|
||||||
|
c = accept(s, (struct sockaddr *)&client_addr,
|
||||||
|
&client_addrlen);
|
||||||
|
if(c < 0) {
|
||||||
|
perror("accept");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("accept...\n");
|
||||||
|
pid = fork();
|
||||||
|
if(pid < 0) {
|
||||||
|
perror("fork");
|
||||||
|
return 1;
|
||||||
|
} else if(pid == 0) {
|
||||||
|
/* child */
|
||||||
|
child = 1;
|
||||||
|
close(s);
|
||||||
|
s = -1;
|
||||||
|
handle_http_connection(c);
|
||||||
|
}
|
||||||
|
close(c);
|
||||||
|
}
|
||||||
|
if(s >= 0) {
|
||||||
|
close(s);
|
||||||
|
s = -1;
|
||||||
|
}
|
||||||
|
if(!child) {
|
||||||
|
while(child_to_wait_for > 0) {
|
||||||
|
pid = wait(&status);
|
||||||
|
if(pid < 0) {
|
||||||
|
perror("wait");
|
||||||
|
} else {
|
||||||
|
printf("child(%d) terminated with status %d\n", pid, status);
|
||||||
|
}
|
||||||
|
--child_to_wait_for;
|
||||||
|
}
|
||||||
|
printf("Bye...\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
/* $Id: minisoap.c,v 1.22 2012/01/21 13:30:31 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2012 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
*
|
||||||
|
* Minimal SOAP implementation for UPnP protocol.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <io.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
#include "minisoap.h"
|
||||||
|
#include "miniupnpcstrings.h"
|
||||||
|
|
||||||
|
/* only for malloc */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
|
||||||
|
#else
|
||||||
|
#define PRINT_SOCKET_ERROR(x) perror(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* httpWrite sends the headers and the body to the socket
|
||||||
|
* and returns the number of bytes sent */
|
||||||
|
static int
|
||||||
|
httpWrite(int fd, const char * body, int bodysize,
|
||||||
|
const char * headers, int headerssize)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
/*n = write(fd, headers, headerssize);*/
|
||||||
|
/*if(bodysize>0)
|
||||||
|
n += write(fd, body, bodysize);*/
|
||||||
|
/* Note : my old linksys router only took into account
|
||||||
|
* soap request that are sent into only one packet */
|
||||||
|
char * p;
|
||||||
|
/* TODO: AVOID MALLOC */
|
||||||
|
p = malloc(headerssize+bodysize);
|
||||||
|
if(!p)
|
||||||
|
return 0;
|
||||||
|
memcpy(p, headers, headerssize);
|
||||||
|
memcpy(p+headerssize, body, bodysize);
|
||||||
|
/*n = write(fd, p, headerssize+bodysize);*/
|
||||||
|
n = send(fd, p, headerssize+bodysize, 0);
|
||||||
|
if(n<0) {
|
||||||
|
PRINT_SOCKET_ERROR("send");
|
||||||
|
}
|
||||||
|
/* disable send on the socket */
|
||||||
|
/* draytek routers dont seems to like that... */
|
||||||
|
#if 0
|
||||||
|
#ifdef _WIN32
|
||||||
|
if(shutdown(fd, SD_SEND)<0) {
|
||||||
|
#else
|
||||||
|
if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/
|
||||||
|
#endif
|
||||||
|
PRINT_SOCKET_ERROR("shutdown");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
free(p);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* self explanatory */
|
||||||
|
int soapPostSubmit(int fd,
|
||||||
|
const char * url,
|
||||||
|
const char * host,
|
||||||
|
unsigned short port,
|
||||||
|
const char * action,
|
||||||
|
const char * body,
|
||||||
|
const char * httpversion)
|
||||||
|
{
|
||||||
|
int bodysize;
|
||||||
|
char headerbuf[512];
|
||||||
|
int headerssize;
|
||||||
|
char portstr[8];
|
||||||
|
bodysize = (int)strlen(body);
|
||||||
|
/* We are not using keep-alive HTTP connections.
|
||||||
|
* HTTP/1.1 needs the header Connection: close to do that.
|
||||||
|
* This is the default with HTTP/1.0
|
||||||
|
* Using HTTP/1.1 means we need to support chunked transfer-encoding :
|
||||||
|
* When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked
|
||||||
|
* transfer encoding. */
|
||||||
|
/* Connection: Close is normally there only in HTTP/1.1 but who knows */
|
||||||
|
portstr[0] = '\0';
|
||||||
|
if(port != 80)
|
||||||
|
snprintf(portstr, sizeof(portstr), ":%hu", port);
|
||||||
|
headerssize = snprintf(headerbuf, sizeof(headerbuf),
|
||||||
|
"POST %s HTTP/%s\r\n"
|
||||||
|
"Host: %s%s\r\n"
|
||||||
|
"User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
|
||||||
|
"Content-Length: %d\r\n"
|
||||||
|
"Content-Type: text/xml\r\n"
|
||||||
|
"SOAPAction: \"%s\"\r\n"
|
||||||
|
"Connection: Close\r\n"
|
||||||
|
"Cache-Control: no-cache\r\n" /* ??? */
|
||||||
|
"Pragma: no-cache\r\n"
|
||||||
|
"\r\n",
|
||||||
|
url, httpversion, host, portstr, bodysize, action);
|
||||||
|
#ifdef DEBUG
|
||||||
|
/*printf("SOAP request : headersize=%d bodysize=%d\n",
|
||||||
|
headerssize, bodysize);
|
||||||
|
*/
|
||||||
|
printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n",
|
||||||
|
url, httpversion, host, portstr);
|
||||||
|
printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize);
|
||||||
|
printf("Headers :\n%s", headerbuf);
|
||||||
|
printf("Body :\n%s\n", body);
|
||||||
|
#endif
|
||||||
|
return httpWrite(fd, body, bodysize, headerbuf, headerssize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
/* $Id: minisoap.h,v 1.5 2012/09/27 15:42:10 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution. */
|
||||||
|
#ifndef MINISOAP_H_INCLUDED
|
||||||
|
#define MINISOAP_H_INCLUDED
|
||||||
|
|
||||||
|
/*int httpWrite(int, const char *, int, const char *);*/
|
||||||
|
int soapPostSubmit(int, const char *, const char *, unsigned short,
|
||||||
|
const char *, const char *, const char *);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
/* $Id: minissdpc.c,v 1.16 2012/03/05 19:42:46 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Web : http://miniupnp.free.fr/
|
||||||
|
* Author : Thomas BERNARD
|
||||||
|
* copyright (c) 2005-2012 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 <winsock.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
#if defined(__amigaos__) || defined(__amigaos4__)
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
#if defined(__amigaos__)
|
||||||
|
#define uint16_t unsigned short
|
||||||
|
#endif
|
||||||
|
/* Hack */
|
||||||
|
#define UNIX_PATH_LEN 108
|
||||||
|
struct sockaddr_un {
|
||||||
|
uint16_t sun_family;
|
||||||
|
char sun_path[UNIX_PATH_LEN];
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "minissdpc.h"
|
||||||
|
#include "miniupnpc.h"
|
||||||
|
|
||||||
|
#include "codelength.h"
|
||||||
|
|
||||||
|
struct UPNPDev *
|
||||||
|
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
|
||||||
|
{
|
||||||
|
struct UPNPDev * tmp;
|
||||||
|
struct UPNPDev * devlist = NULL;
|
||||||
|
unsigned char buffer[2048];
|
||||||
|
ssize_t n;
|
||||||
|
unsigned char * p;
|
||||||
|
unsigned char * url;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int urlsize, stsize, usnsize, l;
|
||||||
|
int s;
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
|
||||||
|
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if(s < 0)
|
||||||
|
{
|
||||||
|
/*syslog(LOG_ERR, "socket(unix): %m");*/
|
||||||
|
perror("socket(unix)");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path));
|
||||||
|
/* TODO : check if we need to handle the EINTR */
|
||||||
|
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0)
|
||||||
|
{
|
||||||
|
/*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/
|
||||||
|
close(s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
stsize = strlen(devtype);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
memcpy(p, devtype, stsize);
|
||||||
|
p += stsize;
|
||||||
|
if(write(s, buffer, p - buffer) < 0)
|
||||||
|
{
|
||||||
|
/*syslog(LOG_ERR, "write(): %m");*/
|
||||||
|
perror("minissdpc.c: write()");
|
||||||
|
close(s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
n = read(s, buffer, sizeof(buffer));
|
||||||
|
if(n<=0)
|
||||||
|
{
|
||||||
|
perror("minissdpc.c: read()");
|
||||||
|
close(s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
p = buffer + 1;
|
||||||
|
for(i = 0; i < buffer[0]; 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);
|
||||||
|
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;
|
||||||
|
tmp->buffer[urlsize+1+stsize] = '\0';
|
||||||
|
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);
|
||||||
|
return devlist;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
/* $Id: minissdpc.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */
|
||||||
|
/* Project: miniupnp
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* Author: Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2007 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);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,43 @@
|
||||||
|
LIBRARY
|
||||||
|
; miniupnpc library
|
||||||
|
miniupnpc
|
||||||
|
|
||||||
|
EXPORTS
|
||||||
|
; miniupnpc
|
||||||
|
upnpDiscover
|
||||||
|
freeUPNPDevlist
|
||||||
|
parserootdesc
|
||||||
|
UPNP_GetValidIGD
|
||||||
|
UPNP_GetIGDFromUrl
|
||||||
|
GetUPNPUrls
|
||||||
|
FreeUPNPUrls
|
||||||
|
; miniwget
|
||||||
|
miniwget
|
||||||
|
miniwget_getaddr
|
||||||
|
; upnpcommands
|
||||||
|
UPNP_GetTotalBytesSent
|
||||||
|
UPNP_GetTotalBytesReceived
|
||||||
|
UPNP_GetTotalPacketsSent
|
||||||
|
UPNP_GetTotalPacketsReceived
|
||||||
|
UPNP_GetStatusInfo
|
||||||
|
UPNP_GetConnectionTypeInfo
|
||||||
|
UPNP_GetExternalIPAddress
|
||||||
|
UPNP_GetLinkLayerMaxBitRates
|
||||||
|
UPNP_AddPortMapping
|
||||||
|
UPNP_DeletePortMapping
|
||||||
|
UPNP_GetPortMappingNumberOfEntries
|
||||||
|
UPNP_GetSpecificPortMappingEntry
|
||||||
|
UPNP_GetGenericPortMappingEntry
|
||||||
|
UPNP_GetListOfPortMappings
|
||||||
|
UPNP_AddPinhole
|
||||||
|
UPNP_CheckPinholeWorking
|
||||||
|
UPNP_UpdatePinhole
|
||||||
|
UPNP_GetPinholePackets
|
||||||
|
UPNP_DeletePinhole
|
||||||
|
UPNP_GetFirewallStatus
|
||||||
|
UPNP_GetOutboundPinholeTimeout
|
||||||
|
; upnperrors
|
||||||
|
strupnperror
|
||||||
|
; portlistingparse
|
||||||
|
ParsePortListing
|
||||||
|
FreePortListing
|
|
@ -0,0 +1,130 @@
|
||||||
|
/* $Id: miniupnpc.h,v 1.35 2014/01/31 13:26:34 nanard Exp $ */
|
||||||
|
/* Project: miniupnp
|
||||||
|
* http://miniupnp.free.fr/
|
||||||
|
* Author: Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2012 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 "igd_desc_parse.h"
|
||||||
|
|
||||||
|
/* error codes : */
|
||||||
|
#define UPNPDISCOVER_SUCCESS (0)
|
||||||
|
#define UPNPDISCOVER_UNKNOWN_ERROR (-1)
|
||||||
|
#define UPNPDISCOVER_SOCKET_ERROR (-101)
|
||||||
|
#define UPNPDISCOVER_MEMORY_ERROR (-102)
|
||||||
|
|
||||||
|
/* versions : */
|
||||||
|
#define MINIUPNPC_VERSION "1.9.20140401"
|
||||||
|
#define MINIUPNPC_API_VERSION 10
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Structures definitions : */
|
||||||
|
struct UPNParg { const char * elt; const char * val; };
|
||||||
|
|
||||||
|
char *
|
||||||
|
simpleUPnPcommand(int, const char *, const char *,
|
||||||
|
const char *, struct UPNParg *,
|
||||||
|
int *);
|
||||||
|
|
||||||
|
struct UPNPDev {
|
||||||
|
struct UPNPDev * pNext;
|
||||||
|
char * descURL;
|
||||||
|
char * st;
|
||||||
|
unsigned int scope_id;
|
||||||
|
char buffer[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* upnpDiscover()
|
||||||
|
* discover UPnP devices on the network.
|
||||||
|
* The discovered devices are returned as a chained list.
|
||||||
|
* It is up to the caller to free the list with freeUPNPDevlist().
|
||||||
|
* delay (in millisecond) is the maximum time for waiting any device
|
||||||
|
* response.
|
||||||
|
* If available, device list will be obtained from MiniSSDPd.
|
||||||
|
* Default path for minissdpd socket will be used if minissdpdsock argument
|
||||||
|
* is NULL.
|
||||||
|
* If multicastif is not NULL, it will be used instead of the default
|
||||||
|
* multicast interface for sending SSDP discover packets.
|
||||||
|
* If sameport is not null, SSDP packets will be sent from the source port
|
||||||
|
* 1900 (same as destination port) otherwise system assign a source port. */
|
||||||
|
LIBSPEC struct UPNPDev *
|
||||||
|
upnpDiscover(int delay, const char * multicastif,
|
||||||
|
const char * minissdpdsock, int sameport,
|
||||||
|
int ipv6,
|
||||||
|
int * error);
|
||||||
|
/* freeUPNPDevlist()
|
||||||
|
* free list returned by upnpDiscover() */
|
||||||
|
LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
|
||||||
|
|
||||||
|
/* parserootdesc() :
|
||||||
|
* parse root XML description of a UPnP device and fill the IGDdatas
|
||||||
|
* structure. */
|
||||||
|
LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *);
|
||||||
|
|
||||||
|
/* structure used to get fast access to urls
|
||||||
|
* controlURL: controlURL of the WANIPConnection
|
||||||
|
* ipcondescURL: url of the description of the WANIPConnection
|
||||||
|
* controlURL_CIF: controlURL of the WANCommonInterfaceConfig
|
||||||
|
* controlURL_6FC: controlURL of the WANIPv6FirewallControl
|
||||||
|
*/
|
||||||
|
struct UPNPUrls {
|
||||||
|
char * controlURL;
|
||||||
|
char * ipcondescURL;
|
||||||
|
char * controlURL_CIF;
|
||||||
|
char * controlURL_6FC;
|
||||||
|
char * rootdescURL;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* UPNP_GetValidIGD() :
|
||||||
|
* return values :
|
||||||
|
* 0 = NO IGD found
|
||||||
|
* 1 = A valid connected IGD has been found
|
||||||
|
* 2 = A valid IGD has been found but it reported as
|
||||||
|
* not connected
|
||||||
|
* 3 = an UPnP device has been found but was not recognized as an IGD
|
||||||
|
*
|
||||||
|
* In any non zero return case, the urls and data structures
|
||||||
|
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
|
||||||
|
* free allocated memory.
|
||||||
|
*/
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetValidIGD(struct UPNPDev * devlist,
|
||||||
|
struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data,
|
||||||
|
char * lanaddr, int lanaddrlen);
|
||||||
|
|
||||||
|
/* UPNP_GetIGDFromUrl()
|
||||||
|
* Used when skipping the discovery process.
|
||||||
|
* return value :
|
||||||
|
* 0 - Not ok
|
||||||
|
* 1 - OK */
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetIGDFromUrl(const char * rootdescurl,
|
||||||
|
struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data,
|
||||||
|
char * lanaddr, int lanaddrlen);
|
||||||
|
|
||||||
|
LIBSPEC void
|
||||||
|
GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *,
|
||||||
|
const char *, unsigned int);
|
||||||
|
|
||||||
|
LIBSPEC void
|
||||||
|
FreeUPNPUrls(struct UPNPUrls *);
|
||||||
|
|
||||||
|
/* return 0 or 1 */
|
||||||
|
LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,545 @@
|
||||||
|
/* $Id: miniupnpcmodule.c,v 1.22 2014/01/31 13:18:25 nanard Exp $*/
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas BERNARD
|
||||||
|
* website : http://miniupnp.tuxfamily.org/
|
||||||
|
* copyright (c) 2007-2014 Thomas Bernard
|
||||||
|
* This software is subjet to the conditions detailed in the
|
||||||
|
* provided LICENCE file. */
|
||||||
|
#include <Python.h>
|
||||||
|
#define STATICLIB
|
||||||
|
#include "structmember.h"
|
||||||
|
#include "miniupnpc.h"
|
||||||
|
#include "upnpcommands.h"
|
||||||
|
#include "upnperrors.h"
|
||||||
|
|
||||||
|
/* for compatibility with Python < 2.4 */
|
||||||
|
#ifndef Py_RETURN_NONE
|
||||||
|
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef Py_RETURN_TRUE
|
||||||
|
#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef Py_RETURN_FALSE
|
||||||
|
#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* for compatibility with Python < 3.0 */
|
||||||
|
#ifndef PyVarObject_HEAD_INIT
|
||||||
|
#define PyVarObject_HEAD_INIT(type, size) \
|
||||||
|
PyObject_HEAD_INIT(type) size,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef Py_TYPE
|
||||||
|
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
/* Type-specific fields go here. */
|
||||||
|
struct UPNPDev * devlist;
|
||||||
|
struct UPNPUrls urls;
|
||||||
|
struct IGDdatas data;
|
||||||
|
unsigned int discoverdelay; /* value passed to upnpDiscover() */
|
||||||
|
char lanaddr[40]; /* our ip address on the LAN */
|
||||||
|
char * multicastif;
|
||||||
|
char * minissdpdsocket;
|
||||||
|
} UPnPObject;
|
||||||
|
|
||||||
|
static PyMemberDef UPnP_members[] = {
|
||||||
|
{"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr),
|
||||||
|
READONLY, "ip address on the LAN"
|
||||||
|
},
|
||||||
|
{"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay),
|
||||||
|
0/*READWRITE*/, "value in ms used to wait for SSDP responses"
|
||||||
|
},
|
||||||
|
/* 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),
|
||||||
|
0, "path of the MiniSSDPd unix socket"
|
||||||
|
},
|
||||||
|
{NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
UPnPObject_dealloc(UPnPObject *self)
|
||||||
|
{
|
||||||
|
freeUPNPDevlist(self->devlist);
|
||||||
|
FreeUPNPUrls(&self->urls);
|
||||||
|
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
UPnP_discover(UPnPObject *self)
|
||||||
|
{
|
||||||
|
struct UPNPDev * dev;
|
||||||
|
int i;
|
||||||
|
PyObject *res = NULL;
|
||||||
|
if(self->devlist)
|
||||||
|
{
|
||||||
|
freeUPNPDevlist(self->devlist);
|
||||||
|
self->devlist = 0;
|
||||||
|
}
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
|
||||||
|
0/* multicast if*/,
|
||||||
|
0/*minissdpd socket*/,
|
||||||
|
0/*sameport flag*/,
|
||||||
|
0/*ip v6*/,
|
||||||
|
0/*error */);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
/* Py_RETURN_NONE ??? */
|
||||||
|
for(dev = self->devlist, i = 0; dev; dev = dev->pNext)
|
||||||
|
i++;
|
||||||
|
res = Py_BuildValue("i", i);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
UPnP_selectigd(UPnPObject *self)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data,
|
||||||
|
self->lanaddr, sizeof(self->lanaddr));
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if(r)
|
||||||
|
{
|
||||||
|
return Py_BuildValue("s", self->urls.controlURL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* TODO: have our own exception type ! */
|
||||||
|
PyErr_SetString(PyExc_Exception, "No UPnP device discovered");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
UPnP_totalbytesent(UPnPObject *self)
|
||||||
|
{
|
||||||
|
UNSIGNED_INTEGER i;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
|
||||||
|
self->data.CIF.servicetype);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
return Py_BuildValue("I", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
UPnP_totalbytereceived(UPnPObject *self)
|
||||||
|
{
|
||||||
|
UNSIGNED_INTEGER i;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
|
||||||
|
self->data.CIF.servicetype);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
return Py_BuildValue("I", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
UPnP_totalpacketsent(UPnPObject *self)
|
||||||
|
{
|
||||||
|
UNSIGNED_INTEGER i;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
|
||||||
|
self->data.CIF.servicetype);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
return Py_BuildValue("I", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
UPnP_totalpacketreceived(UPnPObject *self)
|
||||||
|
{
|
||||||
|
UNSIGNED_INTEGER i;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
|
||||||
|
self->data.CIF.servicetype);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
return Py_BuildValue("I", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
UPnP_statusinfo(UPnPObject *self)
|
||||||
|
{
|
||||||
|
char status[64];
|
||||||
|
char lastconnerror[64];
|
||||||
|
unsigned int uptime = 0;
|
||||||
|
int r;
|
||||||
|
status[0] = '\0';
|
||||||
|
lastconnerror[0] = '\0';
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype,
|
||||||
|
status, &uptime, lastconnerror);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if(r==UPNPCOMMAND_SUCCESS) {
|
||||||
|
return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);
|
||||||
|
} else {
|
||||||
|
/* TODO: have our own exception type ! */
|
||||||
|
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
UPnP_connectiontype(UPnPObject *self)
|
||||||
|
{
|
||||||
|
char connectionType[64];
|
||||||
|
int r;
|
||||||
|
connectionType[0] = '\0';
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
r = UPNP_GetConnectionTypeInfo(self->urls.controlURL,
|
||||||
|
self->data.first.servicetype,
|
||||||
|
connectionType);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if(r==UPNPCOMMAND_SUCCESS) {
|
||||||
|
return Py_BuildValue("s", connectionType);
|
||||||
|
} else {
|
||||||
|
/* TODO: have our own exception type ! */
|
||||||
|
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
UPnP_externalipaddress(UPnPObject *self)
|
||||||
|
{
|
||||||
|
char externalIPAddress[40];
|
||||||
|
int r;
|
||||||
|
externalIPAddress[0] = '\0';
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
r = UPNP_GetExternalIPAddress(self->urls.controlURL,
|
||||||
|
self->data.first.servicetype,
|
||||||
|
externalIPAddress);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if(r==UPNPCOMMAND_SUCCESS) {
|
||||||
|
return Py_BuildValue("s", externalIPAddress);
|
||||||
|
} else {
|
||||||
|
/* TODO: have our own exception type ! */
|
||||||
|
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc,
|
||||||
|
* remoteHost)
|
||||||
|
* protocol is 'UDP' or 'TCP' */
|
||||||
|
static PyObject *
|
||||||
|
UPnP_addportmapping(UPnPObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
char extPort[6];
|
||||||
|
unsigned short ePort;
|
||||||
|
char inPort[6];
|
||||||
|
unsigned short iPort;
|
||||||
|
const char * proto;
|
||||||
|
const char * host;
|
||||||
|
const char * desc;
|
||||||
|
const char * remoteHost;
|
||||||
|
const char * leaseDuration = "0";
|
||||||
|
int r;
|
||||||
|
if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto,
|
||||||
|
&host, &iPort, &desc, &remoteHost))
|
||||||
|
return NULL;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
sprintf(extPort, "%hu", ePort);
|
||||||
|
sprintf(inPort, "%hu", iPort);
|
||||||
|
r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype,
|
||||||
|
extPort, inPort, host, desc, proto,
|
||||||
|
remoteHost, leaseDuration);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if(r==UPNPCOMMAND_SUCCESS)
|
||||||
|
{
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: RAISE an Exception. See upnpcommands.h for errors codes.
|
||||||
|
// upnperrors.c
|
||||||
|
//Py_RETURN_FALSE;
|
||||||
|
/* TODO: have our own exception type ! */
|
||||||
|
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DeletePortMapping(extPort, proto, removeHost='')
|
||||||
|
* proto = 'UDP', 'TCP' */
|
||||||
|
static PyObject *
|
||||||
|
UPnP_deleteportmapping(UPnPObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
char extPort[6];
|
||||||
|
unsigned short ePort;
|
||||||
|
const char * proto;
|
||||||
|
const char * remoteHost = "";
|
||||||
|
int r;
|
||||||
|
if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
|
||||||
|
return NULL;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
sprintf(extPort, "%hu", ePort);
|
||||||
|
r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype,
|
||||||
|
extPort, proto, remoteHost);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if(r==UPNPCOMMAND_SUCCESS) {
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
} else {
|
||||||
|
/* TODO: have our own exception type ! */
|
||||||
|
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
UPnP_getportmappingnumberofentries(UPnPObject *self)
|
||||||
|
{
|
||||||
|
unsigned int n = 0;
|
||||||
|
int r;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL,
|
||||||
|
self->data.first.servicetype,
|
||||||
|
&n);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if(r==UPNPCOMMAND_SUCCESS) {
|
||||||
|
return Py_BuildValue("I", n);
|
||||||
|
} else {
|
||||||
|
/* TODO: have our own exception type ! */
|
||||||
|
PyErr_SetString(PyExc_Exception, strupnperror(r));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GetSpecificPortMapping(ePort, proto, remoteHost='')
|
||||||
|
* proto = 'UDP' or 'TCP' */
|
||||||
|
static PyObject *
|
||||||
|
UPnP_getspecificportmapping(UPnPObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
char extPort[6];
|
||||||
|
unsigned short ePort;
|
||||||
|
const char * proto;
|
||||||
|
const char * remoteHost = "";
|
||||||
|
char intClient[40];
|
||||||
|
char intPort[6];
|
||||||
|
unsigned short iPort;
|
||||||
|
char desc[80];
|
||||||
|
char enabled[4];
|
||||||
|
char leaseDuration[16];
|
||||||
|
if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
|
||||||
|
return NULL;
|
||||||
|
extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0';
|
||||||
|
desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0';
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
sprintf(extPort, "%hu", ePort);
|
||||||
|
UPNP_GetSpecificPortMappingEntry(self->urls.controlURL,
|
||||||
|
self->data.first.servicetype,
|
||||||
|
extPort, proto, remoteHost,
|
||||||
|
intClient, intPort,
|
||||||
|
desc, enabled, leaseDuration);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if(intClient[0])
|
||||||
|
{
|
||||||
|
iPort = (unsigned short)atoi(intPort);
|
||||||
|
return Py_BuildValue("(s,H,s,O,i)",
|
||||||
|
intClient, iPort, desc,
|
||||||
|
PyBool_FromLong(atoi(enabled)),
|
||||||
|
atoi(leaseDuration));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GetGenericPortMapping(index) */
|
||||||
|
static PyObject *
|
||||||
|
UPnP_getgenericportmapping(UPnPObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
int i, r;
|
||||||
|
char index[8];
|
||||||
|
char intClient[40];
|
||||||
|
char intPort[6];
|
||||||
|
unsigned short iPort;
|
||||||
|
char extPort[6];
|
||||||
|
unsigned short ePort;
|
||||||
|
char protocol[4];
|
||||||
|
char desc[80];
|
||||||
|
char enabled[6];
|
||||||
|
char rHost[64];
|
||||||
|
char duration[16]; /* lease duration */
|
||||||
|
unsigned int dur;
|
||||||
|
if(!PyArg_ParseTuple(args, "i", &i))
|
||||||
|
return NULL;
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
snprintf(index, sizeof(index), "%d", i);
|
||||||
|
rHost[0] = '\0'; enabled[0] = '\0';
|
||||||
|
duration[0] = '\0'; desc[0] = '\0';
|
||||||
|
extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
|
||||||
|
r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL,
|
||||||
|
self->data.first.servicetype,
|
||||||
|
index,
|
||||||
|
extPort, intClient, intPort,
|
||||||
|
protocol, desc, enabled, rHost,
|
||||||
|
duration);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if(r==UPNPCOMMAND_SUCCESS)
|
||||||
|
{
|
||||||
|
ePort = (unsigned short)atoi(extPort);
|
||||||
|
iPort = (unsigned short)atoi(intPort);
|
||||||
|
dur = (unsigned int)strtoul(duration, 0, 0);
|
||||||
|
return Py_BuildValue("(H,s,(s,H),s,s,s,I)",
|
||||||
|
ePort, protocol, intClient, iPort,
|
||||||
|
desc, enabled, rHost, dur);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* miniupnpc.UPnP object Method Table */
|
||||||
|
static PyMethodDef UPnP_methods[] = {
|
||||||
|
{"discover", (PyCFunction)UPnP_discover, METH_NOARGS,
|
||||||
|
"discover UPnP IGD devices on the network"
|
||||||
|
},
|
||||||
|
{"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS,
|
||||||
|
"select a valid UPnP IGD among discovered devices"
|
||||||
|
},
|
||||||
|
{"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS,
|
||||||
|
"return the total number of bytes sent by UPnP IGD"
|
||||||
|
},
|
||||||
|
{"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS,
|
||||||
|
"return the total number of bytes received by UPnP IGD"
|
||||||
|
},
|
||||||
|
{"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS,
|
||||||
|
"return the total number of packets sent by UPnP IGD"
|
||||||
|
},
|
||||||
|
{"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS,
|
||||||
|
"return the total number of packets received by UPnP IGD"
|
||||||
|
},
|
||||||
|
{"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS,
|
||||||
|
"return status and uptime"
|
||||||
|
},
|
||||||
|
{"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS,
|
||||||
|
"return IGD WAN connection type"
|
||||||
|
},
|
||||||
|
{"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS,
|
||||||
|
"return external IP address"
|
||||||
|
},
|
||||||
|
{"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,
|
||||||
|
"add a port mapping"
|
||||||
|
},
|
||||||
|
{"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,
|
||||||
|
"delete a port mapping"
|
||||||
|
},
|
||||||
|
{"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,
|
||||||
|
"-- non standard --"
|
||||||
|
},
|
||||||
|
{"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS,
|
||||||
|
"get details about a specific port mapping entry"
|
||||||
|
},
|
||||||
|
{"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS,
|
||||||
|
"get all details about the port mapping at index"
|
||||||
|
},
|
||||||
|
{NULL} /* Sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyTypeObject UPnPType = {
|
||||||
|
PyVarObject_HEAD_INIT(NULL,
|
||||||
|
0) /*ob_size*/
|
||||||
|
"miniupnpc.UPnP", /*tp_name*/
|
||||||
|
sizeof(UPnPObject), /*tp_basicsize*/
|
||||||
|
0, /*tp_itemsize*/
|
||||||
|
(destructor)UPnPObject_dealloc,/*tp_dealloc*/
|
||||||
|
0, /*tp_print*/
|
||||||
|
0, /*tp_getattr*/
|
||||||
|
0, /*tp_setattr*/
|
||||||
|
0, /*tp_compare*/
|
||||||
|
0, /*tp_repr*/
|
||||||
|
0, /*tp_as_number*/
|
||||||
|
0, /*tp_as_sequence*/
|
||||||
|
0, /*tp_as_mapping*/
|
||||||
|
0, /*tp_hash */
|
||||||
|
0, /*tp_call*/
|
||||||
|
0, /*tp_str*/
|
||||||
|
0, /*tp_getattro*/
|
||||||
|
0, /*tp_setattro*/
|
||||||
|
0, /*tp_as_buffer*/
|
||||||
|
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
||||||
|
"UPnP objects", /* tp_doc */
|
||||||
|
0, /* tp_traverse */
|
||||||
|
0, /* tp_clear */
|
||||||
|
0, /* tp_richcompare */
|
||||||
|
0, /* tp_weaklistoffset */
|
||||||
|
0, /* tp_iter */
|
||||||
|
0, /* tp_iternext */
|
||||||
|
UPnP_methods, /* tp_methods */
|
||||||
|
UPnP_members, /* tp_members */
|
||||||
|
0, /* tp_getset */
|
||||||
|
0, /* tp_base */
|
||||||
|
0, /* tp_dict */
|
||||||
|
0, /* tp_descr_get */
|
||||||
|
0, /* tp_descr_set */
|
||||||
|
0, /* tp_dictoffset */
|
||||||
|
0,/*(initproc)UPnP_init,*/ /* tp_init */
|
||||||
|
0, /* tp_alloc */
|
||||||
|
#ifndef _WIN32
|
||||||
|
PyType_GenericNew,/*UPnP_new,*/ /* tp_new */
|
||||||
|
#else
|
||||||
|
0,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/* module methods */
|
||||||
|
static PyMethodDef miniupnpc_methods[] = {
|
||||||
|
{NULL} /* Sentinel */
|
||||||
|
};
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
static struct PyModuleDef moduledef = {
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
"miniupnpc", /* m_name */
|
||||||
|
"miniupnpc module.", /* m_doc */
|
||||||
|
-1, /* m_size */
|
||||||
|
miniupnpc_methods, /* m_methods */
|
||||||
|
NULL, /* m_reload */
|
||||||
|
NULL, /* m_traverse */
|
||||||
|
NULL, /* m_clear */
|
||||||
|
NULL, /* m_free */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
|
||||||
|
#define PyMODINIT_FUNC void
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PyMODINIT_FUNC
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
PyInit_miniupnpc(void)
|
||||||
|
#else
|
||||||
|
initminiupnpc(void)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
PyObject* m;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
UPnPType.tp_new = PyType_GenericNew;
|
||||||
|
#endif
|
||||||
|
if (PyType_Ready(&UPnPType) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
m = PyModule_Create(&moduledef);
|
||||||
|
#else
|
||||||
|
m = Py_InitModule3("miniupnpc", miniupnpc_methods,
|
||||||
|
"miniupnpc module.");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Py_INCREF(&UPnPType);
|
||||||
|
PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
return m;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef MINIUPNPCSTRINGS_H_INCLUDED
|
||||||
|
#define MINIUPNPCSTRINGS_H_INCLUDED
|
||||||
|
|
||||||
|
#define OS_STRING "${CMAKE_SYSTEM_NAME}"
|
||||||
|
#define MINIUPNPC_VERSION_STRING "${MINIUPNPC_VERSION}"
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,15 @@
|
||||||
|
/* $Id: miniupnpcstrings.h.in,v 1.5 2012/10/16 16:48:26 nanard Exp $ */
|
||||||
|
/* Project: miniupnp
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* Author: Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2011 Thomas Bernard
|
||||||
|
* This software is subjects to the conditions detailed
|
||||||
|
* in the LICENCE file provided within this distribution */
|
||||||
|
#ifndef MINIUPNPCSTRINGS_H_INCLUDED
|
||||||
|
#define MINIUPNPCSTRINGS_H_INCLUDED
|
||||||
|
|
||||||
|
#define OS_STRING "OS/version"
|
||||||
|
#define MINIUPNPC_VERSION_STRING "version"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/* $Id: miniupnpctypes.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */
|
||||||
|
/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2011 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided within this distribution */
|
||||||
|
#ifndef MINIUPNPCTYPES_H_INCLUDED
|
||||||
|
#define MINIUPNPCTYPES_H_INCLUDED
|
||||||
|
|
||||||
|
#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
|
||||||
|
#define UNSIGNED_INTEGER unsigned long long
|
||||||
|
#define STRTOUI strtoull
|
||||||
|
#else
|
||||||
|
#define UNSIGNED_INTEGER unsigned int
|
||||||
|
#define STRTOUI strtoul
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,575 @@
|
||||||
|
/* $Id: miniwget.c,v 1.61 2014/02/05 17:27:48 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Website : http://miniupnp.free.fr/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2014 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution. */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <io.h>
|
||||||
|
#define MAXHOSTNAMELEN 64
|
||||||
|
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define socklen_t int
|
||||||
|
#ifndef strncasecmp
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||||
|
#define strncasecmp _memicmp
|
||||||
|
#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
|
||||||
|
#define strncasecmp memicmp
|
||||||
|
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
|
||||||
|
#endif /* #ifndef strncasecmp */
|
||||||
|
#else /* #ifdef _WIN32 */
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||||
|
#define socklen_t int
|
||||||
|
#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
|
||||||
|
#include <sys/select.h>
|
||||||
|
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#define closesocket close
|
||||||
|
#endif /* #else _WIN32 */
|
||||||
|
#if defined(__sun) || defined(sun)
|
||||||
|
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "miniupnpcstrings.h"
|
||||||
|
#include "miniwget.h"
|
||||||
|
#include "connecthostport.h"
|
||||||
|
#include "receivedata.h"
|
||||||
|
|
||||||
|
#ifndef MAXHOSTNAMELEN
|
||||||
|
#define MAXHOSTNAMELEN 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a HTTP response from a socket.
|
||||||
|
* Process Content-Length and Transfer-encoding headers.
|
||||||
|
* return a pointer to the content buffer, which length is saved
|
||||||
|
* to the length parameter.
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
getHTTPResponse(int s, int * size)
|
||||||
|
{
|
||||||
|
char buf[2048];
|
||||||
|
int n;
|
||||||
|
int endofheaders = 0;
|
||||||
|
int chunked = 0;
|
||||||
|
int content_length = -1;
|
||||||
|
unsigned int chunksize = 0;
|
||||||
|
unsigned int bytestocopy = 0;
|
||||||
|
/* buffers : */
|
||||||
|
char * header_buf;
|
||||||
|
unsigned int header_buf_len = 2048;
|
||||||
|
unsigned int header_buf_used = 0;
|
||||||
|
char * content_buf;
|
||||||
|
unsigned int content_buf_len = 2048;
|
||||||
|
unsigned int content_buf_used = 0;
|
||||||
|
char chunksize_buf[32];
|
||||||
|
unsigned int chunksize_buf_index;
|
||||||
|
|
||||||
|
header_buf = malloc(header_buf_len);
|
||||||
|
content_buf = malloc(content_buf_len);
|
||||||
|
chunksize_buf[0] = '\0';
|
||||||
|
chunksize_buf_index = 0;
|
||||||
|
|
||||||
|
while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0)
|
||||||
|
{
|
||||||
|
if(endofheaders == 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int linestart=0;
|
||||||
|
int colon=0;
|
||||||
|
int valuestart=0;
|
||||||
|
if(header_buf_used + n > header_buf_len) {
|
||||||
|
header_buf = realloc(header_buf, header_buf_used + n);
|
||||||
|
header_buf_len = header_buf_used + n;
|
||||||
|
}
|
||||||
|
memcpy(header_buf + header_buf_used, buf, n);
|
||||||
|
header_buf_used += n;
|
||||||
|
/* search for CR LF CR LF (end of headers)
|
||||||
|
* recognize also LF LF */
|
||||||
|
i = 0;
|
||||||
|
while(i < ((int)header_buf_used-1) && (endofheaders == 0)) {
|
||||||
|
if(header_buf[i] == '\r') {
|
||||||
|
i++;
|
||||||
|
if(header_buf[i] == '\n') {
|
||||||
|
i++;
|
||||||
|
if(i < (int)header_buf_used && header_buf[i] == '\r') {
|
||||||
|
i++;
|
||||||
|
if(i < (int)header_buf_used && header_buf[i] == '\n') {
|
||||||
|
endofheaders = i+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(header_buf[i] == '\n') {
|
||||||
|
i++;
|
||||||
|
if(header_buf[i] == '\n') {
|
||||||
|
endofheaders = i+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if(endofheaders == 0)
|
||||||
|
continue;
|
||||||
|
/* parse header lines */
|
||||||
|
for(i = 0; i < endofheaders - 1; i++) {
|
||||||
|
if(colon <= linestart && header_buf[i]==':')
|
||||||
|
{
|
||||||
|
colon = i;
|
||||||
|
while(i < (endofheaders-1)
|
||||||
|
&& (header_buf[i+1] == ' ' || header_buf[i+1] == '\t'))
|
||||||
|
i++;
|
||||||
|
valuestart = i + 1;
|
||||||
|
}
|
||||||
|
/* detecting end of line */
|
||||||
|
else if(header_buf[i]=='\r' || header_buf[i]=='\n')
|
||||||
|
{
|
||||||
|
if(colon > linestart && valuestart > colon)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("header='%.*s', value='%.*s'\n",
|
||||||
|
colon-linestart, header_buf+linestart,
|
||||||
|
i-valuestart, header_buf+valuestart);
|
||||||
|
#endif
|
||||||
|
if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart))
|
||||||
|
{
|
||||||
|
content_length = atoi(header_buf+valuestart);
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Content-Length: %d\n", content_length);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart)
|
||||||
|
&& 0==strncasecmp(header_buf+valuestart, "chunked", 7))
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("chunked transfer-encoding!\n");
|
||||||
|
#endif
|
||||||
|
chunked = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n'))
|
||||||
|
i++;
|
||||||
|
linestart = i;
|
||||||
|
colon = linestart;
|
||||||
|
valuestart = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* copy the remaining of the received data back to buf */
|
||||||
|
n = header_buf_used - endofheaders;
|
||||||
|
memcpy(buf, header_buf + endofheaders, n);
|
||||||
|
/* if(headers) */
|
||||||
|
}
|
||||||
|
if(endofheaders)
|
||||||
|
{
|
||||||
|
/* content */
|
||||||
|
if(chunked)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while(i < n)
|
||||||
|
{
|
||||||
|
if(chunksize == 0)
|
||||||
|
{
|
||||||
|
/* reading chunk size */
|
||||||
|
if(chunksize_buf_index == 0) {
|
||||||
|
/* skipping any leading CR LF */
|
||||||
|
if(i<n && buf[i] == '\r') i++;
|
||||||
|
if(i<n && buf[i] == '\n') i++;
|
||||||
|
}
|
||||||
|
while(i<n && isxdigit(buf[i])
|
||||||
|
&& chunksize_buf_index < (sizeof(chunksize_buf)-1))
|
||||||
|
{
|
||||||
|
chunksize_buf[chunksize_buf_index++] = buf[i];
|
||||||
|
chunksize_buf[chunksize_buf_index] = '\0';
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
while(i<n && buf[i] != '\r' && buf[i] != '\n')
|
||||||
|
i++; /* discarding chunk-extension */
|
||||||
|
if(i<n && buf[i] == '\r') i++;
|
||||||
|
if(i<n && buf[i] == '\n') {
|
||||||
|
unsigned int j;
|
||||||
|
for(j = 0; j < chunksize_buf_index; j++) {
|
||||||
|
if(chunksize_buf[j] >= '0'
|
||||||
|
&& chunksize_buf[j] <= '9')
|
||||||
|
chunksize = (chunksize << 4) + (chunksize_buf[j] - '0');
|
||||||
|
else
|
||||||
|
chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10);
|
||||||
|
}
|
||||||
|
chunksize_buf[0] = '\0';
|
||||||
|
chunksize_buf_index = 0;
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
/* not finished to get chunksize */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("chunksize = %u (%x)\n", chunksize, chunksize);
|
||||||
|
#endif
|
||||||
|
if(chunksize == 0)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("end of HTTP content - %d %d\n", i, n);
|
||||||
|
/*printf("'%.*s'\n", n-i, buf+i);*/
|
||||||
|
#endif
|
||||||
|
goto end_of_stream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i);
|
||||||
|
if((content_buf_used + bytestocopy) > content_buf_len)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
memcpy(content_buf + content_buf_used, buf + i, bytestocopy);
|
||||||
|
content_buf_used += bytestocopy;
|
||||||
|
i += bytestocopy;
|
||||||
|
chunksize -= bytestocopy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* not chunked */
|
||||||
|
if(content_length > 0
|
||||||
|
&& (int)(content_buf_used + n) > content_length) {
|
||||||
|
/* skipping additional bytes */
|
||||||
|
n = content_length - content_buf_used;
|
||||||
|
}
|
||||||
|
if(content_buf_used + n > content_buf_len)
|
||||||
|
{
|
||||||
|
if(content_length >= (int)(content_buf_used + n)) {
|
||||||
|
content_buf_len = content_length;
|
||||||
|
} else {
|
||||||
|
content_buf_len = content_buf_used + n;
|
||||||
|
}
|
||||||
|
content_buf = (char *)realloc((void *)content_buf,
|
||||||
|
content_buf_len);
|
||||||
|
}
|
||||||
|
memcpy(content_buf + content_buf_used, buf, n);
|
||||||
|
content_buf_used += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* use the Content-Length header value if available */
|
||||||
|
if(content_length > 0 && (int)content_buf_used >= content_length)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("End of HTTP content\n");
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end_of_stream:
|
||||||
|
free(header_buf); header_buf = NULL;
|
||||||
|
*size = content_buf_used;
|
||||||
|
if(content_buf_used == 0)
|
||||||
|
{
|
||||||
|
free(content_buf);
|
||||||
|
content_buf = NULL;
|
||||||
|
}
|
||||||
|
return content_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* miniwget3() :
|
||||||
|
* do all the work.
|
||||||
|
* Return NULL if something failed. */
|
||||||
|
static void *
|
||||||
|
miniwget3(const char * host,
|
||||||
|
unsigned short port, const char * path,
|
||||||
|
int * size, char * addr_str, int addr_str_len,
|
||||||
|
const char * httpversion, unsigned int scope_id)
|
||||||
|
{
|
||||||
|
char buf[2048];
|
||||||
|
int s;
|
||||||
|
int n;
|
||||||
|
int len;
|
||||||
|
int sent;
|
||||||
|
void * content;
|
||||||
|
|
||||||
|
*size = 0;
|
||||||
|
s = connecthostport(host, port, scope_id);
|
||||||
|
if(s < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* get address for caller ! */
|
||||||
|
if(addr_str)
|
||||||
|
{
|
||||||
|
struct sockaddr_storage saddr;
|
||||||
|
socklen_t saddrlen;
|
||||||
|
|
||||||
|
saddrlen = sizeof(saddr);
|
||||||
|
if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0)
|
||||||
|
{
|
||||||
|
perror("getsockname");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||||
|
/* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD);
|
||||||
|
* But his function make a string with the port : nn.nn.nn.nn:port */
|
||||||
|
/* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr),
|
||||||
|
NULL, addr_str, (DWORD *)&addr_str_len))
|
||||||
|
{
|
||||||
|
printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError());
|
||||||
|
}*/
|
||||||
|
/* the following code is only compatible with ip v4 addresses */
|
||||||
|
strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len);
|
||||||
|
#else
|
||||||
|
#if 0
|
||||||
|
if(saddr.sa_family == AF_INET6) {
|
||||||
|
inet_ntop(AF_INET6,
|
||||||
|
&(((struct sockaddr_in6 *)&saddr)->sin6_addr),
|
||||||
|
addr_str, addr_str_len);
|
||||||
|
} else {
|
||||||
|
inet_ntop(AF_INET,
|
||||||
|
&(((struct sockaddr_in *)&saddr)->sin_addr),
|
||||||
|
addr_str, addr_str_len);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* getnameinfo return ip v6 address with the scope identifier
|
||||||
|
* such as : 2a01:e35:8b2b:7330::%4281128194 */
|
||||||
|
n = getnameinfo((const struct sockaddr *)&saddr, saddrlen,
|
||||||
|
addr_str, addr_str_len,
|
||||||
|
NULL, 0,
|
||||||
|
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||||
|
if(n != 0) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
fprintf(stderr, "getnameinfo() failed : %d\n", n);
|
||||||
|
#else
|
||||||
|
fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("address miniwget : %s\n", addr_str);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
len = snprintf(buf, sizeof(buf),
|
||||||
|
"GET %s HTTP/%s\r\n"
|
||||||
|
"Host: %s:%d\r\n"
|
||||||
|
"Connection: Close\r\n"
|
||||||
|
"User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
|
||||||
|
|
||||||
|
"\r\n",
|
||||||
|
path, httpversion, host, port);
|
||||||
|
sent = 0;
|
||||||
|
/* sending the HTTP request */
|
||||||
|
while(sent < len)
|
||||||
|
{
|
||||||
|
n = send(s, buf+sent, len-sent, 0);
|
||||||
|
if(n < 0)
|
||||||
|
{
|
||||||
|
perror("send");
|
||||||
|
closesocket(s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sent += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content = getHTTPResponse(s, size);
|
||||||
|
closesocket(s);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* miniwget2() :
|
||||||
|
* Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */
|
||||||
|
static void *
|
||||||
|
miniwget2(const char * host,
|
||||||
|
unsigned short port, const char * path,
|
||||||
|
int * size, char * addr_str, int addr_str_len,
|
||||||
|
unsigned int scope_id)
|
||||||
|
{
|
||||||
|
char * respbuffer;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
respbuffer = miniwget3(host, port, path, size,
|
||||||
|
addr_str, addr_str_len, "1.1", scope_id);
|
||||||
|
#else
|
||||||
|
respbuffer = miniwget3(host, port, path, size,
|
||||||
|
addr_str, addr_str_len, "1.0", scope_id);
|
||||||
|
if (*size == 0)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("Retrying with HTTP/1.1\n");
|
||||||
|
#endif
|
||||||
|
free(respbuffer);
|
||||||
|
respbuffer = miniwget3(host, port, path, size,
|
||||||
|
addr_str, addr_str_len, "1.1", scope_id);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return respbuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* parseURL()
|
||||||
|
* arguments :
|
||||||
|
* url : source string not modified
|
||||||
|
* hostname : hostname destination string (size of MAXHOSTNAMELEN+1)
|
||||||
|
* port : port (destination)
|
||||||
|
* path : pointer to the path part of the URL
|
||||||
|
*
|
||||||
|
* Return values :
|
||||||
|
* 0 - Failure
|
||||||
|
* 1 - Success */
|
||||||
|
int
|
||||||
|
parseURL(const char * url,
|
||||||
|
char * hostname, unsigned short * port,
|
||||||
|
char * * path, unsigned int * scope_id)
|
||||||
|
{
|
||||||
|
char * p1, *p2, *p3;
|
||||||
|
if(!url)
|
||||||
|
return 0;
|
||||||
|
p1 = strstr(url, "://");
|
||||||
|
if(!p1)
|
||||||
|
return 0;
|
||||||
|
p1 += 3;
|
||||||
|
if( (url[0]!='h') || (url[1]!='t')
|
||||||
|
||(url[2]!='t') || (url[3]!='p'))
|
||||||
|
return 0;
|
||||||
|
memset(hostname, 0, MAXHOSTNAMELEN + 1);
|
||||||
|
if(*p1 == '[')
|
||||||
|
{
|
||||||
|
/* IP v6 : http://[2a00:1450:8002::6a]/path/abc */
|
||||||
|
char * scope;
|
||||||
|
scope = strchr(p1, '%');
|
||||||
|
p2 = strchr(p1, ']');
|
||||||
|
if(p2 && scope && scope < p2 && scope_id) {
|
||||||
|
/* parse scope */
|
||||||
|
#ifdef IF_NAMESIZE
|
||||||
|
char tmp[IF_NAMESIZE];
|
||||||
|
int l;
|
||||||
|
scope++;
|
||||||
|
/* "%25" is just '%' in URL encoding */
|
||||||
|
if(scope[0] == '2' && scope[1] == '5')
|
||||||
|
scope += 2; /* skip "25" */
|
||||||
|
l = p2 - scope;
|
||||||
|
if(l >= IF_NAMESIZE)
|
||||||
|
l = IF_NAMESIZE - 1;
|
||||||
|
memcpy(tmp, scope, l);
|
||||||
|
tmp[l] = '\0';
|
||||||
|
*scope_id = if_nametoindex(tmp);
|
||||||
|
if(*scope_id == 0) {
|
||||||
|
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* under windows, scope is numerical */
|
||||||
|
char tmp[8];
|
||||||
|
int l;
|
||||||
|
scope++;
|
||||||
|
/* "%25" is just '%' in URL encoding */
|
||||||
|
if(scope[0] == '2' && scope[1] == '5')
|
||||||
|
scope += 2; /* skip "25" */
|
||||||
|
l = p2 - scope;
|
||||||
|
if(l >= sizeof(tmp))
|
||||||
|
l = sizeof(tmp) - 1;
|
||||||
|
memcpy(tmp, scope, l);
|
||||||
|
tmp[l] = '\0';
|
||||||
|
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
p3 = strchr(p1, '/');
|
||||||
|
if(p2 && p3)
|
||||||
|
{
|
||||||
|
p2++;
|
||||||
|
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
|
||||||
|
if(*p2 == ':')
|
||||||
|
{
|
||||||
|
*port = 0;
|
||||||
|
p2++;
|
||||||
|
while( (*p2 >= '0') && (*p2 <= '9'))
|
||||||
|
{
|
||||||
|
*port *= 10;
|
||||||
|
*port += (unsigned short)(*p2 - '0');
|
||||||
|
p2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*port = 80;
|
||||||
|
}
|
||||||
|
*path = p3;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p2 = strchr(p1, ':');
|
||||||
|
p3 = strchr(p1, '/');
|
||||||
|
if(!p3)
|
||||||
|
return 0;
|
||||||
|
if(!p2 || (p2>p3))
|
||||||
|
{
|
||||||
|
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1)));
|
||||||
|
*port = 80;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
|
||||||
|
*port = 0;
|
||||||
|
p2++;
|
||||||
|
while( (*p2 >= '0') && (*p2 <= '9'))
|
||||||
|
{
|
||||||
|
*port *= 10;
|
||||||
|
*port += (unsigned short)(*p2 - '0');
|
||||||
|
p2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*path = p3;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
miniwget(const char * url, int * size, unsigned int scope_id)
|
||||||
|
{
|
||||||
|
unsigned short port;
|
||||||
|
char * path;
|
||||||
|
/* protocol://host:port/chemin */
|
||||||
|
char hostname[MAXHOSTNAMELEN+1];
|
||||||
|
*size = 0;
|
||||||
|
if(!parseURL(url, hostname, &port, &path, &scope_id))
|
||||||
|
return NULL;
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
|
||||||
|
hostname, port, path, scope_id);
|
||||||
|
#endif
|
||||||
|
return miniwget2(hostname, port, path, size, 0, 0, scope_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
miniwget_getaddr(const char * url, int * size,
|
||||||
|
char * addr, int addrlen, unsigned int scope_id)
|
||||||
|
{
|
||||||
|
unsigned short port;
|
||||||
|
char * path;
|
||||||
|
/* protocol://host:port/path */
|
||||||
|
char hostname[MAXHOSTNAMELEN+1];
|
||||||
|
*size = 0;
|
||||||
|
if(addr)
|
||||||
|
addr[0] = '\0';
|
||||||
|
if(!parseURL(url, hostname, &port, &path, &scope_id))
|
||||||
|
return NULL;
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
|
||||||
|
hostname, port, path, scope_id);
|
||||||
|
#endif
|
||||||
|
return miniwget2(hostname, port, path, size, addr, addrlen, scope_id);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* $Id: miniwget.h,v 1.8 2012/09/27 15:42:10 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2012 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"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LIBSPEC void * getHTTPResponse(int s, int * size);
|
||||||
|
|
||||||
|
LIBSPEC void * miniwget(const char *, int *, unsigned int);
|
||||||
|
|
||||||
|
LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int);
|
||||||
|
|
||||||
|
int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
/* $Id: minixml.c,v 1.11 2014/02/03 15:54:12 nanard Exp $ */
|
||||||
|
/* minixml.c : the minimum size a xml parser can be ! */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
|
||||||
|
Copyright (c) 2005-2014, Thomas BERNARD
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include "minixml.h"
|
||||||
|
|
||||||
|
/* parseatt : used to parse the argument list
|
||||||
|
* return 0 (false) in case of success and -1 (true) if the end
|
||||||
|
* of the xmlbuffer is reached. */
|
||||||
|
static int parseatt(struct xmlparser * p)
|
||||||
|
{
|
||||||
|
const char * attname;
|
||||||
|
int attnamelen;
|
||||||
|
const char * attvalue;
|
||||||
|
int attvaluelen;
|
||||||
|
while(p->xml < p->xmlend)
|
||||||
|
{
|
||||||
|
if(*p->xml=='/' || *p->xml=='>')
|
||||||
|
return 0;
|
||||||
|
if( !IS_WHITE_SPACE(*p->xml) )
|
||||||
|
{
|
||||||
|
char sep;
|
||||||
|
attname = p->xml;
|
||||||
|
attnamelen = 0;
|
||||||
|
while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) )
|
||||||
|
{
|
||||||
|
attnamelen++; p->xml++;
|
||||||
|
if(p->xml >= p->xmlend)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
while(*(p->xml++) != '=')
|
||||||
|
{
|
||||||
|
if(p->xml >= p->xmlend)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
while(IS_WHITE_SPACE(*p->xml))
|
||||||
|
{
|
||||||
|
p->xml++;
|
||||||
|
if(p->xml >= p->xmlend)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sep = *p->xml;
|
||||||
|
if(sep=='\'' || sep=='\"')
|
||||||
|
{
|
||||||
|
p->xml++;
|
||||||
|
if(p->xml >= p->xmlend)
|
||||||
|
return -1;
|
||||||
|
attvalue = p->xml;
|
||||||
|
attvaluelen = 0;
|
||||||
|
while(*p->xml != sep)
|
||||||
|
{
|
||||||
|
attvaluelen++; p->xml++;
|
||||||
|
if(p->xml >= p->xmlend)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
attvalue = p->xml;
|
||||||
|
attvaluelen = 0;
|
||||||
|
while( !IS_WHITE_SPACE(*p->xml)
|
||||||
|
&& *p->xml != '>' && *p->xml != '/')
|
||||||
|
{
|
||||||
|
attvaluelen++; p->xml++;
|
||||||
|
if(p->xml >= p->xmlend)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*printf("%.*s='%.*s'\n",
|
||||||
|
attnamelen, attname, attvaluelen, attvalue);*/
|
||||||
|
if(p->attfunc)
|
||||||
|
p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen);
|
||||||
|
}
|
||||||
|
p->xml++;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parseelt parse the xml stream and
|
||||||
|
* call the callback functions when needed... */
|
||||||
|
static void parseelt(struct xmlparser * p)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char * elementname;
|
||||||
|
while(p->xml < (p->xmlend - 1))
|
||||||
|
{
|
||||||
|
if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "<!--", 4)))
|
||||||
|
{
|
||||||
|
p->xml += 3;
|
||||||
|
/* ignore comments */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
p->xml++;
|
||||||
|
if ((p->xml + 3) >= p->xmlend)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while(memcmp(p->xml, "-->", 3) != 0);
|
||||||
|
p->xml += 3;
|
||||||
|
}
|
||||||
|
else if((p->xml)[0]=='<' && (p->xml)[1]!='?')
|
||||||
|
{
|
||||||
|
i = 0; elementname = ++p->xml;
|
||||||
|
while( !IS_WHITE_SPACE(*p->xml)
|
||||||
|
&& (*p->xml!='>') && (*p->xml!='/')
|
||||||
|
)
|
||||||
|
{
|
||||||
|
i++; p->xml++;
|
||||||
|
if (p->xml >= p->xmlend)
|
||||||
|
return;
|
||||||
|
/* to ignore namespace : */
|
||||||
|
if(*p->xml==':')
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
elementname = ++p->xml;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(i>0)
|
||||||
|
{
|
||||||
|
if(p->starteltfunc)
|
||||||
|
p->starteltfunc(p->data, elementname, i);
|
||||||
|
if(parseatt(p))
|
||||||
|
return;
|
||||||
|
if(*p->xml!='/')
|
||||||
|
{
|
||||||
|
const char * data;
|
||||||
|
i = 0; data = ++p->xml;
|
||||||
|
if (p->xml >= p->xmlend)
|
||||||
|
return;
|
||||||
|
while( IS_WHITE_SPACE(*p->xml) )
|
||||||
|
{
|
||||||
|
i++; p->xml++;
|
||||||
|
if (p->xml >= p->xmlend)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(memcmp(p->xml, "<![CDATA[", 9) == 0)
|
||||||
|
{
|
||||||
|
/* CDATA handling */
|
||||||
|
p->xml += 9;
|
||||||
|
data = p->xml;
|
||||||
|
i = 0;
|
||||||
|
while(memcmp(p->xml, "]]>", 3) != 0)
|
||||||
|
{
|
||||||
|
i++; p->xml++;
|
||||||
|
if ((p->xml + 3) >= p->xmlend)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(i>0 && p->datafunc)
|
||||||
|
p->datafunc(p->data, data, i);
|
||||||
|
while(*p->xml!='<')
|
||||||
|
{
|
||||||
|
p->xml++;
|
||||||
|
if (p->xml >= p->xmlend)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(*p->xml!='<')
|
||||||
|
{
|
||||||
|
i++; p->xml++;
|
||||||
|
if ((p->xml + 1) >= p->xmlend)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(i>0 && p->datafunc && *(p->xml + 1) == '/')
|
||||||
|
p->datafunc(p->data, data, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(*p->xml == '/')
|
||||||
|
{
|
||||||
|
i = 0; elementname = ++p->xml;
|
||||||
|
if (p->xml >= p->xmlend)
|
||||||
|
return;
|
||||||
|
while((*p->xml != '>'))
|
||||||
|
{
|
||||||
|
i++; p->xml++;
|
||||||
|
if (p->xml >= p->xmlend)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(p->endeltfunc)
|
||||||
|
p->endeltfunc(p->data, elementname, i);
|
||||||
|
p->xml++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p->xml++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the parser must be initialized before calling this function */
|
||||||
|
void parsexml(struct xmlparser * parser)
|
||||||
|
{
|
||||||
|
parser->xml = parser->xmlstart;
|
||||||
|
parser->xmlend = parser->xmlstart + parser->xmlsize;
|
||||||
|
parseelt(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */
|
||||||
|
/* minimal xml parser
|
||||||
|
*
|
||||||
|
* Project : miniupnp
|
||||||
|
* Website : http://miniupnp.free.fr/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
* */
|
||||||
|
#ifndef MINIXML_H_INCLUDED
|
||||||
|
#define MINIXML_H_INCLUDED
|
||||||
|
#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n'))
|
||||||
|
|
||||||
|
/* if a callback function pointer is set to NULL,
|
||||||
|
* the function is not called */
|
||||||
|
struct xmlparser {
|
||||||
|
const char *xmlstart;
|
||||||
|
const char *xmlend;
|
||||||
|
const char *xml; /* pointer to current character */
|
||||||
|
int xmlsize;
|
||||||
|
void * data;
|
||||||
|
void (*starteltfunc) (void *, const char *, int);
|
||||||
|
void (*endeltfunc) (void *, const char *, int);
|
||||||
|
void (*datafunc) (void *, const char *, int);
|
||||||
|
void (*attfunc) (void *, const char *, int, const char *, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* parsexml()
|
||||||
|
* the xmlparser structure must be initialized before the call
|
||||||
|
* the following structure members have to be initialized :
|
||||||
|
* xmlstart, xmlsize, data, *func
|
||||||
|
* xml is for internal usage, xmlend is computed automatically */
|
||||||
|
void parsexml(struct xmlparser *);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
/* $Id: minixmlvalid.c,v 1.6 2012/05/01 16:24:07 nanard Exp $ */
|
||||||
|
/* MiniUPnP Project
|
||||||
|
* http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
|
||||||
|
* minixmlvalid.c :
|
||||||
|
* validation program for the minixml parser
|
||||||
|
*
|
||||||
|
* (c) 2006-2011 Thomas Bernard */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "minixml.h"
|
||||||
|
|
||||||
|
/* xml event structure */
|
||||||
|
struct event {
|
||||||
|
enum { ELTSTART, ELTEND, ATT, CHARDATA } type;
|
||||||
|
const char * data;
|
||||||
|
int len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct eventlist {
|
||||||
|
int n;
|
||||||
|
struct event * events;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* compare 2 xml event lists
|
||||||
|
* return 0 if the two lists are equals */
|
||||||
|
int evtlistcmp(struct eventlist * a, struct eventlist * b)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct event * ae, * be;
|
||||||
|
if(a->n != b->n)
|
||||||
|
{
|
||||||
|
printf("event number not matching : %d != %d\n", a->n, b->n);
|
||||||
|
/*return 1;*/
|
||||||
|
}
|
||||||
|
for(i=0; i<a->n; i++)
|
||||||
|
{
|
||||||
|
ae = a->events + i;
|
||||||
|
be = b->events + i;
|
||||||
|
if( (ae->type != be->type)
|
||||||
|
||(ae->len != be->len)
|
||||||
|
||memcmp(ae->data, be->data, ae->len))
|
||||||
|
{
|
||||||
|
printf("Found a difference : %d '%.*s' != %d '%.*s'\n",
|
||||||
|
ae->type, ae->len, ae->data,
|
||||||
|
be->type, be->len, be->data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test data */
|
||||||
|
static const char xmldata[] =
|
||||||
|
"<xmlroot>\n"
|
||||||
|
" <elt1 att1=\"attvalue1\" att2=\"attvalue2\">"
|
||||||
|
"character data"
|
||||||
|
"</elt1> \n \t"
|
||||||
|
"<elt1b/>"
|
||||||
|
"<elt1>\n<![CDATA[ <html>stuff !\n ]]> \n</elt1>\n"
|
||||||
|
"<elt2a> \t<elt2b>chardata1</elt2b><elt2b> chardata2 </elt2b></elt2a>"
|
||||||
|
"</xmlroot>";
|
||||||
|
|
||||||
|
static const struct event evtref[] =
|
||||||
|
{
|
||||||
|
{ELTSTART, "xmlroot", 7},
|
||||||
|
{ELTSTART, "elt1", 4},
|
||||||
|
/* attributes */
|
||||||
|
{CHARDATA, "character data", 14},
|
||||||
|
{ELTEND, "elt1", 4},
|
||||||
|
{ELTSTART, "elt1b", 5},
|
||||||
|
{ELTSTART, "elt1", 4},
|
||||||
|
{CHARDATA, " <html>stuff !\n ", 16},
|
||||||
|
{ELTEND, "elt1", 4},
|
||||||
|
{ELTSTART, "elt2a", 5},
|
||||||
|
{ELTSTART, "elt2b", 5},
|
||||||
|
{CHARDATA, "chardata1", 9},
|
||||||
|
{ELTEND, "elt2b", 5},
|
||||||
|
{ELTSTART, "elt2b", 5},
|
||||||
|
{CHARDATA, " chardata2 ", 11},
|
||||||
|
{ELTEND, "elt2b", 5},
|
||||||
|
{ELTEND, "elt2a", 5},
|
||||||
|
{ELTEND, "xmlroot", 7}
|
||||||
|
};
|
||||||
|
|
||||||
|
void startelt(void * data, const char * p, int l)
|
||||||
|
{
|
||||||
|
struct eventlist * evtlist = data;
|
||||||
|
struct event * evt;
|
||||||
|
evt = evtlist->events + evtlist->n;
|
||||||
|
/*printf("startelt : %.*s\n", l, p);*/
|
||||||
|
evt->type = ELTSTART;
|
||||||
|
evt->data = p;
|
||||||
|
evt->len = l;
|
||||||
|
evtlist->n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void endelt(void * data, const char * p, int l)
|
||||||
|
{
|
||||||
|
struct eventlist * evtlist = data;
|
||||||
|
struct event * evt;
|
||||||
|
evt = evtlist->events + evtlist->n;
|
||||||
|
/*printf("endelt : %.*s\n", l, p);*/
|
||||||
|
evt->type = ELTEND;
|
||||||
|
evt->data = p;
|
||||||
|
evt->len = l;
|
||||||
|
evtlist->n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void chardata(void * data, const char * p, int l)
|
||||||
|
{
|
||||||
|
struct eventlist * evtlist = data;
|
||||||
|
struct event * evt;
|
||||||
|
evt = evtlist->events + evtlist->n;
|
||||||
|
/*printf("chardata : '%.*s'\n", l, p);*/
|
||||||
|
evt->type = CHARDATA;
|
||||||
|
evt->data = p;
|
||||||
|
evt->len = l;
|
||||||
|
evtlist->n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int testxmlparser(const char * xml, int size)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct eventlist evtlist;
|
||||||
|
struct eventlist evtlistref;
|
||||||
|
struct xmlparser parser;
|
||||||
|
evtlist.n = 0;
|
||||||
|
evtlist.events = malloc(sizeof(struct event)*100);
|
||||||
|
memset(&parser, 0, sizeof(parser));
|
||||||
|
parser.xmlstart = xml;
|
||||||
|
parser.xmlsize = size;
|
||||||
|
parser.data = &evtlist;
|
||||||
|
parser.starteltfunc = startelt;
|
||||||
|
parser.endeltfunc = endelt;
|
||||||
|
parser.datafunc = chardata;
|
||||||
|
parsexml(&parser);
|
||||||
|
printf("%d events\n", evtlist.n);
|
||||||
|
/* compare */
|
||||||
|
evtlistref.n = sizeof(evtref)/sizeof(struct event);
|
||||||
|
evtlistref.events = (struct event *)evtref;
|
||||||
|
r = evtlistcmp(&evtlistref, &evtlist);
|
||||||
|
free(evtlist.events);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
(void)argc; (void)argv;
|
||||||
|
|
||||||
|
r = testxmlparser(xmldata, sizeof(xmldata)-1);
|
||||||
|
if(r)
|
||||||
|
printf("minixml validation test failed\n");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||||
|
# Visual C++ Express 2008
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniupnpc", "miniupnpc.vcproj", "{D28CE435-CB33-4BAE-8A52-C6EF915956F5}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "upnpc-static", "upnpc-static.vcproj", "{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{D28CE435-CB33-4BAE-8A52-C6EF915956F5} = {D28CE435-CB33-4BAE-8A52-C6EF915956F5}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Win32 = Debug|Win32
|
||||||
|
Release|Win32 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{D28CE435-CB33-4BAE-8A52-C6EF915956F5}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,271 @@
|
||||||
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
|
<VisualStudioProject
|
||||||
|
ProjectType="Visual C++"
|
||||||
|
Version="9,00"
|
||||||
|
Name="miniupnpc"
|
||||||
|
ProjectGUID="{D28CE435-CB33-4BAE-8A52-C6EF915956F5}"
|
||||||
|
RootNamespace="miniupnpc"
|
||||||
|
Keyword="Win32Proj"
|
||||||
|
TargetFrameworkVersion="196613"
|
||||||
|
>
|
||||||
|
<Platforms>
|
||||||
|
<Platform
|
||||||
|
Name="Win32"
|
||||||
|
/>
|
||||||
|
</Platforms>
|
||||||
|
<ToolFiles>
|
||||||
|
</ToolFiles>
|
||||||
|
<Configurations>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;WIN32;STATICLIB;DEBUG"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
BasicRuntimeChecks="3"
|
||||||
|
RuntimeLibrary="3"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="4"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|Win32"
|
||||||
|
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="1"
|
||||||
|
WholeProgramOptimization="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="2"
|
||||||
|
EnableIntrinsicFunctions="true"
|
||||||
|
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;WIN32;STATICLIB"
|
||||||
|
RuntimeLibrary="2"
|
||||||
|
EnableFunctionLevelLinking="true"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
</Configurations>
|
||||||
|
<References>
|
||||||
|
</References>
|
||||||
|
<Files>
|
||||||
|
<Filter
|
||||||
|
Name="Fichiers sources"
|
||||||
|
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||||
|
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\connecthostport.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\igd_desc_parse.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\minisoap.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\miniupnpc.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\miniwget.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\minixml.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\portlistingparse.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\receivedata.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\upnpcommands.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\upnperrors.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\upnpreplyparse.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Fichiers d'en-tête"
|
||||||
|
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||||
|
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\bsdqueue.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\connecthostport.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\declspec.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\igd_desc_parse.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\minisoap.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\miniupnpc.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\miniupnpcstrings.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\miniupnpctypes.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\miniwget.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\minixml.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\portlistingparse.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\receivedata.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\upnpcommands.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\upnperrors.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\upnpreplyparse.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Fichiers de ressources"
|
||||||
|
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||||
|
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||||
|
>
|
||||||
|
</Filter>
|
||||||
|
</Files>
|
||||||
|
<Globals>
|
||||||
|
</Globals>
|
||||||
|
</VisualStudioProject>
|
|
@ -0,0 +1,195 @@
|
||||||
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
|
<VisualStudioProject
|
||||||
|
ProjectType="Visual C++"
|
||||||
|
Version="9,00"
|
||||||
|
Name="upnpc-static"
|
||||||
|
ProjectGUID="{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}"
|
||||||
|
RootNamespace="upnpcstatic"
|
||||||
|
Keyword="Win32Proj"
|
||||||
|
TargetFrameworkVersion="196613"
|
||||||
|
>
|
||||||
|
<Platforms>
|
||||||
|
<Platform
|
||||||
|
Name="Win32"
|
||||||
|
/>
|
||||||
|
</Platforms>
|
||||||
|
<ToolFiles>
|
||||||
|
</ToolFiles>
|
||||||
|
<Configurations>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)"
|
||||||
|
ConfigurationType="1"
|
||||||
|
CharacterSet="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;STATICLIB;DEBUG;_CRT_SECURE_NO_WARNINGS"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
BasicRuntimeChecks="3"
|
||||||
|
RuntimeLibrary="3"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="4"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLinkerTool"
|
||||||
|
AdditionalDependencies="ws2_32.lib IPHlpApi.Lib Debug\miniupnpc.lib"
|
||||||
|
LinkIncremental="2"
|
||||||
|
GenerateDebugInformation="true"
|
||||||
|
SubSystem="1"
|
||||||
|
TargetMachine="1"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManifestTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCAppVerifierTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|Win32"
|
||||||
|
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)"
|
||||||
|
ConfigurationType="1"
|
||||||
|
CharacterSet="1"
|
||||||
|
WholeProgramOptimization="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="2"
|
||||||
|
EnableIntrinsicFunctions="true"
|
||||||
|
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;STATICLIB"
|
||||||
|
RuntimeLibrary="2"
|
||||||
|
EnableFunctionLevelLinking="true"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLinkerTool"
|
||||||
|
AdditionalDependencies="ws2_32.lib IPHlpApi.Lib Release\miniupnpc.lib"
|
||||||
|
LinkIncremental="1"
|
||||||
|
GenerateDebugInformation="true"
|
||||||
|
SubSystem="1"
|
||||||
|
OptimizeReferences="2"
|
||||||
|
EnableCOMDATFolding="2"
|
||||||
|
TargetMachine="1"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManifestTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCAppVerifierTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
</Configurations>
|
||||||
|
<References>
|
||||||
|
</References>
|
||||||
|
<Files>
|
||||||
|
<Filter
|
||||||
|
Name="Fichiers sources"
|
||||||
|
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||||
|
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\upnpc.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Fichiers d'en-tête"
|
||||||
|
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||||
|
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||||
|
>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Fichiers de ressources"
|
||||||
|
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||||
|
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||||
|
>
|
||||||
|
</Filter>
|
||||||
|
</Files>
|
||||||
|
<Globals>
|
||||||
|
</Globals>
|
||||||
|
</VisualStudioProject>
|
|
@ -0,0 +1,159 @@
|
||||||
|
/* $Id: portlistingparse.c,v 1.6 2012/05/29 10:26:51 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* (c) 2011 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed
|
||||||
|
* in the LICENCE file provided within the distribution */
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "portlistingparse.h"
|
||||||
|
#include "minixml.h"
|
||||||
|
|
||||||
|
/* list of the elements */
|
||||||
|
static const struct {
|
||||||
|
const portMappingElt code;
|
||||||
|
const char * const str;
|
||||||
|
} elements[] = {
|
||||||
|
{ PortMappingEntry, "PortMappingEntry"},
|
||||||
|
{ NewRemoteHost, "NewRemoteHost"},
|
||||||
|
{ NewExternalPort, "NewExternalPort"},
|
||||||
|
{ NewProtocol, "NewProtocol"},
|
||||||
|
{ NewInternalPort, "NewInternalPort"},
|
||||||
|
{ NewInternalClient, "NewInternalClient"},
|
||||||
|
{ NewEnabled, "NewEnabled"},
|
||||||
|
{ NewDescription, "NewDescription"},
|
||||||
|
{ NewLeaseTime, "NewLeaseTime"},
|
||||||
|
{ PortMappingEltNone, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Helper function */
|
||||||
|
static UNSIGNED_INTEGER
|
||||||
|
atoui(const char * p, int l)
|
||||||
|
{
|
||||||
|
UNSIGNED_INTEGER r = 0;
|
||||||
|
while(l > 0 && *p)
|
||||||
|
{
|
||||||
|
if(*p >= '0' && *p <= '9')
|
||||||
|
r = r*10 + (*p - '0');
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
p++;
|
||||||
|
l--;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start element handler */
|
||||||
|
static void
|
||||||
|
startelt(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
|
||||||
|
pdata->curelt = PortMappingEltNone;
|
||||||
|
for(i = 0; elements[i].str; i++)
|
||||||
|
{
|
||||||
|
if(memcmp(name, elements[i].str, l) == 0)
|
||||||
|
{
|
||||||
|
pdata->curelt = elements[i].code;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(pdata->curelt == PortMappingEntry)
|
||||||
|
{
|
||||||
|
struct PortMapping * pm;
|
||||||
|
pm = calloc(1, sizeof(struct PortMapping));
|
||||||
|
LIST_INSERT_HEAD( &(pdata->head), pm, entries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End element handler */
|
||||||
|
static void
|
||||||
|
endelt(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
|
||||||
|
(void)name;
|
||||||
|
(void)l;
|
||||||
|
pdata->curelt = PortMappingEltNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Data handler */
|
||||||
|
static void
|
||||||
|
data(void * d, const char * data, int l)
|
||||||
|
{
|
||||||
|
struct PortMapping * pm;
|
||||||
|
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
|
||||||
|
pm = pdata->head.lh_first;
|
||||||
|
if(!pm)
|
||||||
|
return;
|
||||||
|
if(l > 63)
|
||||||
|
l = 63;
|
||||||
|
switch(pdata->curelt)
|
||||||
|
{
|
||||||
|
case NewRemoteHost:
|
||||||
|
memcpy(pm->remoteHost, data, l);
|
||||||
|
pm->remoteHost[l] = '\0';
|
||||||
|
break;
|
||||||
|
case NewExternalPort:
|
||||||
|
pm->externalPort = (unsigned short)atoui(data, l);
|
||||||
|
break;
|
||||||
|
case NewProtocol:
|
||||||
|
if(l > 3)
|
||||||
|
l = 3;
|
||||||
|
memcpy(pm->protocol, data, l);
|
||||||
|
pm->protocol[l] = '\0';
|
||||||
|
break;
|
||||||
|
case NewInternalPort:
|
||||||
|
pm->internalPort = (unsigned short)atoui(data, l);
|
||||||
|
break;
|
||||||
|
case NewInternalClient:
|
||||||
|
memcpy(pm->internalClient, data, l);
|
||||||
|
pm->internalClient[l] = '\0';
|
||||||
|
break;
|
||||||
|
case NewEnabled:
|
||||||
|
pm->enabled = (unsigned char)atoui(data, l);
|
||||||
|
break;
|
||||||
|
case NewDescription:
|
||||||
|
memcpy(pm->description, data, l);
|
||||||
|
pm->description[l] = '\0';
|
||||||
|
break;
|
||||||
|
case NewLeaseTime:
|
||||||
|
pm->leaseTime = atoui(data, l);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Parse the PortMappingList XML document for IGD version 2
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ParsePortListing(const char * buffer, int bufsize,
|
||||||
|
struct PortMappingParserData * pdata)
|
||||||
|
{
|
||||||
|
struct xmlparser parser;
|
||||||
|
|
||||||
|
memset(pdata, 0, sizeof(struct PortMappingParserData));
|
||||||
|
LIST_INIT(&(pdata->head));
|
||||||
|
/* init xmlparser */
|
||||||
|
parser.xmlstart = buffer;
|
||||||
|
parser.xmlsize = bufsize;
|
||||||
|
parser.data = pdata;
|
||||||
|
parser.starteltfunc = startelt;
|
||||||
|
parser.endeltfunc = endelt;
|
||||||
|
parser.datafunc = data;
|
||||||
|
parser.attfunc = 0;
|
||||||
|
parsexml(&parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FreePortListing(struct PortMappingParserData * pdata)
|
||||||
|
{
|
||||||
|
struct PortMapping * pm;
|
||||||
|
while((pm = pdata->head.lh_first) != NULL)
|
||||||
|
{
|
||||||
|
LIST_REMOVE(pm, entries);
|
||||||
|
free(pm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/* $Id: portlistingparse.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* (c) 2011-2012 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"
|
||||||
|
/* for the definition of UNSIGNED_INTEGER */
|
||||||
|
#include "miniupnpctypes.h"
|
||||||
|
|
||||||
|
#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__)
|
||||||
|
#include "bsdqueue.h"
|
||||||
|
#else
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* sample of PortMappingEntry :
|
||||||
|
<p:PortMappingEntry>
|
||||||
|
<p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
|
||||||
|
<p:NewExternalPort>2345</p:NewExternalPort>
|
||||||
|
<p:NewProtocol>TCP</p:NewProtocol>
|
||||||
|
<p:NewInternalPort>2345</p:NewInternalPort>
|
||||||
|
<p:NewInternalClient>192.168.1.137</p:NewInternalClient>
|
||||||
|
<p:NewEnabled>1</p:NewEnabled>
|
||||||
|
<p:NewDescription>dooom</p:NewDescription>
|
||||||
|
<p:NewLeaseTime>345</p:NewLeaseTime>
|
||||||
|
</p:PortMappingEntry>
|
||||||
|
*/
|
||||||
|
typedef enum { PortMappingEltNone,
|
||||||
|
PortMappingEntry, NewRemoteHost,
|
||||||
|
NewExternalPort, NewProtocol,
|
||||||
|
NewInternalPort, NewInternalClient,
|
||||||
|
NewEnabled, NewDescription,
|
||||||
|
NewLeaseTime } portMappingElt;
|
||||||
|
|
||||||
|
struct PortMapping {
|
||||||
|
LIST_ENTRY(PortMapping) entries;
|
||||||
|
UNSIGNED_INTEGER leaseTime;
|
||||||
|
unsigned short externalPort;
|
||||||
|
unsigned short internalPort;
|
||||||
|
char remoteHost[64];
|
||||||
|
char internalClient[64];
|
||||||
|
char description[64];
|
||||||
|
char protocol[4];
|
||||||
|
unsigned char enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PortMappingParserData {
|
||||||
|
LIST_HEAD(portmappinglisthead, PortMapping) head;
|
||||||
|
portMappingElt curelt;
|
||||||
|
};
|
||||||
|
|
||||||
|
LIBSPEC void
|
||||||
|
ParsePortListing(const char * buffer, int bufsize,
|
||||||
|
struct PortMappingParserData * pdata);
|
||||||
|
|
||||||
|
LIBSPEC void
|
||||||
|
FreePortListing(struct PortMappingParserData * pdata);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,52 @@
|
||||||
|
#! /usr/bin/python
|
||||||
|
# MiniUPnP project
|
||||||
|
# Author : Thomas Bernard
|
||||||
|
# This Sample code is public domain.
|
||||||
|
# website : http://miniupnp.tuxfamily.org/
|
||||||
|
|
||||||
|
# import the python miniupnpc module
|
||||||
|
import miniupnpc
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# create the object
|
||||||
|
u = miniupnpc.UPnP()
|
||||||
|
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
|
||||||
|
print u.discover(), 'device(s) detected'
|
||||||
|
# select an igd
|
||||||
|
try:
|
||||||
|
u.selectigd()
|
||||||
|
except Exception, e:
|
||||||
|
print 'Exception :', e
|
||||||
|
sys.exit(1)
|
||||||
|
# display information about the IGD and the internet connection
|
||||||
|
print 'local ip address :', u.lanaddr
|
||||||
|
print 'external ip address :', u.externalipaddress()
|
||||||
|
print u.statusinfo(), u.connectiontype()
|
||||||
|
|
||||||
|
#print u.addportmapping(64000, 'TCP',
|
||||||
|
# '192.168.1.166', 63000, 'port mapping test', '')
|
||||||
|
#print u.deleteportmapping(64000, 'TCP')
|
||||||
|
|
||||||
|
port = 0
|
||||||
|
proto = 'UDP'
|
||||||
|
# list the redirections :
|
||||||
|
i = 0
|
||||||
|
while True:
|
||||||
|
p = u.getgenericportmapping(i)
|
||||||
|
if p==None:
|
||||||
|
break
|
||||||
|
print i, p
|
||||||
|
(port, proto, (ihost,iport), desc, c, d, e) = p
|
||||||
|
#print port, desc
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
|
print u.getspecificportmapping(port, proto)
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
/* $Id: receivedata.c,v 1.5 2013/10/07 09:48:36 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Website : http://miniupnp.free.fr/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2011-2012 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution. */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#if defined(__amigaos__) && !defined(__amigaos4__)
|
||||||
|
#define socklen_t int
|
||||||
|
#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
|
||||||
|
#include <sys/select.h>
|
||||||
|
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#if !defined(__amigaos__) && !defined(__amigaos4__)
|
||||||
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
|
#include <errno.h>
|
||||||
|
#define MINIUPNPC_IGNORE_EINTR
|
||||||
|
#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
|
||||||
|
|
||||||
|
#include "receivedata.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
receivedata(int socket,
|
||||||
|
char * data, int length,
|
||||||
|
int timeout, unsigned int * scope_id)
|
||||||
|
{
|
||||||
|
#if MINIUPNPC_GET_SRC_ADDR
|
||||||
|
#ifdef DEBUG
|
||||||
|
/* to shut up valgrind about uninit value */
|
||||||
|
struct sockaddr_storage src_addr = {0};
|
||||||
|
#else
|
||||||
|
struct sockaddr_storage src_addr;
|
||||||
|
#endif
|
||||||
|
socklen_t src_addr_len = sizeof(src_addr);
|
||||||
|
#endif
|
||||||
|
int n;
|
||||||
|
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
|
||||||
|
/* using poll */
|
||||||
|
struct pollfd fds[1]; /* for the poll */
|
||||||
|
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||||
|
do {
|
||||||
|
#endif
|
||||||
|
fds[0].fd = socket;
|
||||||
|
fds[0].events = POLLIN;
|
||||||
|
n = poll(fds, 1, timeout);
|
||||||
|
#ifdef MINIUPNPC_IGNORE_EINTR
|
||||||
|
} while(n < 0 && errno == EINTR);
|
||||||
|
#endif
|
||||||
|
if(n < 0) {
|
||||||
|
PRINT_SOCKET_ERROR("poll");
|
||||||
|
return -1;
|
||||||
|
} else if(n == 0) {
|
||||||
|
/* timeout */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
|
||||||
|
/* using select under _WIN32 and amigaos */
|
||||||
|
fd_set socketSet;
|
||||||
|
TIMEVAL timeval;
|
||||||
|
FD_ZERO(&socketSet);
|
||||||
|
FD_SET(socket, &socketSet);
|
||||||
|
timeval.tv_sec = timeout / 1000;
|
||||||
|
timeval.tv_usec = (timeout % 1000) * 1000;
|
||||||
|
n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval);
|
||||||
|
if(n < 0) {
|
||||||
|
PRINT_SOCKET_ERROR("select");
|
||||||
|
return -1;
|
||||||
|
} else if(n == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if MINIUPNPC_GET_SRC_ADDR
|
||||||
|
n = recvfrom(socket, data, length, 0,
|
||||||
|
(struct sockaddr *)&src_addr, &src_addr_len);
|
||||||
|
#else
|
||||||
|
n = recv(socket, data, length, 0);
|
||||||
|
#endif
|
||||||
|
if(n<0) {
|
||||||
|
PRINT_SOCKET_ERROR("recv");
|
||||||
|
}
|
||||||
|
#if 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
|
||||||
|
if(scope_id)
|
||||||
|
*scope_id = src_addr6->sin6_scope_id;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/* $Id: receivedata.h,v 1.4 2012/09/27 15:42:10 nanard Exp $ */
|
||||||
|
/* Project: miniupnp
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* Author: Thomas Bernard
|
||||||
|
* Copyright (c) 2011-2012 Thomas Bernard
|
||||||
|
* This software is subjects to the conditions detailed
|
||||||
|
* in the LICENCE file provided within this distribution */
|
||||||
|
#ifndef RECEIVEDATA_H_INCLUDED
|
||||||
|
#define RECEIVEDATA_H_INCLUDED
|
||||||
|
|
||||||
|
/* Reads data from the specified socket.
|
||||||
|
* Returns the number of bytes read if successful, zero if no bytes were
|
||||||
|
* read or if we timed out. Returns negative if there was an error. */
|
||||||
|
int receivedata(int socket,
|
||||||
|
char * data, int length,
|
||||||
|
int timeout, unsigned int * scope_id);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#! /usr/bin/python
|
||||||
|
# $Id: setup.py,v 1.9 2012/05/23 08:50:10 nanard Exp $
|
||||||
|
# the MiniUPnP Project (c) 2007-2012 Thomas Bernard
|
||||||
|
# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
from distutils import sysconfig
|
||||||
|
sysconfig.get_config_vars()["OPT"] = ''
|
||||||
|
sysconfig.get_config_vars()["CFLAGS"] = ''
|
||||||
|
setup(name="miniupnpc", version="1.7",
|
||||||
|
ext_modules=[
|
||||||
|
Extension(name="miniupnpc", sources=["miniupnpcmodule.c"],
|
||||||
|
extra_objects=["libminiupnpc.a"])
|
||||||
|
])
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#! /usr/bin/python
|
||||||
|
# $Id: setupmingw32.py,v 1.8 2012/05/23 08:50:10 nanard Exp $
|
||||||
|
# the MiniUPnP Project (c) 2007-2012 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
|
||||||
|
from distutils import sysconfig
|
||||||
|
sysconfig.get_config_vars()["OPT"] = ''
|
||||||
|
sysconfig.get_config_vars()["CFLAGS"] = ''
|
||||||
|
setup(name="miniupnpc", version="1.7",
|
||||||
|
ext_modules=[
|
||||||
|
Extension(name="miniupnpc", sources=["miniupnpcmodule.c"],
|
||||||
|
libraries=["ws2_32", "iphlpapi"],
|
||||||
|
extra_objects=["libminiupnpc.a"])
|
||||||
|
])
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
/* $Id: testigddescparse.c,v 1.4 2012/06/28 18:52:12 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* http://miniupnp.free.fr/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2008-2012 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
* */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "igd_desc_parse.h"
|
||||||
|
#include "minixml.h"
|
||||||
|
#include "miniupnpc.h"
|
||||||
|
|
||||||
|
int test_igd_desc_parse(char * buffer, int len)
|
||||||
|
{
|
||||||
|
struct IGDdatas igd;
|
||||||
|
struct xmlparser parser;
|
||||||
|
struct UPNPUrls urls;
|
||||||
|
memset(&igd, 0, sizeof(struct IGDdatas));
|
||||||
|
memset(&parser, 0, sizeof(struct xmlparser));
|
||||||
|
parser.xmlstart = buffer;
|
||||||
|
parser.xmlsize = len;
|
||||||
|
parser.data = &igd;
|
||||||
|
parser.starteltfunc = IGDstartelt;
|
||||||
|
parser.endeltfunc = IGDendelt;
|
||||||
|
parser.datafunc = IGDdata;
|
||||||
|
parsexml(&parser);
|
||||||
|
printIGD(&igd);
|
||||||
|
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);
|
||||||
|
FreeUPNPUrls(&urls);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
FILE * f;
|
||||||
|
char * buffer;
|
||||||
|
int len;
|
||||||
|
int r = 0;
|
||||||
|
if(argc<2) {
|
||||||
|
fprintf(stderr, "Usage: %s file.xml\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
f = fopen(argv[1], "r");
|
||||||
|
if(!f) {
|
||||||
|
fprintf(stderr, "Cannot open %s for reading.\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
len = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
buffer = malloc(len);
|
||||||
|
fread(buffer, 1, len, f);
|
||||||
|
fclose(f);
|
||||||
|
r = test_igd_desc_parse(buffer, len);
|
||||||
|
free(buffer);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* $Id: testminiwget.c,v 1.4 2012/06/23 22:35:59 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2012 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution.
|
||||||
|
* */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "miniwget.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This program uses the miniwget / miniwget_getaddr function
|
||||||
|
* from miniwget.c in order to retreive a web ressource using
|
||||||
|
* a GET HTTP method, and store it in a file.
|
||||||
|
*/
|
||||||
|
int main(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
void * data;
|
||||||
|
int size, writtensize;
|
||||||
|
FILE *f;
|
||||||
|
char addr[64];
|
||||||
|
|
||||||
|
if(argc < 3) {
|
||||||
|
fprintf(stderr, "Usage:\t%s url file\n", argv[0]);
|
||||||
|
fprintf(stderr, "Example:\t%s http://www.google.com/ out.html\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
data = miniwget_getaddr(argv[1], &size, addr, sizeof(addr), 0);
|
||||||
|
if(!data) {
|
||||||
|
fprintf(stderr, "Error fetching %s\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("local address : %s\n", addr);
|
||||||
|
printf("got %d bytes\n", size);
|
||||||
|
f = fopen(argv[2], "wb");
|
||||||
|
if(!f) {
|
||||||
|
fprintf(stderr, "Cannot open file %s for writing\n", argv[2]);
|
||||||
|
free(data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
writtensize = fwrite(data, 1, size, f);
|
||||||
|
if(writtensize != size) {
|
||||||
|
fprintf(stderr, "Could only write %d bytes out of %d to %s\n",
|
||||||
|
writtensize, size, argv[2]);
|
||||||
|
} else {
|
||||||
|
printf("%d bytes written to %s\n", writtensize, argv[2]);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
free(data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# $Id: testminiwget.sh,v 1.10 2013/11/13 15:08:08 nanard Exp $
|
||||||
|
# project miniupnp : http://miniupnp.free.fr/
|
||||||
|
# (c) 2011-2012 Thomas Bernard
|
||||||
|
#
|
||||||
|
# test program for miniwget.c
|
||||||
|
# is usually invoked by "make check"
|
||||||
|
#
|
||||||
|
# This test program :
|
||||||
|
# 1 - launches a local HTTP server (minihttptestserver)
|
||||||
|
# 2 - uses testminiwget to retreive data from this server
|
||||||
|
# 3 - compares served and received data
|
||||||
|
# 4 - kills the local HTTP server and exits
|
||||||
|
#
|
||||||
|
# The script was tested and works with ksh, bash
|
||||||
|
# it should now also run with dash
|
||||||
|
|
||||||
|
TMPD=`mktemp -d miniwgetXXXXXXXXXX`
|
||||||
|
HTTPSERVEROUT="${TMPD}/httpserverout"
|
||||||
|
EXPECTEDFILE="${TMPD}/expectedfile"
|
||||||
|
DOWNLOADEDFILE="${TMPD}/downloadedfile"
|
||||||
|
PORT=
|
||||||
|
RET=0
|
||||||
|
|
||||||
|
case "$HAVE_IPV6" in
|
||||||
|
n|no|0)
|
||||||
|
ADDR=localhost
|
||||||
|
SERVERARGS=""
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
ADDR="[::1]"
|
||||||
|
SERVERARGS="-6"
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
#make minihttptestserver
|
||||||
|
#make testminiwget
|
||||||
|
|
||||||
|
# launching the test HTTP server
|
||||||
|
./minihttptestserver $SERVERARGS -e $EXPECTEDFILE > $HTTPSERVEROUT &
|
||||||
|
SERVERPID=$!
|
||||||
|
while [ -z "$PORT" ]; do
|
||||||
|
sleep 1
|
||||||
|
PORT=`cat $HTTPSERVEROUT | sed 's/Listening on port \([0-9]*\)/\1/' `
|
||||||
|
done
|
||||||
|
echo "Test HTTP server is listening on $PORT"
|
||||||
|
|
||||||
|
URL1="http://$ADDR:$PORT/index.html"
|
||||||
|
URL2="http://$ADDR:$PORT/chunked"
|
||||||
|
URL3="http://$ADDR:$PORT/addcrap"
|
||||||
|
|
||||||
|
echo "standard test ..."
|
||||||
|
./testminiwget $URL1 "${DOWNLOADEDFILE}.1"
|
||||||
|
if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.1" ; then
|
||||||
|
echo "ok"
|
||||||
|
else
|
||||||
|
echo "standard test FAILED"
|
||||||
|
RET=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "chunked transfert encoding test ..."
|
||||||
|
./testminiwget $URL2 "${DOWNLOADEDFILE}.2"
|
||||||
|
if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.2" ; then
|
||||||
|
echo "ok"
|
||||||
|
else
|
||||||
|
echo "chunked transfert encoding test FAILED"
|
||||||
|
RET=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "response too long test ..."
|
||||||
|
./testminiwget $URL3 "${DOWNLOADEDFILE}.3"
|
||||||
|
if cmp $EXPECTEDFILE "${DOWNLOADEDFILE}.3" ; then
|
||||||
|
echo "ok"
|
||||||
|
else
|
||||||
|
echo "response too long test FAILED"
|
||||||
|
RET=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# kill the test HTTP server
|
||||||
|
kill $SERVERPID
|
||||||
|
wait $SERVERPID
|
||||||
|
|
||||||
|
# remove temporary files (for success cases)
|
||||||
|
if [ $RET -eq 0 ]; then
|
||||||
|
rm -f "${DOWNLOADEDFILE}.1"
|
||||||
|
rm -f "${DOWNLOADEDFILE}.2"
|
||||||
|
rm -f "${DOWNLOADEDFILE}.3"
|
||||||
|
rm -f $EXPECTEDFILE $HTTPSERVEROUT
|
||||||
|
rmdir ${TMPD}
|
||||||
|
else
|
||||||
|
echo "at least one of the test FAILED"
|
||||||
|
echo "directory ${TMPD} is left intact"
|
||||||
|
fi
|
||||||
|
exit $RET
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/* $Id: testminixml.c,v 1.9 2013/05/14 19:50:49 nanard Exp $
|
||||||
|
* MiniUPnP project
|
||||||
|
* Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* Author : Thomas Bernard.
|
||||||
|
* Copyright (c) 2005-2013 Thomas Bernard
|
||||||
|
*
|
||||||
|
* testminixml.c
|
||||||
|
* test program for the "minixml" functions.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "minixml.h"
|
||||||
|
#include "igd_desc_parse.h"
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
void printeltname1(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
(void)d;
|
||||||
|
printf("element ");
|
||||||
|
for(i=0;i<l;i++)
|
||||||
|
putchar(name[i]);
|
||||||
|
}
|
||||||
|
void printeltname2(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
(void)d;
|
||||||
|
putchar('/');
|
||||||
|
for(i=0;i<l;i++)
|
||||||
|
putchar(name[i]);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
void printdata(void *d, const char * data, int l)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
(void)d;
|
||||||
|
printf("data : ");
|
||||||
|
for(i=0;i<l;i++)
|
||||||
|
putchar(data[i]);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void burptest(const char * buffer, int bufsize)
|
||||||
|
{
|
||||||
|
struct IGDdatas data;
|
||||||
|
struct xmlparser parser;
|
||||||
|
/*objet IGDdatas */
|
||||||
|
memset(&data, 0, sizeof(struct IGDdatas));
|
||||||
|
/* objet xmlparser */
|
||||||
|
parser.xmlstart = buffer;
|
||||||
|
parser.xmlsize = bufsize;
|
||||||
|
parser.data = &data;
|
||||||
|
/*parser.starteltfunc = printeltname1;
|
||||||
|
parser.endeltfunc = printeltname2;
|
||||||
|
parser.datafunc = printdata; */
|
||||||
|
parser.starteltfunc = IGDstartelt;
|
||||||
|
parser.endeltfunc = IGDendelt;
|
||||||
|
parser.datafunc = IGDdata;
|
||||||
|
parsexml(&parser);
|
||||||
|
printIGD(&data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----- main ---- */
|
||||||
|
#define XML_MAX_SIZE (8192)
|
||||||
|
int main(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
FILE * f;
|
||||||
|
char buffer[XML_MAX_SIZE];
|
||||||
|
int bufsize;
|
||||||
|
if(argc<2)
|
||||||
|
{
|
||||||
|
printf("usage:\t%s file.xml\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
f = fopen(argv[1], "r");
|
||||||
|
if(!f)
|
||||||
|
{
|
||||||
|
printf("cannot open file %s\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
bufsize = (int)fread(buffer, 1, XML_MAX_SIZE, f);
|
||||||
|
fclose(f);
|
||||||
|
burptest(buffer, bufsize);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
NewRemoteHost=
|
||||||
|
NewExternalPort=123
|
||||||
|
NewProtocol=TCP
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:DeletePortMapping xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"><NewRemoteHost></NewRemoteHost><NewExternalPort>123</NewExternalPort>
|
||||||
|
<NewProtocol>TCP</NewProtocol></u:DeletePortMapping></s:Body>
|
||||||
|
|
||||||
|
</s:Envelope>
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
NewExternalIPAddress=1.2.3.4
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetExternalIPAddressResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"><NewExternalIPAddress>1.2.3.4</NewExternalIPAddress></u:GetExternalIPAddressResponse></s:Body></s:Envelope>
|
||||||
|
|
3
external/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue
vendored
Executable file
3
external/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue
vendored
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
NewProtocol=UDP
|
||||||
|
NewExternalPort=12345
|
||||||
|
NewRemoteHost=
|
|
@ -0,0 +1,3 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetSpecificPortMappingEntry xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"><NewRemoteHost></NewRemoteHost><NewExternalPort>12345</NewExternalPort><NewProtocol>UDP</NewProtocol></u:GetSpecificPortMappingEntry></s:Body></s:Envelope>
|
||||||
|
|
5
external/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue
vendored
Executable file
5
external/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue
vendored
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
NewInternalPort=12345
|
||||||
|
NewInternalClient=192.168.10.110
|
||||||
|
NewEnabled=1
|
||||||
|
NewPortMappingDescription=libminiupnpc
|
||||||
|
NewLeaseDuration=0
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetSpecificPortMappingEntryResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"><NewInternalPort>12345</NewInternalPort><NewInternalClient>192.168.10.110</NewInternalClient><NewEnabled>1</NewEnabled><NewPortMappingDescription>libminiupnpc</NewPortMappingDescription><NewLeaseDuration>0</NewLeaseDuration></u:GetSpecificPortMappingEntryResponse></s:Body></s:Envelope>
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
NewDefaultConnectionService=uuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID
|
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?><s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><u:SetDefaultConnectionService xmlns:u="urn:schemas-upnp-org:service:Layer3Forwarding:1"><NewDefaultConnectionService>uuid:c6c05a33-f704-48df-9910-e099b3471d81:WANConnectionDevice:1,INVALID_SERVICE_ID</NewDefaultConnectionService></u:SetDefaultConnectionService></s:Body></s:Envelope>
|
|
@ -0,0 +1,7 @@
|
||||||
|
This directory contains files used for validation of upnpreplyparse.c code.
|
||||||
|
|
||||||
|
Each .xml file to parse should give the results which are in the .namevalue
|
||||||
|
file.
|
||||||
|
|
||||||
|
A .namevalue file contain name=value lines.
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
#! /usr/bin/python
|
||||||
|
# $Id: testupnpigd.py,v 1.4 2008/10/11 10:27:20 nanard Exp $
|
||||||
|
# MiniUPnP project
|
||||||
|
# Author : Thomas Bernard
|
||||||
|
# This Sample code is public domain.
|
||||||
|
# website : http://miniupnp.tuxfamily.org/
|
||||||
|
|
||||||
|
# import the python miniupnpc module
|
||||||
|
import miniupnpc
|
||||||
|
import socket
|
||||||
|
import BaseHTTPServer
|
||||||
|
|
||||||
|
# function definition
|
||||||
|
def list_redirections():
|
||||||
|
i = 0
|
||||||
|
while True:
|
||||||
|
p = u.getgenericportmapping(i)
|
||||||
|
if p==None:
|
||||||
|
break
|
||||||
|
print i, p
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
|
#define the handler class for HTTP connections
|
||||||
|
class handler_class(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||||
|
def do_GET(self):
|
||||||
|
self.send_response(200)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write("OK MON GARS")
|
||||||
|
|
||||||
|
# create the object
|
||||||
|
u = miniupnpc.UPnP()
|
||||||
|
#print 'inital(default) values :'
|
||||||
|
#print ' discoverdelay', u.discoverdelay
|
||||||
|
#print ' lanaddr', u.lanaddr
|
||||||
|
#print ' multicastif', u.multicastif
|
||||||
|
#print ' minissdpdsocket', u.minissdpdsocket
|
||||||
|
u.discoverdelay = 200;
|
||||||
|
|
||||||
|
try:
|
||||||
|
print 'Discovering... delay=%ums' % u.discoverdelay
|
||||||
|
ndevices = u.discover()
|
||||||
|
print ndevices, 'device(s) detected'
|
||||||
|
|
||||||
|
# select an igd
|
||||||
|
u.selectigd()
|
||||||
|
# display information about the IGD and the internet connection
|
||||||
|
print 'local ip address :', u.lanaddr
|
||||||
|
externalipaddress = u.externalipaddress()
|
||||||
|
print 'external ip address :', externalipaddress
|
||||||
|
print u.statusinfo(), u.connectiontype()
|
||||||
|
|
||||||
|
#instanciate a HTTPd object. The port is assigned by the system.
|
||||||
|
httpd = BaseHTTPServer.HTTPServer((u.lanaddr, 0), handler_class)
|
||||||
|
eport = httpd.server_port
|
||||||
|
|
||||||
|
# find a free port for the redirection
|
||||||
|
r = u.getspecificportmapping(eport, 'TCP')
|
||||||
|
while r != None and eport < 65536:
|
||||||
|
eport = eport + 1
|
||||||
|
r = u.getspecificportmapping(eport, 'TCP')
|
||||||
|
|
||||||
|
print 'trying to redirect %s port %u TCP => %s port %u TCP' % (externalipaddress, eport, u.lanaddr, httpd.server_port)
|
||||||
|
|
||||||
|
b = u.addportmapping(eport, 'TCP', u.lanaddr, httpd.server_port,
|
||||||
|
'UPnP IGD Tester port %u' % eport, '')
|
||||||
|
if b:
|
||||||
|
print 'Success. Now waiting for some HTTP request on http://%s:%u' % (externalipaddress ,eport)
|
||||||
|
try:
|
||||||
|
httpd.handle_request()
|
||||||
|
httpd.server_close()
|
||||||
|
except KeyboardInterrupt, details:
|
||||||
|
print "CTRL-C exception!", details
|
||||||
|
b = u.deleteportmapping(eport, 'TCP')
|
||||||
|
if b:
|
||||||
|
print 'Successfully deleted port mapping'
|
||||||
|
else:
|
||||||
|
print 'Failed to remove port mapping'
|
||||||
|
else:
|
||||||
|
print 'Failed'
|
||||||
|
|
||||||
|
httpd.server_close()
|
||||||
|
|
||||||
|
except Exception, e:
|
||||||
|
print 'Exception :', e
|
|
@ -0,0 +1,96 @@
|
||||||
|
/* $Id: testupnpreplyparse.c,v 1.4 2014/01/27 11:45:19 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* (c) 2006-2014 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed
|
||||||
|
* in the LICENCE file provided within the distribution */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "upnpreplyparse.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
test_parsing(const char * buf, int len, FILE * f)
|
||||||
|
{
|
||||||
|
char line[1024];
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
int ok = 1;
|
||||||
|
ParseNameValue(buf, len, &pdata);
|
||||||
|
/* check result */
|
||||||
|
if(f != NULL)
|
||||||
|
{
|
||||||
|
while(fgets(line, sizeof(line), f))
|
||||||
|
{
|
||||||
|
char * value;
|
||||||
|
char * equal;
|
||||||
|
char * parsedvalue;
|
||||||
|
int l;
|
||||||
|
l = strlen(line);
|
||||||
|
while((l > 0) && ((line[l-1] == '\r') || (line[l-1] == '\n')))
|
||||||
|
line[--l] = '\0';
|
||||||
|
/* skip empty lines */
|
||||||
|
if(l == 0)
|
||||||
|
continue;
|
||||||
|
equal = strchr(line, '=');
|
||||||
|
if(equal == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Warning, line does not contain '=' : %s\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*equal = '\0';
|
||||||
|
value = equal + 1;
|
||||||
|
parsedvalue = GetValueFromNameValueList(&pdata, line);
|
||||||
|
if((parsedvalue == NULL) || (strcmp(parsedvalue, value) != 0))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Element <%s> : expecting value '%s', got '%s'\n",
|
||||||
|
line, value, parsedvalue ? parsedvalue : "<null string>");
|
||||||
|
ok = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
FILE * f;
|
||||||
|
char buffer[4096];
|
||||||
|
int l;
|
||||||
|
int ok;
|
||||||
|
|
||||||
|
if(argc<2)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s file.xml [file.namevalues]\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
f = fopen(argv[1], "r");
|
||||||
|
if(!f)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error : can not open file %s\n", argv[1]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
l = fread(buffer, 1, sizeof(buffer)-1, f);
|
||||||
|
fclose(f);
|
||||||
|
f = NULL;
|
||||||
|
buffer[l] = '\0';
|
||||||
|
if(argc > 2)
|
||||||
|
{
|
||||||
|
f = fopen(argv[2], "r");
|
||||||
|
if(!f)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error : can not open file %s\n", argv[2]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
DisplayNameValueList(buffer, l);
|
||||||
|
#endif
|
||||||
|
ok = test_parsing(buffer, l, f);
|
||||||
|
if(f)
|
||||||
|
{
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
return ok ? 0 : 3;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
for f in testreplyparse/*.xml ; do
|
||||||
|
bf="`dirname $f`/`basename $f .xml`"
|
||||||
|
if ./testupnpreplyparse $f $bf.namevalue ; then
|
||||||
|
echo "$f : passed"
|
||||||
|
else
|
||||||
|
echo "$f : FAILED"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
#! /bin/sh
|
||||||
|
# $Id: updateminiupnpcstrings.sh,v 1.7 2011/01/04 11:41:53 nanard Exp $
|
||||||
|
# project miniupnp : http://miniupnp.free.fr/
|
||||||
|
# (c) 2009 Thomas Bernard
|
||||||
|
|
||||||
|
FILE=miniupnpcstrings.h
|
||||||
|
TMPFILE=miniupnpcstrings.h.tmp
|
||||||
|
TEMPLATE_FILE=${FILE}.in
|
||||||
|
|
||||||
|
# detecting the OS name and version
|
||||||
|
OS_NAME=`uname -s`
|
||||||
|
OS_VERSION=`uname -r`
|
||||||
|
if [ -f /etc/debian_version ]; then
|
||||||
|
OS_NAME=Debian
|
||||||
|
OS_VERSION=`cat /etc/debian_version`
|
||||||
|
fi
|
||||||
|
# use lsb_release (Linux Standard Base) when available
|
||||||
|
LSB_RELEASE=`which lsb_release`
|
||||||
|
if [ 0 -eq $? -a -x "${LSB_RELEASE}" ]; then
|
||||||
|
OS_NAME=`${LSB_RELEASE} -i -s`
|
||||||
|
OS_VERSION=`${LSB_RELEASE} -r -s`
|
||||||
|
case $OS_NAME in
|
||||||
|
Debian)
|
||||||
|
#OS_VERSION=`${LSB_RELEASE} -c -s`
|
||||||
|
;;
|
||||||
|
Ubuntu)
|
||||||
|
#OS_VERSION=`${LSB_RELEASE} -c -s`
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# on AmigaOS 3, uname -r returns "unknown", so we use uname -v
|
||||||
|
if [ "$OS_NAME" = "AmigaOS" ]; then
|
||||||
|
if [ "$OS_VERSION" = "unknown" ]; then
|
||||||
|
OS_VERSION=`uname -v`
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Detected OS [$OS_NAME] version [$OS_VERSION]"
|
||||||
|
MINIUPNPC_VERSION=`cat VERSION`
|
||||||
|
echo "MiniUPnPc version [${MINIUPNPC_VERSION}]"
|
||||||
|
|
||||||
|
EXPR="s|OS_STRING \".*\"|OS_STRING \"${OS_NAME}/${OS_VERSION}\"|"
|
||||||
|
#echo $EXPR
|
||||||
|
test -f ${FILE}.in
|
||||||
|
echo "setting OS_STRING macro value to ${OS_NAME}/${OS_VERSION} in $FILE."
|
||||||
|
sed -e "$EXPR" < $TEMPLATE_FILE > $TMPFILE
|
||||||
|
|
||||||
|
EXPR="s|MINIUPNPC_VERSION_STRING \".*\"|MINIUPNPC_VERSION_STRING \"${MINIUPNPC_VERSION}\"|"
|
||||||
|
echo "setting MINIUPNPC_VERSION_STRING macro value to ${MINIUPNPC_VERSION} in $FILE."
|
||||||
|
sed -e "$EXPR" < $TMPFILE > $FILE
|
||||||
|
rm $TMPFILE
|
||||||
|
|
|
@ -0,0 +1,720 @@
|
||||||
|
/* $Id: upnpc.c,v 1.102 2014/02/05 17:27:14 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2014 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided in this distribution. */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#else
|
||||||
|
/* for IPPROTO_TCP / IPPROTO_UDP */
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif
|
||||||
|
#include "miniwget.h"
|
||||||
|
#include "miniupnpc.h"
|
||||||
|
#include "upnpcommands.h"
|
||||||
|
#include "upnperrors.h"
|
||||||
|
|
||||||
|
/* protofix() checks if protocol is "UDP" or "TCP"
|
||||||
|
* returns NULL if not */
|
||||||
|
const char * protofix(const char * proto)
|
||||||
|
{
|
||||||
|
static const char proto_tcp[4] = { 'T', 'C', 'P', 0};
|
||||||
|
static const char proto_udp[4] = { 'U', 'D', 'P', 0};
|
||||||
|
int i, b;
|
||||||
|
for(i=0, b=1; i<4; i++)
|
||||||
|
b = b && ( (proto[i] == proto_tcp[i])
|
||||||
|
|| (proto[i] == (proto_tcp[i] | 32)) );
|
||||||
|
if(b)
|
||||||
|
return proto_tcp;
|
||||||
|
for(i=0, b=1; i<4; i++)
|
||||||
|
b = b && ( (proto[i] == proto_udp[i])
|
||||||
|
|| (proto[i] == (proto_udp[i] | 32)) );
|
||||||
|
if(b)
|
||||||
|
return proto_udp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DisplayInfos(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data)
|
||||||
|
{
|
||||||
|
char externalIPAddress[40];
|
||||||
|
char connectionType[64];
|
||||||
|
char status[64];
|
||||||
|
char lastconnerr[64];
|
||||||
|
unsigned int uptime;
|
||||||
|
unsigned int brUp, brDown;
|
||||||
|
time_t timenow, timestarted;
|
||||||
|
int r;
|
||||||
|
if(UPNP_GetConnectionTypeInfo(urls->controlURL,
|
||||||
|
data->first.servicetype,
|
||||||
|
connectionType) != UPNPCOMMAND_SUCCESS)
|
||||||
|
printf("GetConnectionTypeInfo failed.\n");
|
||||||
|
else
|
||||||
|
printf("Connection Type : %s\n", connectionType);
|
||||||
|
if(UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
|
||||||
|
status, &uptime, lastconnerr) != UPNPCOMMAND_SUCCESS)
|
||||||
|
printf("GetStatusInfo failed.\n");
|
||||||
|
else
|
||||||
|
printf("Status : %s, uptime=%us, LastConnectionError : %s\n",
|
||||||
|
status, uptime, lastconnerr);
|
||||||
|
timenow = time(NULL);
|
||||||
|
timestarted = timenow - uptime;
|
||||||
|
printf(" Time started : %s", ctime(×tarted));
|
||||||
|
if(UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype,
|
||||||
|
&brDown, &brUp) != UPNPCOMMAND_SUCCESS) {
|
||||||
|
printf("GetLinkLayerMaxBitRates failed.\n");
|
||||||
|
} else {
|
||||||
|
printf("MaxBitRateDown : %u bps", brDown);
|
||||||
|
if(brDown >= 1000000) {
|
||||||
|
printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10);
|
||||||
|
} else if(brDown >= 1000) {
|
||||||
|
printf(" (%u Kbps)", brDown / 1000);
|
||||||
|
}
|
||||||
|
printf(" MaxBitRateUp %u bps", brUp);
|
||||||
|
if(brUp >= 1000000) {
|
||||||
|
printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10);
|
||||||
|
} else if(brUp >= 1000) {
|
||||||
|
printf(" (%u Kbps)", brUp / 1000);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
r = UPNP_GetExternalIPAddress(urls->controlURL,
|
||||||
|
data->first.servicetype,
|
||||||
|
externalIPAddress);
|
||||||
|
if(r != UPNPCOMMAND_SUCCESS) {
|
||||||
|
printf("GetExternalIPAddress failed. (errorcode=%d)\n", r);
|
||||||
|
} else {
|
||||||
|
printf("ExternalIPAddress = %s\n", externalIPAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GetConnectionStatus(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data)
|
||||||
|
{
|
||||||
|
unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
|
||||||
|
DisplayInfos(urls, data);
|
||||||
|
bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
|
||||||
|
bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
|
||||||
|
packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
|
||||||
|
packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
|
||||||
|
printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
|
||||||
|
printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ListRedirections(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
int i = 0;
|
||||||
|
char index[6];
|
||||||
|
char intClient[40];
|
||||||
|
char intPort[6];
|
||||||
|
char extPort[6];
|
||||||
|
char protocol[4];
|
||||||
|
char desc[80];
|
||||||
|
char enabled[6];
|
||||||
|
char rHost[64];
|
||||||
|
char duration[16];
|
||||||
|
/*unsigned int num=0;
|
||||||
|
UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num);
|
||||||
|
printf("PortMappingNumberOfEntries : %u\n", num);*/
|
||||||
|
printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
|
||||||
|
do {
|
||||||
|
snprintf(index, 6, "%d", i);
|
||||||
|
rHost[0] = '\0'; enabled[0] = '\0';
|
||||||
|
duration[0] = '\0'; desc[0] = '\0';
|
||||||
|
extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
|
||||||
|
r = UPNP_GetGenericPortMappingEntry(urls->controlURL,
|
||||||
|
data->first.servicetype,
|
||||||
|
index,
|
||||||
|
extPort, intClient, intPort,
|
||||||
|
protocol, desc, enabled,
|
||||||
|
rHost, duration);
|
||||||
|
if(r==0)
|
||||||
|
/*
|
||||||
|
printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n"
|
||||||
|
" desc='%s' rHost='%s'\n",
|
||||||
|
i, protocol, extPort, intClient, intPort,
|
||||||
|
enabled, duration,
|
||||||
|
desc, rHost);
|
||||||
|
*/
|
||||||
|
printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n",
|
||||||
|
i, protocol, extPort, intClient, intPort,
|
||||||
|
desc, rHost, duration);
|
||||||
|
else
|
||||||
|
printf("GetGenericPortMappingEntry() returned %d (%s)\n",
|
||||||
|
r, strupnperror(r));
|
||||||
|
i++;
|
||||||
|
} while(r==0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NewListRedirections(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
int i = 0;
|
||||||
|
struct PortMappingParserData pdata;
|
||||||
|
struct PortMapping * pm;
|
||||||
|
|
||||||
|
memset(&pdata, 0, sizeof(struct PortMappingParserData));
|
||||||
|
r = UPNP_GetListOfPortMappings(urls->controlURL,
|
||||||
|
data->first.servicetype,
|
||||||
|
"0",
|
||||||
|
"65535",
|
||||||
|
"TCP",
|
||||||
|
"1000",
|
||||||
|
&pdata);
|
||||||
|
if(r == UPNPCOMMAND_SUCCESS)
|
||||||
|
{
|
||||||
|
printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
|
||||||
|
for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next)
|
||||||
|
{
|
||||||
|
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
|
||||||
|
i, pm->protocol, pm->externalPort, pm->internalClient,
|
||||||
|
pm->internalPort,
|
||||||
|
pm->description, pm->remoteHost,
|
||||||
|
(unsigned)pm->leaseTime);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
FreePortListing(&pdata);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("GetListOfPortMappings() returned %d (%s)\n",
|
||||||
|
r, strupnperror(r));
|
||||||
|
}
|
||||||
|
r = UPNP_GetListOfPortMappings(urls->controlURL,
|
||||||
|
data->first.servicetype,
|
||||||
|
"0",
|
||||||
|
"65535",
|
||||||
|
"UDP",
|
||||||
|
"1000",
|
||||||
|
&pdata);
|
||||||
|
if(r == UPNPCOMMAND_SUCCESS)
|
||||||
|
{
|
||||||
|
for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next)
|
||||||
|
{
|
||||||
|
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
|
||||||
|
i, pm->protocol, pm->externalPort, pm->internalClient,
|
||||||
|
pm->internalPort,
|
||||||
|
pm->description, pm->remoteHost,
|
||||||
|
(unsigned)pm->leaseTime);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
FreePortListing(&pdata);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("GetListOfPortMappings() returned %d (%s)\n",
|
||||||
|
r, strupnperror(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test function
|
||||||
|
* 1 - get connection type
|
||||||
|
* 2 - get extenal ip address
|
||||||
|
* 3 - Add port mapping
|
||||||
|
* 4 - get this port mapping from the IGD */
|
||||||
|
static void SetRedirectAndTest(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data,
|
||||||
|
const char * iaddr,
|
||||||
|
const char * iport,
|
||||||
|
const char * eport,
|
||||||
|
const char * proto,
|
||||||
|
const char * leaseDuration,
|
||||||
|
const char * description)
|
||||||
|
{
|
||||||
|
char externalIPAddress[40];
|
||||||
|
char intClient[40];
|
||||||
|
char intPort[6];
|
||||||
|
char duration[16];
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if(!iaddr || !iport || !eport || !proto)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Wrong arguments\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
proto = protofix(proto);
|
||||||
|
if(!proto)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "invalid protocol\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UPNP_GetExternalIPAddress(urls->controlURL,
|
||||||
|
data->first.servicetype,
|
||||||
|
externalIPAddress);
|
||||||
|
if(externalIPAddress[0])
|
||||||
|
printf("ExternalIPAddress = %s\n", externalIPAddress);
|
||||||
|
else
|
||||||
|
printf("GetExternalIPAddress failed.\n");
|
||||||
|
|
||||||
|
r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype,
|
||||||
|
eport, iport, iaddr, description,
|
||||||
|
proto, 0, leaseDuration);
|
||||||
|
if(r!=UPNPCOMMAND_SUCCESS)
|
||||||
|
printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
|
||||||
|
eport, iport, iaddr, r, strupnperror(r));
|
||||||
|
|
||||||
|
r = UPNP_GetSpecificPortMappingEntry(urls->controlURL,
|
||||||
|
data->first.servicetype,
|
||||||
|
eport, proto, NULL/*remoteHost*/,
|
||||||
|
intClient, intPort, NULL/*desc*/,
|
||||||
|
NULL/*enabled*/, duration);
|
||||||
|
if(r!=UPNPCOMMAND_SUCCESS)
|
||||||
|
printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n",
|
||||||
|
r, strupnperror(r));
|
||||||
|
|
||||||
|
if(intClient[0]) {
|
||||||
|
printf("InternalIP:Port = %s:%s\n", intClient, intPort);
|
||||||
|
printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n",
|
||||||
|
externalIPAddress, eport, proto, intClient, intPort, duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
RemoveRedirect(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data,
|
||||||
|
const char * eport,
|
||||||
|
const char * proto)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
if(!proto || !eport)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "invalid arguments\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
proto = protofix(proto);
|
||||||
|
if(!proto)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "protocol invalid\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, 0);
|
||||||
|
printf("UPNP_DeletePortMapping() returned : %d\n", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IGD:2, functions for service WANIPv6FirewallControl:1 */
|
||||||
|
static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data)
|
||||||
|
{
|
||||||
|
unsigned int bytessent, bytesreceived, packetsreceived, packetssent;
|
||||||
|
int firewallEnabled = 0, inboundPinholeAllowed = 0;
|
||||||
|
|
||||||
|
UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed);
|
||||||
|
printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed);
|
||||||
|
printf("GetFirewallStatus:\n Firewall Enabled: %s\n Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No");
|
||||||
|
|
||||||
|
bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype);
|
||||||
|
bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype);
|
||||||
|
packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype);
|
||||||
|
packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype);
|
||||||
|
printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived);
|
||||||
|
printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test function
|
||||||
|
* 1 - Add pinhole
|
||||||
|
* 2 - Check if pinhole is working from the IGD side */
|
||||||
|
static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||||
|
const char * remoteaddr, const char * eport,
|
||||||
|
const char * intaddr, const char * iport,
|
||||||
|
const char * proto, const char * lease_time)
|
||||||
|
{
|
||||||
|
char uniqueID[8];
|
||||||
|
/*int isWorking = 0;*/
|
||||||
|
int r;
|
||||||
|
char proto_tmp[8];
|
||||||
|
|
||||||
|
if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Wrong arguments\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(atoi(proto) == 0)
|
||||||
|
{
|
||||||
|
const char * protocol;
|
||||||
|
protocol = protofix(proto);
|
||||||
|
if(protocol && (strcmp("TCP", protocol) == 0))
|
||||||
|
{
|
||||||
|
snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_TCP);
|
||||||
|
proto = proto_tmp;
|
||||||
|
}
|
||||||
|
else if(protocol && (strcmp("UDP", protocol) == 0))
|
||||||
|
{
|
||||||
|
snprintf(proto_tmp, sizeof(proto_tmp), "%d", IPPROTO_UDP);
|
||||||
|
proto = proto_tmp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "invalid protocol\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID);
|
||||||
|
if(r!=UPNPCOMMAND_SUCCESS)
|
||||||
|
printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
|
||||||
|
remoteaddr, eport, intaddr, iport, r, strupnperror(r));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n",
|
||||||
|
remoteaddr, eport, intaddr, iport, uniqueID);
|
||||||
|
/*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking);
|
||||||
|
if(r!=UPNPCOMMAND_SUCCESS)
|
||||||
|
printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
|
||||||
|
printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test function
|
||||||
|
* 1 - Check if pinhole is working from the IGD side
|
||||||
|
* 2 - Update pinhole */
|
||||||
|
static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||||
|
const char * uniqueID, const char * lease_time)
|
||||||
|
{
|
||||||
|
int isWorking = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if(!uniqueID || !lease_time)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Wrong arguments\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
|
||||||
|
printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
|
||||||
|
if(r!=UPNPCOMMAND_SUCCESS)
|
||||||
|
printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
|
||||||
|
if(isWorking || r==709)
|
||||||
|
{
|
||||||
|
r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time);
|
||||||
|
printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time);
|
||||||
|
if(r!=UPNPCOMMAND_SUCCESS)
|
||||||
|
printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test function
|
||||||
|
* Get pinhole timeout
|
||||||
|
*/
|
||||||
|
static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data,
|
||||||
|
const char * remoteaddr, const char * eport,
|
||||||
|
const char * intaddr, const char * iport,
|
||||||
|
const char * proto)
|
||||||
|
{
|
||||||
|
int timeout = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if(!intaddr || !remoteaddr || !iport || !eport || !proto)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Wrong arguments\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout);
|
||||||
|
if(r!=UPNPCOMMAND_SUCCESS)
|
||||||
|
printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n",
|
||||||
|
intaddr, iport, remoteaddr, eport, r, strupnperror(r));
|
||||||
|
else
|
||||||
|
printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
GetPinholePackets(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data, const char * uniqueID)
|
||||||
|
{
|
||||||
|
int r, pinholePackets = 0;
|
||||||
|
if(!uniqueID)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "invalid arguments\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets);
|
||||||
|
if(r!=UPNPCOMMAND_SUCCESS)
|
||||||
|
printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r));
|
||||||
|
else
|
||||||
|
printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
CheckPinhole(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data, const char * uniqueID)
|
||||||
|
{
|
||||||
|
int r, isWorking = 0;
|
||||||
|
if(!uniqueID)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "invalid arguments\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking);
|
||||||
|
if(r!=UPNPCOMMAND_SUCCESS)
|
||||||
|
printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r));
|
||||||
|
else
|
||||||
|
printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
RemovePinhole(struct UPNPUrls * urls,
|
||||||
|
struct IGDdatas * data, const char * uniqueID)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
if(!uniqueID)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "invalid arguments\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID);
|
||||||
|
printf("UPNP_DeletePinhole() returned : %d\n", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* sample upnp client program */
|
||||||
|
int main(int argc, char ** argv)
|
||||||
|
{
|
||||||
|
char command = 0;
|
||||||
|
char ** commandargv = 0;
|
||||||
|
int commandargc = 0;
|
||||||
|
struct UPNPDev * devlist = 0;
|
||||||
|
char lanaddr[64]; /* my ip address on the LAN */
|
||||||
|
int i;
|
||||||
|
const char * rootdescurl = 0;
|
||||||
|
const char * multicastif = 0;
|
||||||
|
const char * minissdpdpath = 0;
|
||||||
|
int retcode = 0;
|
||||||
|
int error = 0;
|
||||||
|
int ipv6 = 0;
|
||||||
|
const char * description = 0;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSADATA wsaData;
|
||||||
|
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
|
||||||
|
if(nResult != NO_ERROR)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "WSAStartup() failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
printf("upnpc : miniupnpc library test client. (c) 2005-2014 Thomas Bernard\n");
|
||||||
|
printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n"
|
||||||
|
"for more information.\n");
|
||||||
|
/* command line processing */
|
||||||
|
for(i=1; i<argc; i++)
|
||||||
|
{
|
||||||
|
if(0 == strcmp(argv[i], "--help") || 0 == strcmp(argv[i], "-h"))
|
||||||
|
{
|
||||||
|
command = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(argv[i][0] == '-')
|
||||||
|
{
|
||||||
|
if(argv[i][1] == 'u')
|
||||||
|
rootdescurl = argv[++i];
|
||||||
|
else if(argv[i][1] == 'm')
|
||||||
|
multicastif = argv[++i];
|
||||||
|
else if(argv[i][1] == 'p')
|
||||||
|
minissdpdpath = argv[++i];
|
||||||
|
else if(argv[i][1] == '6')
|
||||||
|
ipv6 = 1;
|
||||||
|
else if(argv[i][1] == 'e')
|
||||||
|
description = argv[++i];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command = argv[i][1];
|
||||||
|
i++;
|
||||||
|
commandargv = argv + i;
|
||||||
|
commandargc = argc - i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "option '%s' invalid\n", argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!command || (command == 'a' && commandargc<4)
|
||||||
|
|| (command == 'd' && argc<2)
|
||||||
|
|| (command == 'r' && argc<2)
|
||||||
|
|| (command == 'A' && commandargc<6)
|
||||||
|
|| (command == 'U' && commandargc<2)
|
||||||
|
|| (command == 'D' && commandargc<1))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration]\n\t\tAdd port redirection\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -d external_port protocol [port2 protocol2] [...]\n\t\tDelete port redirection\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings, IGD v2)\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -r port1 protocol1 [port2 protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -G remote_ip remote_port internal_ip internal_port protocol\n\t\tGet Outbound Pinhole Timeout (for IGD:2 only)\n", argv[0]);
|
||||||
|
fprintf(stderr, " \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]);
|
||||||
|
fprintf(stderr, "\nprotocol is UDP or TCP\n");
|
||||||
|
fprintf(stderr, "Options:\n");
|
||||||
|
fprintf(stderr, " -e description : set description for port mapping.\n");
|
||||||
|
fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n");
|
||||||
|
fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n");
|
||||||
|
fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n");
|
||||||
|
fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rootdescurl
|
||||||
|
|| (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
|
||||||
|
0/*sameport*/, ipv6, &error)))
|
||||||
|
{
|
||||||
|
struct UPNPDev * device;
|
||||||
|
struct UPNPUrls urls;
|
||||||
|
struct IGDdatas data;
|
||||||
|
if(devlist)
|
||||||
|
{
|
||||||
|
printf("List of UPNP devices found on the network :\n");
|
||||||
|
for(device = devlist; device; device = device->pNext)
|
||||||
|
{
|
||||||
|
printf(" desc: %s\n st: %s\n\n",
|
||||||
|
device->descURL, device->st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("upnpDiscover() error code=%d\n", error);
|
||||||
|
}
|
||||||
|
i = 1;
|
||||||
|
if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr)))
|
||||||
|
|| (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr))))
|
||||||
|
{
|
||||||
|
switch(i) {
|
||||||
|
case 1:
|
||||||
|
printf("Found valid IGD : %s\n", urls.controlURL);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
printf("Found a (not connected?) IGD : %s\n", urls.controlURL);
|
||||||
|
printf("Trying to continue anyway\n");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL);
|
||||||
|
printf("Trying to continue anyway\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Found device (igd ?) : %s\n", urls.controlURL);
|
||||||
|
printf("Trying to continue anyway\n");
|
||||||
|
}
|
||||||
|
printf("Local LAN ip address : %s\n", lanaddr);
|
||||||
|
#if 0
|
||||||
|
printf("getting \"%s\"\n", urls.ipcondescURL);
|
||||||
|
descXML = miniwget(urls.ipcondescURL, &descXMLsize);
|
||||||
|
if(descXML)
|
||||||
|
{
|
||||||
|
/*fwrite(descXML, 1, descXMLsize, stdout);*/
|
||||||
|
free(descXML); descXML = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch(command)
|
||||||
|
{
|
||||||
|
case 'l':
|
||||||
|
DisplayInfos(&urls, &data);
|
||||||
|
ListRedirections(&urls, &data);
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
NewListRedirections(&urls, &data);
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
SetRedirectAndTest(&urls, &data,
|
||||||
|
commandargv[0], commandargv[1],
|
||||||
|
commandargv[2], commandargv[3],
|
||||||
|
(commandargc > 4)?commandargv[4]:"0",
|
||||||
|
description);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
for(i=0; i<commandargc; i+=2)
|
||||||
|
{
|
||||||
|
RemoveRedirect(&urls, &data, commandargv[i], commandargv[i+1]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
GetConnectionStatus(&urls, &data);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
for(i=0; i<commandargc; i+=2)
|
||||||
|
{
|
||||||
|
/*printf("port %s protocol %s\n", argv[i], argv[i+1]);*/
|
||||||
|
SetRedirectAndTest(&urls, &data,
|
||||||
|
lanaddr, commandargv[i],
|
||||||
|
commandargv[i], commandargv[i+1], "0",
|
||||||
|
description);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
SetPinholeAndTest(&urls, &data,
|
||||||
|
commandargv[0], commandargv[1],
|
||||||
|
commandargv[2], commandargv[3],
|
||||||
|
commandargv[4], commandargv[5]);
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
GetPinholeAndUpdate(&urls, &data,
|
||||||
|
commandargv[0], commandargv[1]);
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
for(i=0; i<commandargc; i++)
|
||||||
|
{
|
||||||
|
CheckPinhole(&urls, &data, commandargv[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'K':
|
||||||
|
for(i=0; i<commandargc; i++)
|
||||||
|
{
|
||||||
|
GetPinholePackets(&urls, &data, commandargv[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
for(i=0; i<commandargc; i++)
|
||||||
|
{
|
||||||
|
RemovePinhole(&urls, &data, commandargv[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
GetFirewallStatus(&urls, &data);
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
GetPinholeOutboundTimeout(&urls, &data,
|
||||||
|
commandargv[0], commandargv[1],
|
||||||
|
commandargv[2], commandargv[3],
|
||||||
|
commandargv[4]);
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
printf("Presentation URL found:\n");
|
||||||
|
printf(" %s\n", data.presentationurl);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown switch -%c\n", command);
|
||||||
|
retcode = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeUPNPUrls(&urls);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n");
|
||||||
|
retcode = 1;
|
||||||
|
}
|
||||||
|
freeUPNPDevlist(devlist); devlist = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "No IGD UPnP Device found on the network !\n");
|
||||||
|
retcode = 1;
|
||||||
|
}
|
||||||
|
return retcode;
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,293 @@
|
||||||
|
/* $Id: upnpcommands.h,v 1.27 2014/02/17 15:38:26 nanard Exp $ */
|
||||||
|
/* Miniupnp project : http://miniupnp.free.fr/
|
||||||
|
* Author : Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2014 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed in the
|
||||||
|
* LICENCE file provided within this distribution */
|
||||||
|
#ifndef UPNPCOMMANDS_H_INCLUDED
|
||||||
|
#define UPNPCOMMANDS_H_INCLUDED
|
||||||
|
|
||||||
|
#include "upnpreplyparse.h"
|
||||||
|
#include "portlistingparse.h"
|
||||||
|
#include "declspec.h"
|
||||||
|
#include "miniupnpctypes.h"
|
||||||
|
|
||||||
|
/* MiniUPnPc return codes : */
|
||||||
|
#define UPNPCOMMAND_SUCCESS (0)
|
||||||
|
#define UPNPCOMMAND_UNKNOWN_ERROR (-1)
|
||||||
|
#define UPNPCOMMAND_INVALID_ARGS (-2)
|
||||||
|
#define UPNPCOMMAND_HTTP_ERROR (-3)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LIBSPEC UNSIGNED_INTEGER
|
||||||
|
UPNP_GetTotalBytesSent(const char * controlURL,
|
||||||
|
const char * servicetype);
|
||||||
|
|
||||||
|
LIBSPEC UNSIGNED_INTEGER
|
||||||
|
UPNP_GetTotalBytesReceived(const char * controlURL,
|
||||||
|
const char * servicetype);
|
||||||
|
|
||||||
|
LIBSPEC UNSIGNED_INTEGER
|
||||||
|
UPNP_GetTotalPacketsSent(const char * controlURL,
|
||||||
|
const char * servicetype);
|
||||||
|
|
||||||
|
LIBSPEC UNSIGNED_INTEGER
|
||||||
|
UPNP_GetTotalPacketsReceived(const char * controlURL,
|
||||||
|
const char * servicetype);
|
||||||
|
|
||||||
|
/* UPNP_GetStatusInfo()
|
||||||
|
* status and lastconnerror are 64 byte buffers
|
||||||
|
* Return values :
|
||||||
|
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||||
|
* or a UPnP Error code */
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetStatusInfo(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
char * status,
|
||||||
|
unsigned int * uptime,
|
||||||
|
char * lastconnerror);
|
||||||
|
|
||||||
|
/* UPNP_GetConnectionTypeInfo()
|
||||||
|
* argument connectionType is a 64 character buffer
|
||||||
|
* Return Values :
|
||||||
|
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||||
|
* or a UPnP Error code */
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetConnectionTypeInfo(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
char * connectionType);
|
||||||
|
|
||||||
|
/* UPNP_GetExternalIPAddress() call the corresponding UPNP method.
|
||||||
|
* if the third arg is not null the value is copied to it.
|
||||||
|
* at least 16 bytes must be available
|
||||||
|
*
|
||||||
|
* Return values :
|
||||||
|
* 0 : SUCCESS
|
||||||
|
* NON ZERO : ERROR Either an UPnP error code or an unknown error.
|
||||||
|
*
|
||||||
|
* possible UPnP Errors :
|
||||||
|
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||||
|
* 501 Action Failed - See UPnP Device Architecture section on Control. */
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetExternalIPAddress(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
char * extIpAdd);
|
||||||
|
|
||||||
|
/* UPNP_GetLinkLayerMaxBitRates()
|
||||||
|
* call WANCommonInterfaceConfig:1#GetCommonLinkProperties
|
||||||
|
*
|
||||||
|
* return values :
|
||||||
|
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||||
|
* or a UPnP Error Code. */
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
|
||||||
|
const char* servicetype,
|
||||||
|
unsigned int * bitrateDown,
|
||||||
|
unsigned int * bitrateUp);
|
||||||
|
|
||||||
|
/* UPNP_AddPortMapping()
|
||||||
|
* if desc is NULL, it will be defaulted to "libminiupnpc"
|
||||||
|
* remoteHost is usually NULL because IGD don't support it.
|
||||||
|
*
|
||||||
|
* Return values :
|
||||||
|
* 0 : SUCCESS
|
||||||
|
* NON ZERO : ERROR. Either an UPnP error code or an unknown error.
|
||||||
|
*
|
||||||
|
* List of possible UPnP errors for AddPortMapping :
|
||||||
|
* errorCode errorDescription (short) - Description (long)
|
||||||
|
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||||
|
* 501 Action Failed - See UPnP Device Architecture section on Control.
|
||||||
|
* 606 Action not authorized - The action requested REQUIRES authorization and
|
||||||
|
* the sender was not authorized.
|
||||||
|
* 715 WildCardNotPermittedInSrcIP - The source IP address cannot be
|
||||||
|
* wild-carded
|
||||||
|
* 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded
|
||||||
|
* 718 ConflictInMappingEntry - The port mapping entry specified conflicts
|
||||||
|
* with a mapping assigned previously to another client
|
||||||
|
* 724 SamePortValuesRequired - Internal and External port values
|
||||||
|
* must be the same
|
||||||
|
* 725 OnlyPermanentLeasesSupported - The NAT implementation only supports
|
||||||
|
* permanent lease times on port mappings
|
||||||
|
* 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard
|
||||||
|
* and cannot be a specific IP address or DNS name
|
||||||
|
* 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and
|
||||||
|
* cannot be a specific port value
|
||||||
|
* 728 NoPortMapsAvailable - There are not enough free ports available to
|
||||||
|
* complete port mapping.
|
||||||
|
* 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed
|
||||||
|
* due to conflict with other mechanisms.
|
||||||
|
* 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded
|
||||||
|
*/
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
||||||
|
const char * extPort,
|
||||||
|
const char * inPort,
|
||||||
|
const char * inClient,
|
||||||
|
const char * desc,
|
||||||
|
const char * proto,
|
||||||
|
const char * remoteHost,
|
||||||
|
const char * leaseDuration);
|
||||||
|
|
||||||
|
/* UPNP_DeletePortMapping()
|
||||||
|
* Use same argument values as what was used for AddPortMapping().
|
||||||
|
* remoteHost is usually NULL because IGD don't support it.
|
||||||
|
* Return Values :
|
||||||
|
* 0 : SUCCESS
|
||||||
|
* NON ZERO : error. Either an UPnP error code or an undefined error.
|
||||||
|
*
|
||||||
|
* List of possible UPnP errors for DeletePortMapping :
|
||||||
|
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||||
|
* 606 Action not authorized - The action requested REQUIRES authorization
|
||||||
|
* and the sender was not authorized.
|
||||||
|
* 714 NoSuchEntryInArray - The specified value does not exist in the array */
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
|
||||||
|
const char * extPort, const char * proto,
|
||||||
|
const char * remoteHost);
|
||||||
|
|
||||||
|
/* UPNP_GetPortMappingNumberOfEntries()
|
||||||
|
* not supported by all routers */
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetPortMappingNumberOfEntries(const char* controlURL,
|
||||||
|
const char* servicetype,
|
||||||
|
unsigned int * num);
|
||||||
|
|
||||||
|
/* UPNP_GetSpecificPortMappingEntry()
|
||||||
|
* retrieves an existing port mapping
|
||||||
|
* params :
|
||||||
|
* in extPort
|
||||||
|
* in proto
|
||||||
|
* in remoteHost
|
||||||
|
* out intClient (16 bytes)
|
||||||
|
* out intPort (6 bytes)
|
||||||
|
* out desc (80 bytes)
|
||||||
|
* out enabled (4 bytes)
|
||||||
|
* out leaseDuration (16 bytes)
|
||||||
|
*
|
||||||
|
* return value :
|
||||||
|
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||||
|
* or a UPnP Error Code.
|
||||||
|
*
|
||||||
|
* List of possible UPnP errors for _GetSpecificPortMappingEntry :
|
||||||
|
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||||
|
* 501 Action Failed - See UPnP Device Architecture section on Control.
|
||||||
|
* 606 Action not authorized - The action requested REQUIRES authorization
|
||||||
|
* and the sender was not authorized.
|
||||||
|
* 714 NoSuchEntryInArray - The specified value does not exist in the array.
|
||||||
|
*/
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
const char * extPort,
|
||||||
|
const char * proto,
|
||||||
|
const char * remoteHost,
|
||||||
|
char * intClient,
|
||||||
|
char * intPort,
|
||||||
|
char * desc,
|
||||||
|
char * enabled,
|
||||||
|
char * leaseDuration);
|
||||||
|
|
||||||
|
/* UPNP_GetGenericPortMappingEntry()
|
||||||
|
* params :
|
||||||
|
* in index
|
||||||
|
* out extPort (6 bytes)
|
||||||
|
* out intClient (16 bytes)
|
||||||
|
* out intPort (6 bytes)
|
||||||
|
* out protocol (4 bytes)
|
||||||
|
* out desc (80 bytes)
|
||||||
|
* out enabled (4 bytes)
|
||||||
|
* out rHost (64 bytes)
|
||||||
|
* out duration (16 bytes)
|
||||||
|
*
|
||||||
|
* return value :
|
||||||
|
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
||||||
|
* or a UPnP Error Code.
|
||||||
|
*
|
||||||
|
* Possible UPNP Error codes :
|
||||||
|
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||||
|
* 606 Action not authorized - The action requested REQUIRES authorization
|
||||||
|
* and the sender was not authorized.
|
||||||
|
* 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds
|
||||||
|
*/
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetGenericPortMappingEntry(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
const char * index,
|
||||||
|
char * extPort,
|
||||||
|
char * intClient,
|
||||||
|
char * intPort,
|
||||||
|
char * protocol,
|
||||||
|
char * desc,
|
||||||
|
char * enabled,
|
||||||
|
char * rHost,
|
||||||
|
char * duration);
|
||||||
|
|
||||||
|
/* UPNP_GetListOfPortMappings() Available in IGD v2
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Possible UPNP Error codes :
|
||||||
|
* 606 Action not Authorized
|
||||||
|
* 730 PortMappingNotFound - no port mapping is found in the specified range.
|
||||||
|
* 733 InconsistantParameters - NewStartPort and NewEndPort values are not
|
||||||
|
* consistent.
|
||||||
|
*/
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetListOfPortMappings(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
const char * startPort,
|
||||||
|
const char * endPort,
|
||||||
|
const char * protocol,
|
||||||
|
const char * numberOfPorts,
|
||||||
|
struct PortMappingParserData * data);
|
||||||
|
|
||||||
|
/* IGD:2, functions for service WANIPv6FirewallControl:1 */
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetFirewallStatus(const char * controlURL,
|
||||||
|
const char * servicetype,
|
||||||
|
int * firewallEnabled,
|
||||||
|
int * inboundPinholeAllowed);
|
||||||
|
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype,
|
||||||
|
const char * remoteHost,
|
||||||
|
const char * remotePort,
|
||||||
|
const char * intClient,
|
||||||
|
const char * intPort,
|
||||||
|
const char * proto,
|
||||||
|
int * opTimeout);
|
||||||
|
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_AddPinhole(const char * controlURL, const char * servicetype,
|
||||||
|
const char * remoteHost,
|
||||||
|
const char * remotePort,
|
||||||
|
const char * intClient,
|
||||||
|
const char * intPort,
|
||||||
|
const char * proto,
|
||||||
|
const char * leaseTime,
|
||||||
|
char * uniqueID);
|
||||||
|
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
|
||||||
|
const char * uniqueID,
|
||||||
|
const char * leaseTime);
|
||||||
|
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID);
|
||||||
|
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
|
||||||
|
const char * uniqueID, int * isWorking);
|
||||||
|
|
||||||
|
LIBSPEC int
|
||||||
|
UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
|
||||||
|
const char * uniqueID, int * packets);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
/* $Id: upnperrors.c,v 1.6 2012/03/15 01:02:03 nanard Exp $ */
|
||||||
|
/* Project : miniupnp
|
||||||
|
* Author : Thomas BERNARD
|
||||||
|
* copyright (c) 2007 Thomas Bernard
|
||||||
|
* All Right reserved.
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* This software is subjet to the conditions detailed in the
|
||||||
|
* provided LICENCE file. */
|
||||||
|
#include <string.h>
|
||||||
|
#include "upnperrors.h"
|
||||||
|
#include "upnpcommands.h"
|
||||||
|
#include "miniupnpc.h"
|
||||||
|
|
||||||
|
const char * strupnperror(int err)
|
||||||
|
{
|
||||||
|
const char * s = NULL;
|
||||||
|
switch(err) {
|
||||||
|
case UPNPCOMMAND_SUCCESS:
|
||||||
|
s = "Success";
|
||||||
|
break;
|
||||||
|
case UPNPCOMMAND_UNKNOWN_ERROR:
|
||||||
|
s = "Miniupnpc Unknown Error";
|
||||||
|
break;
|
||||||
|
case UPNPCOMMAND_INVALID_ARGS:
|
||||||
|
s = "Miniupnpc Invalid Arguments";
|
||||||
|
break;
|
||||||
|
case UPNPDISCOVER_SOCKET_ERROR:
|
||||||
|
s = "Miniupnpc Socket error";
|
||||||
|
break;
|
||||||
|
case UPNPDISCOVER_MEMORY_ERROR:
|
||||||
|
s = "Miniupnpc Memory allocation error";
|
||||||
|
break;
|
||||||
|
case 401:
|
||||||
|
s = "Invalid Action";
|
||||||
|
break;
|
||||||
|
case 402:
|
||||||
|
s = "Invalid Args";
|
||||||
|
break;
|
||||||
|
case 501:
|
||||||
|
s = "Action Failed";
|
||||||
|
break;
|
||||||
|
case 606:
|
||||||
|
s = "Action not authorized";
|
||||||
|
break;
|
||||||
|
case 701:
|
||||||
|
s = "PinholeSpaceExhausted";
|
||||||
|
break;
|
||||||
|
case 702:
|
||||||
|
s = "FirewallDisabled";
|
||||||
|
break;
|
||||||
|
case 703:
|
||||||
|
s = "InboundPinholeNotAllowed";
|
||||||
|
break;
|
||||||
|
case 704:
|
||||||
|
s = "NoSuchEntry";
|
||||||
|
break;
|
||||||
|
case 705:
|
||||||
|
s = "ProtocolNotSupported";
|
||||||
|
break;
|
||||||
|
case 706:
|
||||||
|
s = "InternalPortWildcardingNotAllowed";
|
||||||
|
break;
|
||||||
|
case 707:
|
||||||
|
s = "ProtocolWildcardingNotAllowed";
|
||||||
|
break;
|
||||||
|
case 708:
|
||||||
|
s = "WildcardNotPermittedInSrcIP";
|
||||||
|
break;
|
||||||
|
case 709:
|
||||||
|
s = "NoPacketSent";
|
||||||
|
break;
|
||||||
|
case 713:
|
||||||
|
s = "SpecifiedArrayIndexInvalid";
|
||||||
|
break;
|
||||||
|
case 714:
|
||||||
|
s = "NoSuchEntryInArray";
|
||||||
|
break;
|
||||||
|
case 715:
|
||||||
|
s = "WildCardNotPermittedInSrcIP";
|
||||||
|
break;
|
||||||
|
case 716:
|
||||||
|
s = "WildCardNotPermittedInExtPort";
|
||||||
|
break;
|
||||||
|
case 718:
|
||||||
|
s = "ConflictInMappingEntry";
|
||||||
|
break;
|
||||||
|
case 724:
|
||||||
|
s = "SamePortValuesRequired";
|
||||||
|
break;
|
||||||
|
case 725:
|
||||||
|
s = "OnlyPermanentLeasesSupported";
|
||||||
|
break;
|
||||||
|
case 726:
|
||||||
|
s = "RemoteHostOnlySupportsWildcard";
|
||||||
|
break;
|
||||||
|
case 727:
|
||||||
|
s = "ExternalPortOnlySupportsWildcard";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = "UnknownError";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* $Id: upnperrors.h,v 1.4 2012/09/27 15:42:11 nanard Exp $ */
|
||||||
|
/* (c) 2007 Thomas Bernard
|
||||||
|
* All rights reserved.
|
||||||
|
* MiniUPnP Project.
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* This software is subjet to the conditions detailed in the
|
||||||
|
* provided LICENCE file. */
|
||||||
|
#ifndef UPNPERRORS_H_INCLUDED
|
||||||
|
#define UPNPERRORS_H_INCLUDED
|
||||||
|
|
||||||
|
#include "declspec.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* strupnperror()
|
||||||
|
* Return a string description of the UPnP error code
|
||||||
|
* or NULL for undefinded errors */
|
||||||
|
LIBSPEC const char * strupnperror(int err);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,183 @@
|
||||||
|
/* $Id: upnpreplyparse.c,v 1.15 2013/06/06 21:36:40 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* (c) 2006-2013 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed
|
||||||
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "upnpreplyparse.h"
|
||||||
|
#include "minixml.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
NameValueParserStartElt(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||||
|
data->topelt = 1;
|
||||||
|
if(l>63)
|
||||||
|
l = 63;
|
||||||
|
memcpy(data->curelt, name, l);
|
||||||
|
data->curelt[l] = '\0';
|
||||||
|
data->cdata = NULL;
|
||||||
|
data->cdatalen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
NameValueParserEndElt(void * d, const char * name, int l)
|
||||||
|
{
|
||||||
|
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||||
|
struct NameValue * nv;
|
||||||
|
(void)name;
|
||||||
|
(void)l;
|
||||||
|
if(!data->topelt)
|
||||||
|
return;
|
||||||
|
if(strcmp(data->curelt, "NewPortListing") != 0)
|
||||||
|
{
|
||||||
|
int l;
|
||||||
|
/* standard case. Limited to n chars strings */
|
||||||
|
l = data->cdatalen;
|
||||||
|
nv = malloc(sizeof(struct NameValue));
|
||||||
|
if(l>=(int)sizeof(nv->value))
|
||||||
|
l = sizeof(nv->value) - 1;
|
||||||
|
strncpy(nv->name, data->curelt, 64);
|
||||||
|
nv->name[63] = '\0';
|
||||||
|
if(data->cdata != NULL)
|
||||||
|
{
|
||||||
|
memcpy(nv->value, data->cdata, l);
|
||||||
|
nv->value[l] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nv->value[0] = '\0';
|
||||||
|
}
|
||||||
|
LIST_INSERT_HEAD( &(data->head), nv, entries);
|
||||||
|
}
|
||||||
|
data->cdata = NULL;
|
||||||
|
data->cdatalen = 0;
|
||||||
|
data->topelt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
NameValueParserGetData(void * d, const char * datas, int l)
|
||||||
|
{
|
||||||
|
struct NameValueParserData * data = (struct NameValueParserData *)d;
|
||||||
|
if(strcmp(data->curelt, "NewPortListing") == 0)
|
||||||
|
{
|
||||||
|
/* specific case for NewPortListing which is a XML Document */
|
||||||
|
data->portListing = malloc(l + 1);
|
||||||
|
if(!data->portListing)
|
||||||
|
{
|
||||||
|
/* malloc error */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(data->portListing, datas, l);
|
||||||
|
data->portListing[l] = '\0';
|
||||||
|
data->portListingLength = l;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* standard case. */
|
||||||
|
data->cdata = datas;
|
||||||
|
data->cdatalen = l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ParseNameValue(const char * buffer, int bufsize,
|
||||||
|
struct NameValueParserData * data)
|
||||||
|
{
|
||||||
|
struct xmlparser parser;
|
||||||
|
LIST_INIT(&(data->head));
|
||||||
|
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;
|
||||||
|
parser.attfunc = 0;
|
||||||
|
parsexml(&parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ClearNameValueList(struct NameValueParserData * pdata)
|
||||||
|
{
|
||||||
|
struct NameValue * nv;
|
||||||
|
if(pdata->portListing)
|
||||||
|
{
|
||||||
|
free(pdata->portListing);
|
||||||
|
pdata->portListing = NULL;
|
||||||
|
pdata->portListingLength = 0;
|
||||||
|
}
|
||||||
|
while((nv = pdata->head.lh_first) != NULL)
|
||||||
|
{
|
||||||
|
LIST_REMOVE(nv, entries);
|
||||||
|
free(nv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||||
|
const char * Name)
|
||||||
|
{
|
||||||
|
struct NameValue * nv;
|
||||||
|
char * p = NULL;
|
||||||
|
for(nv = pdata->head.lh_first;
|
||||||
|
(nv != NULL) && (p == NULL);
|
||||||
|
nv = nv->entries.le_next)
|
||||||
|
{
|
||||||
|
if(strcmp(nv->name, Name) == 0)
|
||||||
|
p = nv->value;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* useless now that minixml ignores namespaces by itself */
|
||||||
|
char *
|
||||||
|
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
|
||||||
|
const char * Name)
|
||||||
|
{
|
||||||
|
struct NameValue * nv;
|
||||||
|
char * p = NULL;
|
||||||
|
char * pname;
|
||||||
|
for(nv = pdata->head.lh_first;
|
||||||
|
(nv != NULL) && (p == NULL);
|
||||||
|
nv = nv->entries.le_next)
|
||||||
|
{
|
||||||
|
pname = strrchr(nv->name, ':');
|
||||||
|
if(pname)
|
||||||
|
pname++;
|
||||||
|
else
|
||||||
|
pname = nv->name;
|
||||||
|
if(strcmp(pname, Name)==0)
|
||||||
|
p = nv->value;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* debug all-in-one function
|
||||||
|
* do parsing then display to stdout */
|
||||||
|
#ifdef DEBUG
|
||||||
|
void
|
||||||
|
DisplayNameValueList(char * buffer, int bufsize)
|
||||||
|
{
|
||||||
|
struct NameValueParserData pdata;
|
||||||
|
struct NameValue * nv;
|
||||||
|
ParseNameValue(buffer, bufsize, &pdata);
|
||||||
|
for(nv = pdata.head.lh_first;
|
||||||
|
nv != NULL;
|
||||||
|
nv = nv->entries.le_next)
|
||||||
|
{
|
||||||
|
printf("%s = %s\n", nv->name, nv->value);
|
||||||
|
}
|
||||||
|
ClearNameValueList(&pdata);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/* $Id: upnpreplyparse.h,v 1.17 2013/06/06 21:36:40 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* (c) 2006-2013 Thomas Bernard
|
||||||
|
* This software is subject to the conditions detailed
|
||||||
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
#ifndef UPNPREPLYPARSE_H_INCLUDED
|
||||||
|
#define UPNPREPLYPARSE_H_INCLUDED
|
||||||
|
|
||||||
|
#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__)
|
||||||
|
#include "bsdqueue.h"
|
||||||
|
#else
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct NameValue {
|
||||||
|
LIST_ENTRY(NameValue) entries;
|
||||||
|
char name[64];
|
||||||
|
char value[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NameValueParserData {
|
||||||
|
LIST_HEAD(listhead, NameValue) head;
|
||||||
|
char curelt[64];
|
||||||
|
char * portListing;
|
||||||
|
int portListingLength;
|
||||||
|
int topelt;
|
||||||
|
const char * cdata;
|
||||||
|
int cdatalen;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ParseNameValue() */
|
||||||
|
void
|
||||||
|
ParseNameValue(const char * buffer, int bufsize,
|
||||||
|
struct NameValueParserData * data);
|
||||||
|
|
||||||
|
/* ClearNameValueList() */
|
||||||
|
void
|
||||||
|
ClearNameValueList(struct NameValueParserData * pdata);
|
||||||
|
|
||||||
|
/* GetValueFromNameValueList() */
|
||||||
|
char *
|
||||||
|
GetValueFromNameValueList(struct NameValueParserData * pdata,
|
||||||
|
const char * Name);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* GetValueFromNameValueListIgnoreNS() */
|
||||||
|
char *
|
||||||
|
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
|
||||||
|
const char * Name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* DisplayNameValueList() */
|
||||||
|
#ifdef DEBUG
|
||||||
|
void
|
||||||
|
DisplayNameValueList(char * buffer, int bufsize);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/* $Id: wingenminiupnpcstrings.c,v 1.3 2012/03/05 19:42:48 nanard Exp $ */
|
||||||
|
/* Project: miniupnp
|
||||||
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
* Author: Thomas Bernard
|
||||||
|
* Copyright (c) 2005-2009 Thomas Bernard
|
||||||
|
* This software is subjects to the conditions detailed
|
||||||
|
* in the LICENSE file provided within this distribution */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
/* This program display the Windows version and is used to
|
||||||
|
* generate the miniupnpcstrings.h
|
||||||
|
* wingenminiupnpcstrings miniupnpcstrings.h.in miniupnpcstrings.h
|
||||||
|
*/
|
||||||
|
int main(int argc, char * * argv) {
|
||||||
|
char buffer[256];
|
||||||
|
OSVERSIONINFO osvi;
|
||||||
|
FILE * fin;
|
||||||
|
FILE * fout;
|
||||||
|
int n;
|
||||||
|
char miniupnpcVersion[32];
|
||||||
|
/* dwMajorVersion :
|
||||||
|
The major version number of the operating system. For more information, see Remarks.
|
||||||
|
dwMinorVersion :
|
||||||
|
The minor version number of the operating system. For more information, see Remarks.
|
||||||
|
dwBuildNumber :
|
||||||
|
The build number of the operating system.
|
||||||
|
dwPlatformId
|
||||||
|
The operating system platform. This member can be the following value.
|
||||||
|
szCSDVersion
|
||||||
|
A null-terminated string, such as "Service Pack 3", that indicates the
|
||||||
|
latest Service Pack installed on the system. If no Service Pack has
|
||||||
|
been installed, the string is empty.
|
||||||
|
*/
|
||||||
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
||||||
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||||
|
|
||||||
|
GetVersionEx(&osvi);
|
||||||
|
|
||||||
|
printf("Windows %lu.%lu Build %lu %s\n",
|
||||||
|
osvi.dwMajorVersion, osvi.dwMinorVersion,
|
||||||
|
osvi.dwBuildNumber, (const char *)&(osvi.szCSDVersion));
|
||||||
|
|
||||||
|
fin = fopen("VERSION", "r");
|
||||||
|
fgets(miniupnpcVersion, sizeof(miniupnpcVersion), fin);
|
||||||
|
fclose(fin);
|
||||||
|
for(n = 0; n < sizeof(miniupnpcVersion); n++) {
|
||||||
|
if(miniupnpcVersion[n] < ' ')
|
||||||
|
miniupnpcVersion[n] = '\0';
|
||||||
|
}
|
||||||
|
printf("MiniUPnPc version %s\n", miniupnpcVersion);
|
||||||
|
|
||||||
|
if(argc >= 3) {
|
||||||
|
fin = fopen(argv[1], "r");
|
||||||
|
if(!fin) {
|
||||||
|
fprintf(stderr, "Cannot open %s for reading.\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fout = fopen(argv[2], "w");
|
||||||
|
if(!fout) {
|
||||||
|
fprintf(stderr, "Cannot open %s for writing.\n", argv[2]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
n = 0;
|
||||||
|
while(fgets(buffer, sizeof(buffer), fin)) {
|
||||||
|
if(0 == memcmp(buffer, "#define OS_STRING \"OS/version\"", 30)) {
|
||||||
|
sprintf(buffer, "#define OS_STRING \"MSWindows/%ld.%ld.%ld\"\n",
|
||||||
|
osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
|
||||||
|
} else if(0 == memcmp(buffer, "#define MINIUPNPC_VERSION_STRING \"version\"", 42)) {
|
||||||
|
sprintf(buffer, "#define MINIUPNPC_VERSION_STRING \"%s\"\n",
|
||||||
|
miniupnpcVersion);
|
||||||
|
}
|
||||||
|
/*fputs(buffer, stdout);*/
|
||||||
|
fputs(buffer, fout);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
fclose(fin);
|
||||||
|
fclose(fout);
|
||||||
|
printf("%d lines written to %s.\n", n, argv[2]);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -7,7 +7,7 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
namespace cryptonote {
|
namespace CryptoNote {
|
||||||
|
|
||||||
class INodeObserver {
|
class INodeObserver {
|
||||||
public:
|
public:
|
||||||
|
@ -23,12 +23,12 @@ public:
|
||||||
class INode {
|
class INode {
|
||||||
public:
|
public:
|
||||||
virtual ~INode() = 0;
|
virtual ~INode() = 0;
|
||||||
virtual void init() = 0;
|
|
||||||
virtual void shutdown() = 0;
|
|
||||||
|
|
||||||
virtual void addObserver(INodeObserver* observer) = 0;
|
virtual void addObserver(INodeObserver* observer) = 0;
|
||||||
virtual void removeObserver(INodeObserver* observer) = 0;
|
virtual void removeObserver(INodeObserver* observer) = 0;
|
||||||
|
|
||||||
|
virtual void init() = 0;
|
||||||
|
virtual void shutdown() = 0;
|
||||||
|
|
||||||
virtual size_t getPeerCount() = 0;
|
virtual size_t getPeerCount() = 0;
|
||||||
virtual uint64_t getLastLocalBlockHeight() = 0;
|
virtual uint64_t getLastLocalBlockHeight() = 0;
|
||||||
virtual uint64_t getLastKnownBlockHeight() = 0;
|
virtual uint64_t getLastKnownBlockHeight() = 0;
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace cryptonote {
|
namespace CryptoNote {
|
||||||
|
|
||||||
typedef size_t TransactionId;
|
typedef size_t TransactionId;
|
||||||
typedef size_t TransferId;
|
typedef size_t TransferId;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
add_definitions(-DSTATICLIB)
|
||||||
|
|
||||||
file(GLOB_RECURSE COMMON common/*)
|
file(GLOB_RECURSE COMMON common/*)
|
||||||
file(GLOB_RECURSE CRYPTO crypto/*)
|
file(GLOB_RECURSE CRYPTO crypto/*)
|
||||||
file(GLOB_RECURSE CRYPTONOTE_CORE cryptonote_core/*)
|
file(GLOB_RECURSE CRYPTONOTE_CORE cryptonote_core/*)
|
||||||
|
@ -28,16 +30,16 @@ add_library(cryptonote_core ${CRYPTONOTE_CORE})
|
||||||
add_executable(daemon ${DAEMON} ${P2P} ${CRYPTONOTE_PROTOCOL})
|
add_executable(daemon ${DAEMON} ${P2P} ${CRYPTONOTE_PROTOCOL})
|
||||||
add_executable(connectivity_tool ${CONN_TOOL})
|
add_executable(connectivity_tool ${CONN_TOOL})
|
||||||
add_executable(simpleminer ${MINER})
|
add_executable(simpleminer ${MINER})
|
||||||
target_link_libraries(daemon rpc cryptonote_core crypto common ${Boost_LIBRARIES})
|
target_link_libraries(daemon rpc cryptonote_core crypto common upnpc-static ${Boost_LIBRARIES})
|
||||||
target_link_libraries(connectivity_tool cryptonote_core crypto common ${Boost_LIBRARIES})
|
target_link_libraries(connectivity_tool cryptonote_core crypto common ${Boost_LIBRARIES})
|
||||||
target_link_libraries(simpleminer cryptonote_core crypto common ${Boost_LIBRARIES})
|
target_link_libraries(simpleminer cryptonote_core crypto common ${Boost_LIBRARIES})
|
||||||
add_dependencies(daemon version)
|
|
||||||
add_library(rpc ${RPC})
|
add_library(rpc ${RPC})
|
||||||
add_library(wallet ${WALLET})
|
add_library(wallet ${WALLET})
|
||||||
add_executable(simplewallet ${SIMPLEWALLET} )
|
add_executable(simplewallet ${SIMPLEWALLET} )
|
||||||
target_link_libraries(simplewallet wallet rpc cryptonote_core crypto common ${Boost_LIBRARIES})
|
target_link_libraries(simplewallet wallet rpc cryptonote_core crypto common upnpc-static ${Boost_LIBRARIES})
|
||||||
add_dependencies(simplewallet version)
|
|
||||||
add_dependencies(daemon version)
|
add_dependencies(daemon version)
|
||||||
|
add_dependencies(rpc version)
|
||||||
|
add_dependencies(simplewallet version)
|
||||||
|
|
||||||
set_property(TARGET common crypto cryptonote_core rpc wallet PROPERTY FOLDER "libs")
|
set_property(TARGET common crypto cryptonote_core rpc wallet PROPERTY FOLDER "libs")
|
||||||
set_property(TARGET daemon simplewallet connectivity_tool simpleminer PROPERTY FOLDER "prog")
|
set_property(TARGET daemon simplewallet connectivity_tool simpleminer PROPERTY FOLDER "prog")
|
||||||
|
|
|
@ -21,6 +21,7 @@ namespace cryptonote {
|
||||||
ADD_CHECKPOINT(390285, "e00bdc9bf407aeace2f3109de11889ed25894bf194231d075eddaec838097eb7");
|
ADD_CHECKPOINT(390285, "e00bdc9bf407aeace2f3109de11889ed25894bf194231d075eddaec838097eb7");
|
||||||
ADD_CHECKPOINT(417000, "2dc96f8fc4d4a4d76b3ed06722829a7ab09d310584b8ecedc9b578b2c458a69f");
|
ADD_CHECKPOINT(417000, "2dc96f8fc4d4a4d76b3ed06722829a7ab09d310584b8ecedc9b578b2c458a69f");
|
||||||
ADD_CHECKPOINT(427193, "00feabb08f2d5759ed04fd6b799a7513187478696bba2db2af10d4347134e311");
|
ADD_CHECKPOINT(427193, "00feabb08f2d5759ed04fd6b799a7513187478696bba2db2af10d4347134e311");
|
||||||
|
ADD_CHECKPOINT(453537, "d17de6916c5aa6ffcae575309c80b0f8fdcd0a84b5fa8e41a841897d4b5a4e97");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
#include "net/local_ip.h"
|
#include "net/local_ip.h"
|
||||||
#include "crypto/crypto.h"
|
#include "crypto/crypto.h"
|
||||||
#include "storages/levin_abstract_invoke2.h"
|
#include "storages/levin_abstract_invoke2.h"
|
||||||
|
#include <miniupnpc/miniupnpc.h>
|
||||||
|
#include <miniupnpc/upnpcommands.h>
|
||||||
|
|
||||||
#define NET_MAKE_IP(b1,b2,b3,b4) ((LPARAM)(((DWORD)(b1)<<24)+((DWORD)(b2)<<16)+((DWORD)(b3)<<8)+((DWORD)(b4))))
|
#define NET_MAKE_IP(b1,b2,b3,b4) ((LPARAM)(((DWORD)(b1)<<24)+((DWORD)(b2)<<16)+((DWORD)(b3)<<8)+((DWORD)(b4))))
|
||||||
|
|
||||||
|
|
||||||
|
@ -233,6 +236,38 @@ namespace nodetool
|
||||||
LOG_PRINT_GREEN("Net service binded on " << m_bind_ip << ":" << m_listenning_port, LOG_LEVEL_0);
|
LOG_PRINT_GREEN("Net service binded on " << m_bind_ip << ":" << m_listenning_port, LOG_LEVEL_0);
|
||||||
if(m_external_port)
|
if(m_external_port)
|
||||||
LOG_PRINT_L0("External port defined as " << m_external_port);
|
LOG_PRINT_L0("External port defined as " << m_external_port);
|
||||||
|
|
||||||
|
// Add UPnP port mapping
|
||||||
|
LOG_PRINT_L0("Attempting to add IGD port mapping.");
|
||||||
|
int result;
|
||||||
|
UPNPDev* deviceList = upnpDiscover(1000, NULL, NULL, 0, 0, &result);
|
||||||
|
UPNPUrls urls;
|
||||||
|
IGDdatas igdData;
|
||||||
|
char lanAddress[64];
|
||||||
|
result = UPNP_GetValidIGD(deviceList, &urls, &igdData, lanAddress, sizeof lanAddress);
|
||||||
|
freeUPNPDevlist(deviceList);
|
||||||
|
if (result != 0) {
|
||||||
|
if (result == 1) {
|
||||||
|
std::ostringstream portString;
|
||||||
|
portString << m_listenning_port;
|
||||||
|
if (UPNP_AddPortMapping(urls.controlURL, igdData.first.servicetype, portString.str().c_str(), portString.str().c_str(), lanAddress, CRYPTONOTE_NAME, "TCP", 0, "0") != 0) {
|
||||||
|
LOG_ERROR("UPNP_AddPortMapping failed.");
|
||||||
|
} else {
|
||||||
|
LOG_PRINT_GREEN("Added IGD port mapping.", LOG_LEVEL_0);
|
||||||
|
}
|
||||||
|
} else if (result == 2) {
|
||||||
|
LOG_PRINT_L0("IGD was found but reported as not connected.");
|
||||||
|
} else if (result == 3) {
|
||||||
|
LOG_PRINT_L0("UPnP device was found but not recoginzed as IGD.");
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("UPNP_GetValidIGD returned an unknown result code.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeUPNPUrls(&urls);
|
||||||
|
} else {
|
||||||
|
LOG_PRINT_L0("No IGD was found.");
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
|
|
|
@ -11,6 +11,7 @@ using namespace epee;
|
||||||
#include "common/command_line.h"
|
#include "common/command_line.h"
|
||||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||||
#include "cryptonote_core/account.h"
|
#include "cryptonote_core/account.h"
|
||||||
|
#include "cryptonote_core/cryptonote_basic_impl.h"
|
||||||
#include "misc_language.h"
|
#include "misc_language.h"
|
||||||
#include "crypto/hash.h"
|
#include "crypto/hash.h"
|
||||||
#include "core_rpc_server_error_codes.h"
|
#include "core_rpc_server_error_codes.h"
|
||||||
|
@ -413,6 +414,140 @@ namespace cryptonote
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
uint64_t core_rpc_server::get_block_reward(const block& blk)
|
||||||
|
{
|
||||||
|
uint64_t reward = 0;
|
||||||
|
BOOST_FOREACH(const tx_out& out, blk.miner_tx.vout)
|
||||||
|
{
|
||||||
|
reward += out.amount;
|
||||||
|
}
|
||||||
|
return reward;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
bool core_rpc_server::fill_block_header_responce(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_responce& responce)
|
||||||
|
{
|
||||||
|
responce.major_version = blk.major_version;
|
||||||
|
responce.minor_version = blk.minor_version;
|
||||||
|
responce.timestamp = blk.timestamp;
|
||||||
|
responce.prev_hash = string_tools::pod_to_hex(blk.prev_id);
|
||||||
|
responce.nonce = blk.nonce;
|
||||||
|
responce.orphan_status = orphan_status;
|
||||||
|
responce.height = height;
|
||||||
|
responce.depth = m_core.get_current_blockchain_height() - height - 1;
|
||||||
|
responce.hash = string_tools::pod_to_hex(hash);
|
||||||
|
responce.difficulty = m_core.get_blockchain_storage().block_difficulty(height);
|
||||||
|
responce.reward = get_block_reward(blk);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
bool core_rpc_server::on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
|
||||||
|
{
|
||||||
|
if(!check_core_ready())
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
|
||||||
|
error_resp.message = "Core is busy.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint64_t last_block_height;
|
||||||
|
crypto::hash last_block_hash;
|
||||||
|
bool have_last_block_hash = m_core.get_blockchain_top(last_block_height, last_block_hash);
|
||||||
|
if (!have_last_block_hash)
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||||
|
error_resp.message = "Internal error: can't get last block hash.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
block last_block;
|
||||||
|
bool have_last_block = m_core.get_block_by_hash(last_block_hash, last_block);
|
||||||
|
if (!have_last_block)
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||||
|
error_resp.message = "Internal error: can't get last block.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool responce_filled = fill_block_header_responce(last_block, false, last_block_height, last_block_hash, res.block_header);
|
||||||
|
if (!responce_filled)
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||||
|
error_resp.message = "Internal error: can't produce valid response.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
res.status = CORE_RPC_STATUS_OK;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
bool core_rpc_server::on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx){
|
||||||
|
if(!check_core_ready())
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
|
||||||
|
error_resp.message = "Core is busy.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
crypto::hash block_hash;
|
||||||
|
bool hash_parsed = parse_hash256(req.hash, block_hash);
|
||||||
|
if(!hash_parsed)
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
|
||||||
|
error_resp.message = "Failed to parse hex representation of block hash. Hex = " + req.hash + '.';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
block blk;
|
||||||
|
bool have_block = m_core.get_block_by_hash(block_hash, blk);
|
||||||
|
if (!have_block)
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||||
|
error_resp.message = "Internal error: can't get block by hash. Hash = " + req.hash + '.';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (blk.miner_tx.vin.front().type() != typeid(txin_gen))
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||||
|
error_resp.message = "Internal error: coinbase transaction in the block has the wrong type";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint64_t block_height = boost::get<txin_gen>(blk.miner_tx.vin.front()).height;
|
||||||
|
bool responce_filled = fill_block_header_responce(blk, false, block_height, block_hash, res.block_header);
|
||||||
|
if (!responce_filled)
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||||
|
error_resp.message = "Internal error: can't produce valid response.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
res.status = CORE_RPC_STATUS_OK;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
bool core_rpc_server::on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp, connection_context& cntx){
|
||||||
|
if(!check_core_ready())
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
|
||||||
|
error_resp.message = "Core is busy.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(m_core.get_current_blockchain_height() <= req.height)
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT;
|
||||||
|
error_resp.message = std::string("To big height: ") + std::to_string(req.height) + ", current blockchain height = " + std::to_string(m_core.get_current_blockchain_height());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
crypto::hash block_hash = m_core.get_block_id_by_height(req.height);
|
||||||
|
block blk;
|
||||||
|
bool have_block = m_core.get_block_by_hash(block_hash, blk);
|
||||||
|
if (!have_block)
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||||
|
error_resp.message = "Internal error: can't get block by height. Height = " + req.height + '.';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool responce_filled = fill_block_header_responce(blk, false, req.height, block_hash, res.block_header);
|
||||||
|
if (!responce_filled)
|
||||||
|
{
|
||||||
|
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||||
|
error_resp.message = "Internal error: can't produce valid response.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
res.status = CORE_RPC_STATUS_OK;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,9 @@ namespace cryptonote
|
||||||
MAP_JON_RPC_WE("on_getblockhash", on_getblockhash, COMMAND_RPC_GETBLOCKHASH)
|
MAP_JON_RPC_WE("on_getblockhash", on_getblockhash, COMMAND_RPC_GETBLOCKHASH)
|
||||||
MAP_JON_RPC_WE("getblocktemplate", on_getblocktemplate, COMMAND_RPC_GETBLOCKTEMPLATE)
|
MAP_JON_RPC_WE("getblocktemplate", on_getblocktemplate, COMMAND_RPC_GETBLOCKTEMPLATE)
|
||||||
MAP_JON_RPC_WE("submitblock", on_submitblock, COMMAND_RPC_SUBMITBLOCK)
|
MAP_JON_RPC_WE("submitblock", on_submitblock, COMMAND_RPC_SUBMITBLOCK)
|
||||||
|
MAP_JON_RPC_WE("getlastblockheader", on_get_last_block_header, COMMAND_RPC_GET_LAST_BLOCK_HEADER)
|
||||||
|
MAP_JON_RPC_WE("getblockheaderbyhash", on_get_block_header_by_hash, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH)
|
||||||
|
MAP_JON_RPC_WE("getblockheaderbyheight", on_get_block_header_by_height, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT)
|
||||||
END_JSON_RPC_MAP()
|
END_JSON_RPC_MAP()
|
||||||
END_URI_MAP2()
|
END_URI_MAP2()
|
||||||
|
|
||||||
|
@ -64,10 +67,17 @@ namespace cryptonote
|
||||||
bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||||
bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||||
bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||||
|
bool on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||||
|
bool on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||||
|
bool on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||||
//-----------------------
|
//-----------------------
|
||||||
bool handle_command_line(const boost::program_options::variables_map& vm);
|
bool handle_command_line(const boost::program_options::variables_map& vm);
|
||||||
bool check_core_ready();
|
bool check_core_ready();
|
||||||
|
|
||||||
|
//utils
|
||||||
|
uint64_t get_block_reward(const block& blk);
|
||||||
|
bool fill_block_header_responce(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_responce& responce);
|
||||||
|
|
||||||
core& m_core;
|
core& m_core;
|
||||||
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p;
|
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p;
|
||||||
std::string m_port;
|
std::string m_port;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||||
#include "cryptonote_core/cryptonote_basic.h"
|
#include "cryptonote_core/cryptonote_basic.h"
|
||||||
|
#include "cryptonote_core/difficulty.h"
|
||||||
#include "crypto/hash.h"
|
#include "crypto/hash.h"
|
||||||
|
|
||||||
namespace cryptonote
|
namespace cryptonote
|
||||||
|
@ -331,7 +332,99 @@ namespace cryptonote
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct block_header_responce
|
||||||
|
{
|
||||||
|
uint8_t major_version;
|
||||||
|
uint8_t minor_version;
|
||||||
|
uint64_t timestamp;
|
||||||
|
std::string prev_hash;
|
||||||
|
uint32_t nonce;
|
||||||
|
bool orphan_status;
|
||||||
|
uint64_t height;
|
||||||
|
uint64_t depth;
|
||||||
|
std::string hash;
|
||||||
|
difficulty_type difficulty;
|
||||||
|
uint64_t reward;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(major_version)
|
||||||
|
KV_SERIALIZE(minor_version)
|
||||||
|
KV_SERIALIZE(timestamp)
|
||||||
|
KV_SERIALIZE(prev_hash)
|
||||||
|
KV_SERIALIZE(nonce)
|
||||||
|
KV_SERIALIZE(orphan_status)
|
||||||
|
KV_SERIALIZE(height)
|
||||||
|
KV_SERIALIZE(depth)
|
||||||
|
KV_SERIALIZE(hash)
|
||||||
|
KV_SERIALIZE(difficulty)
|
||||||
|
KV_SERIALIZE(reward)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
struct COMMAND_RPC_GET_LAST_BLOCK_HEADER
|
||||||
|
{
|
||||||
|
typedef std::list<std::string> request;
|
||||||
|
|
||||||
|
struct response
|
||||||
|
{
|
||||||
|
std::string status;
|
||||||
|
block_header_responce block_header;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(block_header)
|
||||||
|
KV_SERIALIZE(status)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH
|
||||||
|
{
|
||||||
|
struct request
|
||||||
|
{
|
||||||
|
std::string hash;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(hash)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
struct response
|
||||||
|
{
|
||||||
|
std::string status;
|
||||||
|
block_header_responce block_header;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(block_header)
|
||||||
|
KV_SERIALIZE(status)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT
|
||||||
|
{
|
||||||
|
struct request
|
||||||
|
{
|
||||||
|
uint64_t height;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(height)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
struct response
|
||||||
|
{
|
||||||
|
std::string status;
|
||||||
|
block_header_responce block_header;
|
||||||
|
|
||||||
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
|
KV_SERIALIZE(block_header)
|
||||||
|
KV_SERIALIZE(status)
|
||||||
|
END_KV_SERIALIZE_MAP()
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#define BUILD_COMMIT_ID "@VERSION@"
|
#define BUILD_COMMIT_ID "@VERSION@"
|
||||||
#define PROJECT_VERSION "0.8.4"
|
#define PROJECT_VERSION "0.8.5"
|
||||||
#define PROJECT_VERSION_BUILD_NO "289"
|
#define PROJECT_VERSION_BUILD_NO "294"
|
||||||
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"
|
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
add_definitions(-DSTATICLIB)
|
||||||
|
|
||||||
add_subdirectory(gtest)
|
add_subdirectory(gtest)
|
||||||
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
|
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
|
||||||
|
|
||||||
|
@ -29,7 +31,7 @@ add_executable(unit_tests ${UNIT_TESTS})
|
||||||
add_executable(net_load_tests_clt net_load_tests/clt.cpp)
|
add_executable(net_load_tests_clt net_load_tests/clt.cpp)
|
||||||
add_executable(net_load_tests_srv net_load_tests/srv.cpp)
|
add_executable(net_load_tests_srv net_load_tests/srv.cpp)
|
||||||
|
|
||||||
target_link_libraries(core_proxy cryptonote_core common crypto ${Boost_LIBRARIES})
|
target_link_libraries(core_proxy cryptonote_core common crypto upnpc-static ${Boost_LIBRARIES})
|
||||||
target_link_libraries(coretests cryptonote_core common crypto ${Boost_LIBRARIES})
|
target_link_libraries(coretests cryptonote_core common crypto ${Boost_LIBRARIES})
|
||||||
target_link_libraries(difficulty-tests cryptonote_core)
|
target_link_libraries(difficulty-tests cryptonote_core)
|
||||||
target_link_libraries(functional_tests cryptonote_core wallet common crypto ${Boost_LIBRARIES})
|
target_link_libraries(functional_tests cryptonote_core wallet common crypto ${Boost_LIBRARIES})
|
||||||
|
|
Loading…
Reference in New Issue