85 changed files with 11889 additions and 5 deletions
@ -0,0 +1,178 @@
|
||||
cmake_minimum_required (VERSION 2.6) |
||||
|
||||
project (miniupnpc C) |
||||
set (MINIUPNPC_VERSION 1.9) |
||||
set (MINIUPNPC_API_VERSION 15) |
||||
|
||||
if (NOT CMAKE_BUILD_TYPE) |
||||
if (WIN32) |
||||
set (DEFAULT_BUILD_TYPE MinSizeRel) |
||||
else (WIN32) |
||||
set (DEFAULT_BUILD_TYPE RelWithDebInfo) |
||||
endif(WIN32) |
||||
set (CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE} CACHE STRING |
||||
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." |
||||
FORCE) |
||||
endif() |
||||
|
||||
option (UPNPC_BUILD_STATIC "Build static library" TRUE) |
||||
option (UPNPC_BUILD_SHARED "Build shared library" TRUE) |
||||
if (NOT WIN32) |
||||
option (UPNPC_BUILD_TESTS "Build test executables" TRUE) |
||||
endif (NOT WIN32) |
||||
option (NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE) |
||||
|
||||
mark_as_advanced (NO_GETADDRINFO) |
||||
|
||||
if (NO_GETADDRINFO) |
||||
add_definitions (-DNO_GETADDRINFO) |
||||
endif (NO_GETADDRINFO) |
||||
|
||||
if (NOT WIN32) |
||||
add_definitions (-DMINIUPNPC_SET_SOCKET_TIMEOUT) |
||||
add_definitions (-D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112L) |
||||
else (NOT WIN32) |
||||
add_definitions (-D_WIN32_WINNT=0x0501) # XP or higher for getnameinfo and friends |
||||
endif (NOT WIN32) |
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") |
||||
add_definitions (-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 (${CMAKE_SOURCE_DIR}/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 |
||||
minissdpc.c |
||||
miniwget.c |
||||
upnpc.c |
||||
upnpcommands.c |
||||
upnpdev.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 "MINIUPNP_STATICLIB;MINIUPNP_EXPORTS" |
||||
) |
||||
endif (WIN32) |
||||
|
||||
if (WIN32) |
||||
find_library (WINSOCK2_LIBRARY NAMES ws2_32 WS2_32 Ws2_32) |
||||
find_library (IPHLPAPI_LIBRARY NAMES 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 |
||||
upnpdev.h |
||||
miniupnpctypes.h |
||||
portlistingparse.h |
||||
miniupnpc_declspec.h |
||||
DESTINATION include/miniupnpc |
||||
) |
||||
|
||||
set (CONFIGURED YES CACHE INTERNAL "") |
||||
|
||||
# vim: ts=2:sw=2 |
||||
@ -0,0 +1,667 @@
|
||||
$Id: Changelog.txt,v 1.219 2015/10/26 17:05:06 nanard Exp $ |
||||
miniUPnP client Changelog. |
||||
|
||||
2015/10/26: |
||||
snprintf() overflow check. check overflow in simpleUPnPcommand2() |
||||
|
||||
2015/10/25: |
||||
fix compilation with old macs |
||||
fix compilation with mingw32 (for Appveyor) |
||||
fix python module for python <= 2.3 |
||||
|
||||
2015/10/08: |
||||
Change sameport to localport |
||||
see https://github.com/miniupnp/miniupnp/pull/120 |
||||
increments API_VERSION to 15 |
||||
|
||||
2015/09/15: |
||||
Fix buffer overflow in igd_desc_parse.c/IGDstartelt() |
||||
Discovered by Aleksandar Nikolic of Cisco Talos |
||||
|
||||
2015/08/28: |
||||
move ssdpDiscoverDevices() to minissdpc.c |
||||
|
||||
2015/08/27: |
||||
avoid unix socket leak in getDevicesFromMiniSSDPD() |
||||
|
||||
2015/08/16: |
||||
Also accept "Up" as ConnectionStatus value |
||||
|
||||
2015/07/23: |
||||
split getDevicesFromMiniSSDPD |
||||
add ttl argument to upnpDiscover() functions |
||||
increments API_VERSION to 14 |
||||
|
||||
2015/07/22: |
||||
Read USN from SSDP messages. |
||||
|
||||
2015/07/15: |
||||
Check malloc/calloc |
||||
|
||||
2015/06/16: |
||||
update getDevicesFromMiniSSDPD() to process longer minissdpd |
||||
responses |
||||
|
||||
2015/05/22: |
||||
add searchalltypes param to upnpDiscoverDevices() |
||||
increments API_VERSION to 13 |
||||
|
||||
2015/04/30: |
||||
upnpc: output version on the terminal |
||||
|
||||
2015/04/27: |
||||
_BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE |
||||
fix CMakeLists.txt COMPILE_DEFINITIONS |
||||
fix getDevicesFromMiniSSDPD() not setting scope_id |
||||
improve -r command of upnpc command line tool |
||||
|
||||
2014/11/17: |
||||
search all : |
||||
upnpDiscoverDevices() / upnpDiscoverAll() functions |
||||
listdevices executable |
||||
increment API_VERSION to 12 |
||||
validate igd_desc_parse |
||||
|
||||
2014/11/13: |
||||
increment API_VERSION to 11 |
||||
|
||||
2014/11/05: |
||||
simplified function GetUPNPUrls() |
||||
|
||||
2014/09/11: |
||||
use remoteHost arg of DeletePortMapping |
||||
|
||||
2014/09/06: |
||||
Fix python3 build |
||||
|
||||
2014/07/01: |
||||
Fix parsing of IGD2 root descriptions |
||||
|
||||
2014/06/10: |
||||
rename LIBSPEC to MINIUPNP_LIBSPEC |
||||
|
||||
2014/05/15: |
||||
Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange |
||||
|
||||
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-2015, 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,379 @@
|
||||
# $Id: Makefile,v 1.132 2015/10/26 16:59:54 nanard Exp $
|
||||
# MiniUPnP Project
|
||||
# http://miniupnp.free.fr/
|
||||
# http://miniupnp.tuxfamily.org/
|
||||
# https://github.com/miniupnp/miniupnp
|
||||
# (c) 2005-2015 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
|
||||
LIBTOOL ?= $(shell which libtool)
|
||||
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
|
||||
CFLAGS += -D_DEFAULT_SOURCE
|
||||
ifneq ($(OS), FreeBSD) |
||||
ifneq ($(OS), Darwin) |
||||
#CFLAGS += -D_POSIX_C_SOURCE=200112L
|
||||
CFLAGS += -D_XOPEN_SOURCE=600
|
||||
endif |
||||
endif |
||||
#CFLAGS += -ansi
|
||||
# -DNO_GETADDRINFO
|
||||
INSTALL = install
|
||||
SH = /bin/sh
|
||||
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
|
||||
# https://repo1.maven.org/maven2/com/nativelibs4java/jnaerator/0.12/jnaerator-0.12-shaded.jar
|
||||
JNAERATOR = jnaerator-0.12-shaded.jar
|
||||
JNAERATORARGS = -mode StandaloneJar -runtime JNAerator -library miniupnpc
|
||||
#JNAERATORBASEURL = http://jnaerator.googlecode.com/files/
|
||||
JNAERATORBASEURL = https://repo1.maven.org/maven2/com/nativelibs4java/jnaerator/0.12
|
||||
|
||||
ifeq (SunOS, $(OS)) |
||||
LDFLAGS=-lsocket -lnsl -lresolv
|
||||
endif |
||||
|
||||
# APIVERSION is used to build SONAME
|
||||
APIVERSION = 15
|
||||
|
||||
SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \
|
||||
upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \
|
||||
minixmlvalid.c testupnpreplyparse.c minissdpc.c \
|
||||
upnperrors.c testigddescparse.c testminiwget.c \
|
||||
connecthostport.c portlistingparse.c receivedata.c \
|
||||
upnpdev.c testportlistingparse.c miniupnpcmodule.c \
|
||||
minihttptestserver.c \
|
||||
listdevices.c
|
||||
|
||||
LIBOBJS = miniwget.o minixml.o igd_desc_parse.o minisoap.o \
|
||||
miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \
|
||||
connecthostport.o portlistingparse.o receivedata.o upnpdev.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 \
|
||||
upnpdev.h \
|
||||
miniupnpc_declspec.h
|
||||
|
||||
# library names
|
||||
LIBRARY = libminiupnpc.a
|
||||
ifeq ($(OS), Darwin) |
||||
SHAREDLIBRARY = libminiupnpc.dylib
|
||||
SONAME = $(basename $(SHAREDLIBRARY)).$(APIVERSION).dylib
|
||||
CFLAGS := -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 listdevices
|
||||
EXECUTABLES_ADDTESTS = testminixml minixmlvalid testupnpreplyparse \
|
||||
testigddescparse testminiwget testportlistingparse
|
||||
|
||||
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
|
||||
|
||||
TESTPORTLISTINGPARSE = testportlistingparse.o minixml.o portlistingparse.o
|
||||
|
||||
TESTIGDDESCPARSE = testigddescparse.o igd_desc_parse.o minixml.o \
|
||||
miniupnpc.o miniwget.o upnpcommands.o upnpreplyparse.o \
|
||||
minisoap.o connecthostport.o receivedata.o \
|
||||
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 \
|
||||
validateportlistingparse validateigddescparse
|
||||
|
||||
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 $@
|
||||
|
||||
validateportlistingparse: testportlistingparse |
||||
@echo "portlistingparse validation test"
|
||||
./testportlistingparse
|
||||
touch $@
|
||||
|
||||
validateigddescparse: testigddescparse |
||||
@echo "igd desc parse validation test"
|
||||
./testigddescparse testdesc/new_LiveBox_desc.xml testdesc/new_LiveBox_desc.values
|
||||
./testigddescparse testdesc/linksys_WAG200G_desc.xml testdesc/linksys_WAG200G_desc.values
|
||||
touch $@
|
||||
|
||||
clean: |
||||
$(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h
|
||||
$(RM) $(EXECUTABLES_ADDTESTS)
|
||||
# clean python stuff
|
||||
$(RM) pythonmodule pythonmodule3
|
||||
$(RM) validateminixml validateminiwget validateupnpreplyparse
|
||||
$(RM) validateigddescparse
|
||||
$(RM) minihttptestserver
|
||||
$(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) -m 644 man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
|
||||
ifeq ($(OS), Linux) |
||||
gzip -f $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
|
||||
endif |
||||
endif |
||||
|
||||
install-static: updateversion $(FILESTOINSTALL) |
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC)
|
||||
$(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC)
|
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB)
|
||||
$(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB)
|
||||
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN)
|
||||
$(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip
|
||||
|
||||
cleaninstall: |
||||
$(RM) -r $(DESTDIR)$(INSTALLDIRINC)
|
||||
$(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(LIBRARY)
|
||||
$(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY)
|
||||
|
||||
depend: |
||||
makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null
|
||||
|
||||
$(LIBRARY): $(LIBOBJS) |
||||
ifeq ($(OS), Darwin) |
||||
$(LIBTOOL) -static -o $@ $?
|
||||
else |
||||
$(AR) crs $@ $?
|
||||
endif |
||||
|
||||
$(SHAREDLIBRARY): $(LIBOBJS) |
||||
ifeq ($(OS), Darwin) |
||||
# $(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 $@ $^ $(LOADLIBES) $(LDLIBS)
|
||||
|
||||
upnpc-shared: upnpc.o $(SHAREDLIBRARY) |
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS)
|
||||
|
||||
listdevices: listdevices.o $(LIBRARY) |
||||
|
||||
testminixml: $(TESTMINIXMLOBJS) |
||||
|
||||
testminiwget: $(TESTMINIWGETOBJS) |
||||
|
||||
minixmlvalid: minixml.o minixmlvalid.o |
||||
|
||||
testupnpreplyparse: $(TESTUPNPREPLYPARSE) |
||||
|
||||
testigddescparse: $(TESTIGDDESCPARSE) |
||||
|
||||
testportlistingparse: $(TESTPORTLISTINGPARSE) |
||||
|
||||
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 miniupnpc_declspec.h upnpcommands.h upnpreplyparse.h \
|
||||
igd_desc_parse.h miniwget.h upnperrors.h $(SHAREDLIBRARY) \
|
||||
-package fr.free.miniupnp -o . -jar java/miniupnpc_$(JARSUFFIX).jar -v
|
||||
|
||||
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 miniupnpc_declspec.h igd_desc_parse.h upnpdev.h |
||||
miniupnpc.o: minissdpc.h miniwget.h minisoap.h minixml.h upnpcommands.h |
||||
miniupnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h |
||||
miniupnpc.o: connecthostport.h |
||||
minixml.o: minixml.h |
||||
minisoap.o: minisoap.h miniupnpcstrings.h |
||||
miniwget.o: miniupnpcstrings.h miniwget.h miniupnpc_declspec.h |
||||
miniwget.o: connecthostport.h receivedata.h |
||||
upnpc.o: miniwget.h miniupnpc_declspec.h miniupnpc.h igd_desc_parse.h |
||||
upnpc.o: upnpdev.h upnpcommands.h upnpreplyparse.h portlistingparse.h |
||||
upnpc.o: miniupnpctypes.h upnperrors.h miniupnpcstrings.h |
||||
upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h |
||||
upnpcommands.o: miniupnpc_declspec.h miniupnpctypes.h miniupnpc.h |
||||
upnpcommands.o: igd_desc_parse.h upnpdev.h |
||||
upnpreplyparse.o: upnpreplyparse.h minixml.h |
||||
testminixml.o: minixml.h igd_desc_parse.h |
||||
minixmlvalid.o: minixml.h |
||||
testupnpreplyparse.o: upnpreplyparse.h |
||||
minissdpc.o: minissdpc.h miniupnpc_declspec.h upnpdev.h miniupnpc.h |
||||
minissdpc.o: igd_desc_parse.h receivedata.h codelength.h |
||||
upnperrors.o: upnperrors.h miniupnpc_declspec.h upnpcommands.h |
||||
upnperrors.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h |
||||
upnperrors.o: miniupnpc.h igd_desc_parse.h upnpdev.h |
||||
testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.h |
||||
testigddescparse.o: miniupnpc_declspec.h upnpdev.h |
||||
testminiwget.o: miniwget.h miniupnpc_declspec.h |
||||
connecthostport.o: connecthostport.h |
||||
portlistingparse.o: portlistingparse.h miniupnpc_declspec.h miniupnpctypes.h |
||||
portlistingparse.o: minixml.h |
||||
receivedata.o: receivedata.h |
||||
upnpdev.o: upnpdev.h miniupnpc_declspec.h |
||||
testportlistingparse.o: portlistingparse.h miniupnpc_declspec.h |
||||
testportlistingparse.o: miniupnpctypes.h |
||||
miniupnpcmodule.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h |
||||
miniupnpcmodule.o: upnpdev.h upnpcommands.h upnpreplyparse.h |
||||
miniupnpcmodule.o: portlistingparse.h miniupnpctypes.h upnperrors.h |
||||
listdevices.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h upnpdev.h |
||||
@ -0,0 +1,98 @@
|
||||
# $Id: Makefile.mingw,v 1.22 2015/10/26 16:59:54 nanard Exp $
|
||||
# Miniupnp project.
|
||||
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
# (c) 2005-2015 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 \
|
||||
minissdpc.o \
|
||||
miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \
|
||||
connecthostport.o portlistingparse.o receivedata.o \
|
||||
upnpdev.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) -DMINIUPNP_STATICLIB -c -o $@ $<
|
||||
$(CC) $(CFLAGS) -DMINIUPNP_EXPORTS -c -o dll/$@ $<
|
||||
|
||||
upnpc.o: upnpc.c |
||||
$(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -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 |
||||
|
||||
upnpc.o: miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h |
||||
upnpc.o: upnpreplyparse.h upnpcommands.h upnperrors.h miniupnpcstrings.h |
||||
|
||||
miniwget.o: miniwget.c miniwget.h miniupnpcstrings.h connecthostport.h |
||||
|
||||
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 |
||||
|
||||
minissdpc.o: minissdpc.c minissdpc.h receivedata.h |
||||
|
||||
upnpdev.o: upnpdev.c upnpdev.h |
||||
|
||||
@ -0,0 +1,61 @@
|
||||
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-2014 Thomas Bernard |
||||
This software is subject to the conditions detailed in the |
||||
LICENSE file provided within this distribution. |
||||
|
||||
|
||||
* 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,167 @@
|
||||
$Id: apiversions.txt,v 1.8 2015/10/08 16:15:47 nanard Exp $ |
||||
|
||||
Differences in API between miniUPnPc versions |
||||
|
||||
API version 15 |
||||
changed "sameport" argument of upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice() |
||||
to "localport". When 0 or 1, behaviour is not changed, but it can take |
||||
any other value between 2 and 65535 |
||||
Existing programs should be compatible |
||||
updated macro : |
||||
#define MINIUPNPC_API_VERSION 15 |
||||
|
||||
API version 14 |
||||
miniupnpc.h |
||||
add ttl argument to upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice() |
||||
upnpDiscoverDevices() |
||||
getDevicesFromMiniSSDPD() : |
||||
connectToMiniSSDPD() / disconnectFromMiniSSDPD() |
||||
requestDevicesFromMiniSSDPD() / receiveDevicesFromMiniSSDPD() |
||||
updated macro : |
||||
#define MINIUPNPC_API_VERSION 14 |
||||
|
||||
API version 13 |
||||
miniupnpc.h: |
||||
add searchalltype param to upnpDiscoverDevices() function |
||||
updated macro : |
||||
#define MINIUPNPC_API_VERSION 13 |
||||
|
||||
API version 12 |
||||
miniupnpc.h : |
||||
add upnpDiscoverAll() / upnpDiscoverDevice() / upnpDiscoverDevices() |
||||
functions |
||||
updated macros : |
||||
#define MINIUPNPC_API_VERSION 12 |
||||
|
||||
API version 11 |
||||
|
||||
upnpreplyparse.h / portlistingparse.h : |
||||
removed usage of sys/queue.h / bsdqueue.h |
||||
|
||||
miniupnpc.h: |
||||
updated macros : |
||||
#define MINIUPNPC_API_VERSION 11 |
||||
|
||||
====================== miniUPnPc version 1.9 ====================== |
||||
API version 10 |
||||
|
||||
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,54 @@
|
||||
/* $Id: codelength.h,v 1.5 2015/07/09 12:40:18 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* Author : Thomas BERNARD |
||||
* copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subjet to the conditions detailed in the |
||||
* provided LICENCE file. */ |
||||
#ifndef CODELENGTH_H_INCLUDED |
||||
#define CODELENGTH_H_INCLUDED |
||||
|
||||
/* Encode length by using 7bit per Byte :
|
||||
* Most significant bit of each byte specifies that the |
||||
* following byte is part of the code */ |
||||
|
||||
/* n : unsigned
|
||||
* p : unsigned char * |
||||
*/ |
||||
#define DECODELENGTH(n, p) n = 0; \ |
||||
do { n = (n << 7) | (*p & 0x7f); } \
|
||||
while((*(p++)&0x80) && (n<(1<<25))); |
||||
|
||||
/* n : unsigned
|
||||
* READ : function/macro to read one byte (unsigned char) |
||||
*/ |
||||
#define DECODELENGTH_READ(n, READ) \ |
||||
n = 0; \
|
||||
do { \
|
||||
unsigned char c; \
|
||||
READ(c); \
|
||||
n = (n << 7) | (c & 0x07f); \
|
||||
if(!(c&0x80)) break; \
|
||||
} while(n<(1<<25)); |
||||
|
||||
/* n : unsigned
|
||||
* p : unsigned char * |
||||
* p_limit : unsigned char * |
||||
*/ |
||||
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \ |
||||
n = 0; \
|
||||
do { \
|
||||
if((p) >= (p_limit)) break; \
|
||||
n = (n << 7) | (*(p) & 0x7f); \
|
||||
} while((*((p)++)&0x80) && (n<(1<<25))); |
||||
|
||||
|
||||
/* n : unsigned
|
||||
* p : unsigned char * |
||||
*/ |
||||
#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \ |
||||
if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
|
||||
if(n>=16384) *(p++) = (n >> 14) | 0x80; \
|
||||
if(n>=128) *(p++) = (n >> 7) | 0x80; \
|
||||
*(p++) = n & 0x7f; |
||||
|
||||
#endif /* CODELENGTH_H_INCLUDED */ |
||||
@ -0,0 +1,264 @@
|
||||
/* $Id: connecthostport.c,v 1.15 2015/10/09 16:26:19 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2010-2015 Thomas Bernard |
||||
* This software is subject to the conditions detailed in the |
||||
* LICENCE file provided in this distribution. */ |
||||
|
||||
/* use getaddrinfo() or gethostbyname()
|
||||
* uncomment the following line in order to use gethostbyname() */ |
||||
#ifdef NO_GETADDRINFO |
||||
#define USE_GETHOSTBYNAME |
||||
#endif |
||||
|
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#ifdef _WIN32 |
||||
#include <winsock2.h> |
||||
#include <ws2tcpip.h> |
||||
#include <io.h> |
||||
#define MAXHOSTNAMELEN 64 |
||||
#define snprintf _snprintf |
||||
#define herror |
||||
#define socklen_t int |
||||
#else /* #ifdef _WIN32 */ |
||||
#include <unistd.h> |
||||
#include <sys/types.h> |
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT |
||||
#include <sys/time.h> |
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ |
||||
#include <sys/param.h> |
||||
#include <sys/select.h> |
||||
#include <errno.h> |
||||
#define closesocket close |
||||
#include <netdb.h> |
||||
#include <netinet/in.h> |
||||
/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
|
||||
* during the connect() call */ |
||||
#define MINIUPNPC_IGNORE_EINTR |
||||
#ifndef USE_GETHOSTBYNAME |
||||
#include <sys/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,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,123 @@
|
||||
/* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subject to the conditions detailed in the |
||||
* LICENCE file provided in this distribution. */ |
||||
|
||||
#include "igd_desc_parse.h" |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
/* Start element handler :
|
||||
* update nesting level counter and copy element name */ |
||||
void IGDstartelt(void * d, const char * name, int l) |
||||
{ |
||||
struct IGDdatas * datas = (struct IGDdatas *)d; |
||||
if(l >= MINIUPNPC_URL_MAXSIZE) |
||||
l = MINIUPNPC_URL_MAXSIZE-1; |
||||
memcpy(datas->cureltname, name, l); |
||||
datas->cureltname[l] = '\0'; |
||||
datas->level++; |
||||
if( (l==7) && !memcmp(name, "service", l) ) { |
||||
datas->tmp.controlurl[0] = '\0'; |
||||
datas->tmp.eventsuburl[0] = '\0'; |
||||
datas->tmp.scpdurl[0] = '\0'; |
||||
datas->tmp.servicetype[0] = '\0'; |
||||
} |
||||
} |
||||
|
||||
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) |
||||
|
||||
/* End element handler :
|
||||
* update nesting level counter and update parser state if |
||||
* service element is parsed */ |
||||
void IGDendelt(void * d, const char * name, int l) |
||||
{ |
||||
struct IGDdatas * datas = (struct IGDdatas *)d; |
||||
datas->level--; |
||||
/*printf("endelt %2d %.*s\n", datas->level, l, name);*/ |
||||
if( (l==7) && !memcmp(name, "service", l) ) |
||||
{ |
||||
if(COMPARE(datas->tmp.servicetype, |
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) { |
||||
memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service)); |
||||
} else if(COMPARE(datas->tmp.servicetype, |
||||
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) { |
||||
memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service)); |
||||
} else if(COMPARE(datas->tmp.servicetype, |
||||
"urn:schemas-upnp-org:service:WANIPConnection:") |
||||
|| COMPARE(datas->tmp.servicetype, |
||||
"urn:schemas-upnp-org:service:WANPPPConnection:") ) { |
||||
if(datas->first.servicetype[0] == '\0') { |
||||
memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service)); |
||||
} else { |
||||
memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service)); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* Data handler :
|
||||
* copy data depending on the current element name and state */ |
||||
void IGDdata(void * d, const char * data, int l) |
||||
{ |
||||
struct IGDdatas * datas = (struct IGDdatas *)d; |
||||
char * dstmember = 0; |
||||
/*printf("%2d %s : %.*s\n",
|
||||
datas->level, datas->cureltname, l, data); */ |
||||
if( !strcmp(datas->cureltname, "URLBase") ) |
||||
dstmember = datas->urlbase; |
||||
else if( !strcmp(datas->cureltname, "presentationURL") ) |
||||
dstmember = datas->presentationurl; |
||||
else if( !strcmp(datas->cureltname, "serviceType") ) |
||||
dstmember = datas->tmp.servicetype; |
||||
else if( !strcmp(datas->cureltname, "controlURL") ) |
||||
dstmember = datas->tmp.controlurl; |
||||
else if( !strcmp(datas->cureltname, "eventSubURL") ) |
||||
dstmember = datas->tmp.eventsuburl; |
||||
else if( !strcmp(datas->cureltname, "SCPDURL") ) |
||||
dstmember = datas->tmp.scpdurl; |
||||
/* else if( !strcmp(datas->cureltname, "deviceType") )
|
||||
dstmember = datas->devicetype_tmp;*/ |
||||
if(dstmember) |
||||
{ |
||||
if(l>=MINIUPNPC_URL_MAXSIZE) |
||||
l = MINIUPNPC_URL_MAXSIZE-1; |
||||
memcpy(dstmember, data, l); |
||||
dstmember[l] = '\0'; |
||||
} |
||||
} |
||||
|
||||
#ifdef DEBUG |
||||
void printIGD(struct IGDdatas * d) |
||||
{ |
||||
printf("urlbase = '%s'\n", d->urlbase); |
||||
printf("WAN Device (Common interface config) :\n"); |
||||
/*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/ |
||||
printf(" serviceType = '%s'\n", d->CIF.servicetype); |
||||
printf(" controlURL = '%s'\n", d->CIF.controlurl); |
||||
printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl); |
||||
printf(" SCPDURL = '%s'\n", d->CIF.scpdurl); |
||||
printf("primary WAN Connection Device (IP or PPP Connection):\n"); |
||||
/*printf(" deviceType = '%s'\n", d->first.devicetype);*/ |
||||
printf(" servicetype = '%s'\n", d->first.servicetype); |
||||
printf(" controlURL = '%s'\n", d->first.controlurl); |
||||
printf(" eventSubURL = '%s'\n", d->first.eventsuburl); |
||||
printf(" SCPDURL = '%s'\n", d->first.scpdurl); |
||||
printf("secondary WAN Connection Device (IP or PPP Connection):\n"); |
||||
/*printf(" deviceType = '%s'\n", d->second.devicetype);*/ |
||||
printf(" servicetype = '%s'\n", d->second.servicetype); |
||||
printf(" controlURL = '%s'\n", d->second.controlurl); |
||||
printf(" eventSubURL = '%s'\n", d->second.eventsuburl); |
||||
printf(" SCPDURL = '%s'\n", d->second.scpdurl); |
||||
printf("WAN IPv6 Firewall Control :\n"); |
||||
/*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/ |
||||
printf(" servicetype = '%s'\n", d->IPv6FC.servicetype); |
||||
printf(" controlURL = '%s'\n", d->IPv6FC.controlurl); |
||||
printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl); |
||||
printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl); |
||||
} |
||||
#endif /* DEBUG */ |
||||
|
||||
@ -0,0 +1,49 @@
|
||||
/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2005-2014 Thomas Bernard |
||||
* This software is subject to the conditions detailed in the |
||||
* LICENCE file provided in this distribution. |
||||
* */ |
||||
#ifndef IGD_DESC_PARSE_H_INCLUDED |
||||
#define IGD_DESC_PARSE_H_INCLUDED |
||||
|
||||
/* Structure to store the result of the parsing of UPnP
|
||||
* descriptions of Internet Gateway Devices */ |
||||
#define MINIUPNPC_URL_MAXSIZE (128) |
||||
struct IGDdatas_service { |
||||
char controlurl[MINIUPNPC_URL_MAXSIZE]; |
||||
char eventsuburl[MINIUPNPC_URL_MAXSIZE]; |
||||
char scpdurl[MINIUPNPC_URL_MAXSIZE]; |
||||
char servicetype[MINIUPNPC_URL_MAXSIZE]; |
||||
/*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ |
||||
}; |
||||
|
||||
struct IGDdatas { |
||||
char cureltname[MINIUPNPC_URL_MAXSIZE]; |
||||
char urlbase[MINIUPNPC_URL_MAXSIZE]; |
||||
char presentationurl[MINIUPNPC_URL_MAXSIZE]; |
||||
int level; |
||||
/*int state;*/ |
||||
/* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ |
||||
struct IGDdatas_service CIF; |
||||
/* "urn:schemas-upnp-org:service:WANIPConnection:1"
|
||||
* "urn:schemas-upnp-org:service:WANPPPConnection:1" */ |
||||
struct IGDdatas_service first; |
||||
/* if both WANIPConnection and WANPPPConnection are present */ |
||||
struct IGDdatas_service second; |
||||
/* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ |
||||
struct IGDdatas_service IPv6FC; |
||||
/* tmp */ |
||||
struct IGDdatas_service tmp; |
||||
}; |
||||
|
||||
void IGDstartelt(void *, const char *, int); |
||||
void IGDendelt(void *, const char *, int); |
||||
void IGDdata(void *, const char *, int); |
||||
#ifdef DEBUG |
||||
void printIGD(struct IGDdatas *); |
||||
#endif /* DEBUG */ |
||||
|
||||
#endif /* IGD_DESC_PARSE_H_INCLUDED */ |
||||
@ -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, (byte)2, IntBuffer.allocate(1)); |
||||
if (devlist != null) { |
||||
System.out.println("List of UPNP devices found on the network :"); |
||||
for (UPNPDev device = devlist; device != null; device = device.pNext) { |
||||
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,110 @@
|
||||
/* $Id: listdevices.c,v 1.7 2015/10/08 16:15:47 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2013-2015 Thomas Bernard |
||||
* This software is subject to the conditions detailed in the |
||||
* LICENCE file provided in this distribution. */ |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#ifdef _WIN32 |
||||
#include <winsock2.h> |
||||
#endif /* _WIN32 */ |
||||
#include "miniupnpc.h" |
||||
|
||||
int main(int argc, char * * argv) |
||||
{ |
||||
const char * searched_device = NULL; |
||||
const char * * searched_devices = NULL; |
||||
const char * multicastif = 0; |
||||
const char * minissdpdpath = 0; |
||||
int ipv6 = 0; |
||||
unsigned char ttl = 2; |
||||
int error = 0; |
||||
struct UPNPDev * devlist = 0; |
||||
struct UPNPDev * dev; |
||||
int i; |
||||
|
||||
#ifdef _WIN32 |
||||
WSADATA wsaData; |
||||
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); |
||||
if(nResult != NO_ERROR) |
||||
{ |
||||
fprintf(stderr, "WSAStartup() failed.\n"); |
||||
return -1; |
||||
} |
||||
#endif |
||||
|
||||
for(i = 1; i < argc; i++) { |
||||
if(strcmp(argv[i], "-6") == 0) |
||||
ipv6 = 1; |
||||
else if(strcmp(argv[i], "-d") == 0) { |
||||
if(++i >= argc) { |
||||
fprintf(stderr, "%s option needs one argument\n", "-d"); |
||||
return 1; |
||||
} |
||||
searched_device = argv[i]; |
||||
} else if(strcmp(argv[i], "-t") == 0) { |
||||
if(++i >= argc) { |
||||
fprintf(stderr, "%s option needs one argument\n", "-t"); |
||||
return 1; |
||||
} |
||||
ttl = (unsigned char)atoi(argv[i]); |
||||
} else if(strcmp(argv[i], "-l") == 0) { |
||||
if(++i >= argc) { |
||||
fprintf(stderr, "-l option needs at least one argument\n"); |
||||
return 1; |
||||
} |
||||
searched_devices = (const char * *)(argv + i); |
||||
break; |
||||
} else if(strcmp(argv[i], "-m") == 0) { |
||||
if(++i >= argc) { |
||||
fprintf(stderr, "-m option needs one argument\n"); |
||||
return 1; |
||||
} |
||||
multicastif = argv[i]; |
||||
} else { |
||||
printf("usage : %s [options] [-l <device1> <device2> ...]\n", argv[0]); |
||||
printf("options :\n"); |
||||
printf(" -6 : use IPv6\n"); |
||||
printf(" -m address/ifname : network interface to use for multicast\n"); |
||||
printf(" -d <device string> : search only for this type of device\n"); |
||||
printf(" -l <device1> <device2> ... : search only for theses types of device\n"); |
||||
printf(" -t ttl : set multicast TTL. Default value is 2.\n"); |
||||
printf(" -h : this help\n"); |
||||
return 1; |
||||
} |
||||
} |
||||
|
||||
if(searched_device) { |
||||
printf("searching UPnP device type %s\n", searched_device); |
||||
devlist = upnpDiscoverDevice(searched_device, |
||||
2000, multicastif, minissdpdpath, |
||||
0/*localport*/, ipv6, ttl, &error); |
||||
} else if(searched_devices) { |
||||
printf("searching UPnP device types :\n"); |
||||
for(i = 0; searched_devices[i]; i++) |
||||
printf("\t%s\n", searched_devices[i]); |
||||
devlist = upnpDiscoverDevices(searched_devices, |
||||
2000, multicastif, minissdpdpath, |
||||
0/*localport*/, ipv6, ttl, &error, 1); |
||||
} else { |
||||
printf("searching all UPnP devices\n"); |
||||
devlist = upnpDiscoverAll(2000, multicastif, minissdpdpath, |
||||
0/*localport*/, ipv6, ttl, &error); |
||||
} |
||||
if(devlist) { |
||||
for(dev = devlist, i = 1; dev != NULL; dev = dev->pNext, i++) { |
||||
printf("%3d: %-48s\n", i, dev->st); |
||||
printf(" %s\n", dev->descURL); |
||||
printf(" %s\n", dev->usn); |
||||
} |
||||
freeUPNPDevlist(devlist); |
||||
} else { |
||||
printf("no device found.\n"); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
@ -0,0 +1,55 @@
|
||||
.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 localport, int ipv6, int * error);" |
||||
execute the discovery process. |
||||
delay (in millisecond) is the maximum time for waiting any device response. |
||||
If available, device list will be obtained from MiniSSDPd. |
||||
Default path for minissdpd socket will be used if minissdpdsock argument is NULL. |
||||
If multicastif is not NULL, it will be used instead of the default multicast interface for sending SSDP discover packets. |
||||
If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent |
||||
from the source port 1900 (same as destination port), if set to |
||||
UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will |
||||
be attempted as the source port. |
||||
If ipv6 is not 0, IPv6 is used instead of IPv4 for the discovery process. |
||||
.IP "void freeUPNPDevlist(struct UPNPDev * devlist);" |
||||
free the list returned by upnpDiscover(). |
||||
.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,655 @@
|
||||
/* $Id: minihttptestserver.c,v 1.18 2015/07/15 12:41:15 nanard Exp $ */ |
||||
/* Project : miniUPnP
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2011-2015 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) |
||||
{ |
||||
(void)sig; |
||||
/* printf("handle_signal_chld(%d)\n", sig); */ |
||||
++child_to_wait_for; |
||||
} |
||||
|
||||
/**
|
||||
* signal handler for SIGINT (CRTL C) |
||||
*/ |
||||
void handle_signal_int(int sig) |
||||
{ |
||||
(void)sig; |
||||
/* printf("handle_signal_int(%d)\n", sig); */ |
||||
quit = 1; |
||||
} |
||||
|
||||
/**
|
||||
* 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); |
||||
if(response_buffer == NULL) |
||||
return NULL; |
||||
*response_len = snprintf(response_buffer, buffer_length, |
||||
"HTTP/1.1 200 OK\r\n" |
||||
"Content-Type: text/plain\r\n" |
||||
"Transfer-Encoding: chunked\r\n" |
||||
"\r\n"); |
||||
|
||||
/* build the content */ |
||||
content_buffer = malloc(content_length); |
||||
if(content_buffer == NULL) { |
||||
free(response_buffer); |
||||
return NULL; |
||||
} |
||||
build_content(content_buffer, content_length); |
||||
|
||||
/* chunk it */ |
||||
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; |
||||
} |
||||
|
||||
/* favicon.ico generator */ |
||||
#ifdef OLD_HEADER |
||||
#define FAVICON_LENGTH (6 + 16 + 12 + 8 + 32 * 4) |
||||
#else |
||||
#define FAVICON_LENGTH (6 + 16 + 40 + 8 + 32 * 4) |
||||
#endif |
||||
void build_favicon_content(char * p, int n) |
||||
{ |
||||
int i; |
||||
if(n < FAVICON_LENGTH) |
||||
return; |
||||
/* header : 6 bytes */ |
||||
*p++ = 0; |
||||
*p++ = 0; |
||||
*p++ = 1; /* type : ICO */ |
||||
*p++ = 0; |
||||
*p++ = 1; /* number of images in file */ |
||||
*p++ = 0; |
||||
/* image directory (1 entry) : 16 bytes */ |
||||
*p++ = 16; /* width */ |
||||
*p++ = 16; /* height */ |
||||
*p++ = 2; /* number of colors in the palette. 0 = no palette */ |
||||
*p++ = 0; /* reserved */ |
||||
*p++ = 1; /* color planes */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 1; /* bpp */ |
||||
*p++ = 0; /* " */ |
||||
#ifdef OLD_HEADER |
||||
*p++ = 12 + 8 + 32 * 4; /* bmp size */ |
||||
#else |
||||
*p++ = 40 + 8 + 32 * 4; /* bmp size */ |
||||
#endif |
||||
*p++ = 0; /* " */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 6 + 16; /* bmp offset */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 0; /* " */ |
||||
/* BMP */ |
||||
#ifdef OLD_HEADER |
||||
/* BITMAPCOREHEADER */ |
||||
*p++ = 12; /* size of this header */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 16; /* width */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 16 * 2; /* height x 2 ! */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 1; /* color planes */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 1; /* bpp */ |
||||
*p++ = 0; /* " */ |
||||
#else |
||||
/* BITMAPINFOHEADER */ |
||||
*p++ = 40; /* size of this header */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 16; /* width */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 16 * 2; /* height x 2 ! */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 1; /* color planes */ |
||||
*p++ = 0; /* " */ |
||||
*p++ = 1; /* bpp */ |
||||
*p++ = 0; /* " */ |
||||
/* compression method, image size, ppm x, ppm y */ |
||||
/* colors in the palette ? */ |
||||
/* important colors */ |
||||
for(i = 4 * 6; i > 0; --i) |
||||
*p++ = 0; |
||||
#endif |
||||
/* palette */ |
||||
*p++ = 0; /* b */ |
||||
*p++ = 0; /* g */ |
||||
*p++ = 0; /* r */ |
||||
*p++ = 0; /* reserved */ |
||||
*p++ = 255; /* b */ |
||||
*p++ = 255; /* g */ |
||||
*p++ = 255; /* r */ |
||||
*p++ = 0; /* reserved */ |
||||
/* pixel data */ |
||||
for(i = 16; i > 0; --i) { |
||||
if(i & 1) { |
||||
*p++ = 0125; |
||||
*p++ = 0125; |
||||
} else { |
||||
*p++ = 0252; |
||||
*p++ = 0252; |
||||
} |
||||
*p++ = 0; |
||||
*p++ = 0; |
||||
} |
||||
/* Opacity MASK */ |
||||
for(i = 16 * 4; i > 0; --i) { |
||||
*p++ = 0; |
||||
} |
||||
} |
||||
|
||||
enum modes { |
||||
MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL, MODE_FAVICON |
||||
}; |
||||
|
||||
const struct { |
||||
const enum modes mode; |
||||
const char * text; |
||||
} modes_array[] = { |
||||
{MODE_CHUNKED, "chunked"}, |
||||
{MODE_ADDCRAP, "addcrap"}, |
||||
{MODE_NORMAL, "normal"}, |
||||
{MODE_FAVICON, "favicon.ico"}, |
||||
{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) { |
||||
if(errno == EINTR) |
||||
continue; |
||||
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 */ |
||||
printf("no HTTP header found in the request\n"); |
||||
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); |
||||
if(!response_buffer) |
||||
break; |
||||
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; |
||||
p = realloc(response_buffer, response_len); |
||||
if(p == NULL) { |
||||
/* error 500 */ |
||||
free(response_buffer); |
||||
response_buffer = NULL; |
||||
break; |
||||
} |
||||
response_buffer = p; |
||||
build_content(response_buffer + n, content_length); |
||||
build_crap(response_buffer + n + content_length, CRAP_LENGTH); |
||||
break; |
||||
case MODE_FAVICON: |
||||
content_length = FAVICON_LENGTH; |
||||
response_len = content_length + 256; |
||||
response_buffer = malloc(response_len); |
||||
if(!response_buffer) |
||||
break; |
||||
n = snprintf(response_buffer, response_len, |
||||
"HTTP/1.1 200 OK\r\n" |
||||
"Server: minihttptestserver\r\n" |
||||
"Content-Type: image/vnd.microsoft.icon\r\n" |
||||
"Content-Length: %d\r\n" |
||||
"\r\n", content_length); |
||||
/* image/x-icon */ |
||||
build_favicon_content(response_buffer + n, content_length); |
||||
response_len = content_length + n; |
||||
break; |
||||
default: |
||||
response_len = content_length+256; |
||||
response_buffer = malloc(response_len); |
||||
if(!response_buffer) |
||||
break; |
||||
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; |
||||
p = realloc(response_buffer, response_len); |
||||
if(p == NULL) { |
||||
/* Error 500 */ |
||||
free(response_buffer); |
||||
response_buffer = NULL; |
||||
break; |
||||
} |
||||
response_buffer = p; |
||||
build_content(response_buffer + n, response_len - n); |
||||
} |
||||
|
||||
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; |
||||
struct sigaction sa; |
||||
|
||||
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)); |
||||
|
||||
memset(&sa, 0, sizeof(struct sigaction)); |
||||
|
||||
/*signal(SIGCHLD, handle_signal_chld);*/ |
||||
sa.sa_handler = handle_signal_chld; |
||||
if(sigaction(SIGCHLD, &sa, NULL) < 0) { |
||||
perror("sigaction"); |
||||
return 1; |
||||
} |
||||
/*signal(SIGINT, handle_signal_int);*/ |
||||
sa.sa_handler = handle_signal_int; |
||||
if(sigaction(SIGINT, &sa, NULL) < 0) { |
||||
perror("sigaction"); |
||||
return 1; |
||||
} |
||||
|
||||
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); |
||||
if(buffer == NULL) { |
||||
fprintf(stderr, "memory allocation error\n"); |
||||
} else { |
||||
build_content(buffer, 16*1024); |
||||
i = fwrite(buffer, 1, 16*1024, f); |
||||
if(i != 16*1024) { |
||||
fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024); |
||||
} |
||||
free(buffer); |
||||
} |
||||
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; |
||||
} |
||||
client_addrlen = sizeof(struct sockaddr_storage); |
||||
c = accept(s, (struct sockaddr *)&client_addr, |
||||
&client_addrlen); |
||||
if(c < 0) { |
||||
if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) |
||||
continue; |
||||
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,123 @@
|
||||
/* $Id: minisoap.c,v 1.24 2015/10/26 17:05:07 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subject to the conditions detailed in the |
||||
* LICENCE file provided in this distribution. |
||||
* |
||||
* Minimal SOAP implementation for UPnP protocol. |
||||
*/ |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#ifdef _WIN32 |
||||
#include <io.h> |
||||
#include <winsock2.h> |
||||
#define snprintf _snprintf |
||||
#else |
||||
#include <unistd.h> |
||||
#include <sys/types.h> |
||||
#include <sys/socket.h> |
||||
#endif |
||||
#include "minisoap.h" |
||||
#include "miniupnpcstrings.h" |
||||
|
||||
/* only for malloc */ |
||||
#include <stdlib.h> |
||||
|
||||
#ifdef _WIN32 |
||||
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); |
||||
#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, we could use writev() for that */ |
||||
p = malloc(headerssize+bodysize); |
||||
if(!p) |
||||
return -1; |
||||
memcpy(p, headers, headerssize); |
||||
memcpy(p+headerssize, body, bodysize); |
||||
/*n = write(fd, p, headerssize+bodysize);*/ |
||||
n = send(fd, p, headerssize+bodysize, 0); |
||||
if(n<0) { |
||||
PRINT_SOCKET_ERROR("send"); |
||||
} |
||||
/* disable send on the socket */ |
||||
/* draytek routers dont seems to like that... */ |
||||
#if 0 |
||||
#ifdef _WIN32 |
||||
if(shutdown(fd, SD_SEND)<0) { |
||||
#else |
||||
if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/ |
||||
#endif |
||||
PRINT_SOCKET_ERROR("shutdown"); |
||||
} |
||||
#endif |
||||
free(p); |
||||
return n; |
||||
} |
||||
|
||||
/* self explanatory */ |
||||
int soapPostSubmit(int fd, |
||||
const char * url, |
||||
const char * host, |
||||
unsigned short port, |
||||
const char * action, |
||||
const char * body, |
||||
const char * httpversion) |
||||
{ |
||||
int bodysize; |
||||
char headerbuf[512]; |
||||
int headerssize; |
||||
char portstr[8]; |
||||
bodysize = (int)strlen(body); |
||||
/* We are not using keep-alive HTTP connections.
|
||||
* HTTP/1.1 needs the header Connection: close to do that. |
||||
* This is the default with HTTP/1.0 |
||||
* Using HTTP/1.1 means we need to support chunked transfer-encoding : |
||||
* When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked |
||||
* transfer encoding. */ |
||||
/* Connection: Close is normally there only in HTTP/1.1 but who knows */ |
||||
portstr[0] = '\0'; |
||||
if(port != 80) |
||||
snprintf(portstr, sizeof(portstr), ":%hu", port); |
||||
headerssize = snprintf(headerbuf, sizeof(headerbuf), |
||||
"POST %s HTTP/%s\r\n" |
||||
"Host: %s%s\r\n" |
||||
"User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" |
||||
"Content-Length: %d\r\n" |
||||
"Content-Type: text/xml\r\n" |
||||
"SOAPAction: \"%s\"\r\n" |
||||
"Connection: Close\r\n" |
||||
"Cache-Control: no-cache\r\n" /* ??? */ |
||||
"Pragma: no-cache\r\n" |
||||
"\r\n", |
||||
url, httpversion, host, portstr, bodysize, action); |
||||
if ((unsigned int)headerssize >= sizeof(headerbuf)) |
||||
return -1; |
||||
#ifdef DEBUG |
||||
/*printf("SOAP request : headersize=%d bodysize=%d\n",
|
||||
headerssize, bodysize); |
||||
*/ |
||||
printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n", |
||||
url, httpversion, host, portstr); |
||||
printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize); |
||||
printf("Headers :\n%s", headerbuf); |
||||
printf("Body :\n%s\n", body); |
||||
#endif |
||||
return httpWrite(fd, body, bodysize, headerbuf, headerssize); |
||||
} |
||||
|
||||
|
||||
@ -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,849 @@
|
||||
/* $Id: minissdpc.c,v 1.30 2015/10/26 17:05:07 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD |
||||
* copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subjet to the conditions detailed in the |
||||
* provided LICENCE file. */ |
||||
/*#include <syslog.h>*/ |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <sys/types.h> |
||||
#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) |
||||
#ifdef _WIN32 |
||||
#include <winsock2.h> |
||||
#include <ws2tcpip.h> |
||||
#include <io.h> |
||||
#include <iphlpapi.h> |
||||
#include <winsock.h> |
||||
#define snprintf _snprintf |
||||
#if !defined(_MSC_VER) |
||||
#include <stdint.h> |
||||
#else /* !defined(_MSC_VER) */ |
||||
typedef unsigned short uint16_t; |
||||
#endif /* !defined(_MSC_VER) */ |
||||
#ifndef strncasecmp |
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400) |
||||
#define strncasecmp _memicmp |
||||
#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ |
||||
#define strncasecmp memicmp |
||||
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ |
||||
#endif /* #ifndef strncasecmp */ |
||||
#endif /* _WIN32 */ |
||||
#if defined(__amigaos__) || defined(__amigaos4__) |
||||
#include <sys/socket.h> |
||||
#endif /* defined(__amigaos__) || defined(__amigaos4__) */ |
||||
#if defined(__amigaos__) |
||||
#define uint16_t unsigned short |
||||
#endif /* defined(__amigaos__) */ |
||||
/* Hack */ |
||||
#define UNIX_PATH_LEN 108 |
||||
struct sockaddr_un { |
||||
uint16_t sun_family; |
||||
char sun_path[UNIX_PATH_LEN]; |
||||
}; |
||||
#else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */ |
||||
#include <strings.h> |
||||
#include <unistd.h> |
||||
#include <sys/socket.h> |
||||
#include <sys/param.h> |
||||
#include <sys/time.h> |
||||
#include <sys/un.h> |
||||
#include <netinet/in.h> |
||||
#include <arpa/inet.h> |
||||
#include <netdb.h> |
||||
#include <net/if.h> |
||||
#define closesocket close |
||||
#endif |
||||
|
||||
#ifdef _WIN32 |
||||
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); |
||||
#else |
||||
#define PRINT_SOCKET_ERROR(x) perror(x) |
||||
#endif |
||||
|
||||
#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__) |
||||
#define HAS_IP_MREQN |
||||
#endif |
||||
|
||||
#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN) |
||||
/* Several versions of glibc don't define this structure,
|
||||
* define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */ |
||||
struct ip_mreqn |
||||
{ |
||||
struct in_addr imr_multiaddr; /* IP multicast address of group */ |
||||
struct in_addr imr_address; /* local IP address of interface */ |
||||
int imr_ifindex; /* Interface index */ |
||||
}; |
||||
#endif |
||||
|
||||
#if defined(__amigaos__) || defined(__amigaos4__) |
||||
/* Amiga OS specific stuff */ |
||||
#define TIMEVAL struct timeval |
||||
#endif |
||||
|
||||
#include "minissdpc.h" |
||||
#include "miniupnpc.h" |
||||
#include "receivedata.h" |
||||
|
||||
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) |
||||
|
||||
#include "codelength.h" |
||||
|
||||
struct UPNPDev * |
||||
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error) |
||||
{ |
||||
struct UPNPDev * devlist = NULL; |
||||
int s; |
||||
int res; |
||||
|
||||
s = connectToMiniSSDPD(socketpath); |
||||
if (s < 0) { |
||||
if (error) |
||||
*error = s; |
||||
return NULL; |
||||
} |
||||
res = requestDevicesFromMiniSSDPD(s, devtype); |
||||
if (res < 0) { |
||||
if (error) |
||||
*error = res; |
||||
} else { |
||||
devlist = receiveDevicesFromMiniSSDPD(s, error); |
||||
} |
||||
disconnectFromMiniSSDPD(s); |
||||
return devlist; |
||||
} |
||||
|
||||
/* macros used to read from unix socket */ |
||||
#define READ_BYTE_BUFFER(c) \ |
||||
if((int)bufferindex >= n) { \
|
||||
n = read(s, buffer, sizeof(buffer)); \
|
||||
if(n<=0) break; \
|
||||
bufferindex = 0; \
|
||||
} \
|
||||
c = buffer[bufferindex++]; |
||||
|
||||
#ifndef MIN |
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) |
||||
#endif /* MIN */ |
||||
|
||||
#define READ_COPY_BUFFER(dst, len) \ |
||||
for(l = len, p = (unsigned char *)dst; l > 0; ) { \
|
||||
unsigned int lcopy; \
|
||||
if((int)bufferindex >= n) { \
|
||||
n = read(s, buffer, sizeof(buffer)); \
|
||||
if(n<=0) break; \
|
||||
bufferindex = 0; \
|
||||
} \
|
||||
lcopy = MIN(l, (n - bufferindex)); \
|
||||
memcpy(p, buffer + bufferindex, lcopy); \
|
||||
l -= lcopy; \
|
||||
p += lcopy; \
|
||||
bufferindex += lcopy; \
|
||||
} |
||||
|
||||
#define READ_DISCARD_BUFFER(len) \ |
||||
for(l = len; l > 0; ) { \
|
||||
unsigned int lcopy; \
|
||||
if(bufferindex >= n) { \
|
||||
n = read(s, buffer, sizeof(buffer)); \
|
||||
if(n<=0) break; \
|
||||
bufferindex = 0; \
|
||||
} \
|
||||
lcopy = MIN(l, (n - bufferindex)); \
|
||||
l -= lcopy; \
|
||||
bufferindex += lcopy; \
|
||||
} |
||||
|
||||
int |
||||
connectToMiniSSDPD(const char * socketpath) |
||||
{ |
||||
int s; |
||||
struct sockaddr_un addr; |
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT |
||||
struct timeval timeout; |
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ |
||||
|
||||
s = socket(AF_UNIX, SOCK_STREAM, 0); |
||||
if(s < 0) |
||||
{ |
||||
/*syslog(LOG_ERR, "socket(unix): %m");*/ |
||||
perror("socket(unix)"); |
||||
return MINISSDPC_SOCKET_ERROR; |
||||
} |
||||
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT |
||||
/* setting a 3 seconds timeout */ |
||||
timeout.tv_sec = 3; |
||||
timeout.tv_usec = 0; |
||||
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) |
||||
{ |
||||
perror("setsockopt"); |
||||
} |
||||
timeout.tv_sec = 3; |
||||
timeout.tv_usec = 0; |
||||
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) |
||||
{ |
||||
perror("setsockopt"); |
||||
} |
||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ |
||||
if(!socketpath) |
||||
socketpath = "/var/run/minissdpd.sock"; |
||||
addr.sun_family = AF_UNIX; |
||||
strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path)); |
||||
/* TODO : check if we need to handle the EINTR */ |
||||
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) |
||||
{ |
||||
/*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ |
||||
close(s); |
||||
return MINISSDPC_SOCKET_ERROR; |
||||
} |
||||
return s; |
||||
} |
||||
|
||||
int |
||||
disconnectFromMiniSSDPD(int s) |
||||
{ |
||||
if (close(s) < 0) |
||||
return MINISSDPC_SOCKET_ERROR; |
||||
return MINISSDPC_SUCCESS; |
||||
} |
||||
|
||||
int |
||||
requestDevicesFromMiniSSDPD(int s, const char * devtype) |
||||
{ |
||||
unsigned char buffer[256]; |
||||
unsigned char * p; |
||||
unsigned int stsize, l; |
||||
|
||||
stsize = strlen(devtype); |
||||
if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8)) |
||||
{ |
||||
buffer[0] = 3; /* request type 3 : everything */ |
||||
} |
||||
else |
||||
{ |
||||
buffer[0] = 1; /* request type 1 : request devices/services by type */ |
||||
} |
||||
p = buffer + 1; |
||||
l = stsize; CODELENGTH(l, p); |
||||
if(p + stsize > buffer + sizeof(buffer)) |
||||
{ |
||||
/* devtype is too long ! */ |
||||
#ifdef DEBUG |
||||
fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n", |
||||
stsize, (unsigned)sizeof(buffer)); |
||||
#endif /* DEBUG */ |
||||
return MINISSDPC_INVALID_INPUT; |
||||
} |
||||
memcpy(p, devtype, stsize); |
||||
p += stsize; |
||||
if(write(s, buffer, p - buffer) < 0) |
||||
{ |
||||
/*syslog(LOG_ERR, "write(): %m");*/ |
||||
perror("minissdpc.c: write()"); |
||||
return MINISSDPC_SOCKET_ERROR; |
||||
} |
||||
return MINISSDPC_SUCCESS; |
||||
} |
||||
|
||||
struct UPNPDev * |
||||
receiveDevicesFromMiniSSDPD(int s, int * error) |
||||
{ |
||||
struct UPNPDev * tmp; |
||||
struct UPNPDev * devlist = NULL; |
||||
unsigned char buffer[256]; |
||||
ssize_t n; |
||||
unsigned char * p; |
||||
unsigned char * url; |
||||
unsigned char * st; |
||||
unsigned int bufferindex; |
||||
unsigned int i, ndev; |
||||
unsigned int urlsize, stsize, usnsize, l; |
||||
|
||||
n = read(s, buffer, sizeof(buffer)); |
||||
if(n<=0) |
||||
{ |
||||
perror("minissdpc.c: read()"); |
||||
if (error) |
||||
*error = MINISSDPC_SOCKET_ERROR; |
||||
return NULL; |
||||
} |
||||
ndev = buffer[0]; |
||||
bufferindex = 1; |
||||
for(i = 0; i < ndev; i++) |
||||
{ |
||||
DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER); |
||||
if(n<=0) { |
||||
if (error) |
||||
*error = MINISSDPC_INVALID_SERVER_REPLY; |
||||
return devlist; |
||||
} |
||||
#ifdef DEBUG |
||||
printf(" urlsize=%u", urlsize); |
||||
#endif /* DEBUG */ |
||||
url = malloc(urlsize); |
||||
if(url == NULL) { |
||||
if (error) |
||||
*error = MINISSDPC_MEMORY_ERROR; |
||||
return devlist; |
||||
} |
||||
READ_COPY_BUFFER(url, urlsize); |
||||
if(n<=0) { |
||||
if (error) |
||||
*error = MINISSDPC_INVALID_SERVER_REPLY; |
||||
goto free_url_and_return; |
||||
} |
||||
DECODELENGTH_READ(stsize, READ_BYTE_BUFFER); |
||||
if(n<=0) { |
||||
if (error) |
||||
*error = MINISSDPC_INVALID_SERVER_REPLY; |
||||
goto free_url_and_return; |
||||
} |
||||
#ifdef DEBUG |
||||
printf(" stsize=%u", stsize); |
||||
#endif /* DEBUG */ |
||||
st = malloc(stsize); |
||||
if (st == NULL) { |
||||
if (error) |
||||
*error = MINISSDPC_MEMORY_ERROR; |
||||
goto free_url_and_return; |
||||
} |
||||
READ_COPY_BUFFER(st, stsize); |
||||
if(n<=0) { |
||||
if (error) |
||||
*error = MINISSDPC_INVALID_SERVER_REPLY; |
||||
goto free_url_and_st_and_return; |
||||
} |
||||
DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER); |
||||
if(n<=0) { |
||||
if (error) |
||||
*error = MINISSDPC_INVALID_SERVER_REPLY; |
||||
goto free_url_and_st_and_return; |
||||
} |
||||
#ifdef DEBUG |
||||
printf(" usnsize=%u\n", usnsize); |
||||
#endif /* DEBUG */ |
||||
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize); |
||||
if(tmp == NULL) { |
||||
if (error) |
||||
*error = MINISSDPC_MEMORY_ERROR; |
||||
goto free_url_and_st_and_return; |
||||
} |
||||
tmp->pNext = devlist; |
||||
tmp->descURL = tmp->buffer; |
||||
tmp->st = tmp->buffer + 1 + urlsize; |
||||
memcpy(tmp->buffer, url, urlsize); |
||||
tmp->buffer[urlsize] = '\0'; |
||||
memcpy(tmp->st, st, stsize); |
||||
tmp->buffer[urlsize+1+stsize] = '\0'; |
||||
free(url); |
||||
free(st); |
||||
url = NULL; |
||||
st = NULL; |
||||
tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize; |
||||
READ_COPY_BUFFER(tmp->usn, usnsize); |
||||
if(n<=0) { |
||||
if (error) |
||||
*error = MINISSDPC_INVALID_SERVER_REPLY; |
||||
goto free_tmp_and_return; |
||||
} |
||||
tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0'; |
||||
tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */ |
||||
devlist = tmp; |
||||
} |
||||
if (error) |
||||
*error = MINISSDPC_SUCCESS; |
||||
return devlist; |
||||
|
||||
free_url_and_st_and_return: |
||||
free(st); |
||||
free_url_and_return: |
||||
free(url); |
||||
return devlist; |
||||
|
||||
free_tmp_and_return: |
||||
free(tmp); |
||||
return devlist; |
||||
} |
||||
|
||||
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */ |
||||
|
||||
/* parseMSEARCHReply()
|
||||
* the last 4 arguments are filled during the parsing : |
||||
* - location/locationsize : "location:" field of the SSDP reply packet |
||||
* - st/stsize : "st:" field of the SSDP reply packet. |
||||
* The strings are NOT null terminated */ |
||||
static void |
||||
parseMSEARCHReply(const char * reply, int size, |
||||
const char * * location, int * locationsize, |
||||
const char * * st, int * stsize, |
||||
const char * * usn, int * usnsize) |
||||
{ |
||||
int a, b, i; |
||||
i = 0; |
||||
a = i; /* start of the line */ |
||||
b = 0; /* end of the "header" (position of the colon) */ |
||||
while(i<size) |
||||
{ |
||||
switch(reply[i]) |
||||
{ |
||||
case ':': |
||||
if(b==0) |
||||
{ |
||||
b = i; /* end of the "header" */ |
||||
/*for(j=a; j<b; j++)
|
||||
{ |
||||
putchar(reply[j]); |
||||
} |
||||
*/ |
||||
} |
||||
break; |
||||
case '\x0a': |
||||
case '\x0d': |
||||
if(b!=0) |
||||
{ |
||||
/*for(j=b+1; j<i; j++)
|
||||
{ |
||||
putchar(reply[j]); |
||||
} |
||||
putchar('\n');*/ |
||||
/* skip the colon and white spaces */ |
||||
do { b++; } while(reply[b]==' '); |
||||
if(0==strncasecmp(reply+a, "location", 8)) |
||||
{ |
||||
*location = reply+b; |
||||
*locationsize = i-b; |
||||
} |
||||
else if(0==strncasecmp(reply+a, "st", 2)) |
||||
{ |
||||
*st = reply+b; |
||||
*stsize = i-b; |
||||
} |
||||
else if(0==strncasecmp(reply+a, "usn", 3)) |
||||
{ |
||||
*usn = reply+b; |
||||
*usnsize = i-b; |
||||
} |
||||
b = 0; |
||||
} |
||||
a = i+1; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
i++; |
||||
} |
||||
} |
||||
|
||||
/* port upnp discover : SSDP protocol */ |
||||
#define SSDP_PORT 1900 |
||||
#define XSTR(s) STR(s) |
||||
#define STR(s) #s |
||||
#define UPNP_MCAST_ADDR "239.255.255.250" |
||||
/* for IPv6 */ |
||||
#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */ |
||||
#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */ |
||||
|
||||
/* direct discovery if minissdpd responses are not sufficient */ |
||||
/* ssdpDiscoverDevices() :
|
||||
* return a chained list of all devices found or NULL if |
||||
* no devices was found. |
||||
* It is up to the caller to free the chained list |
||||
* delay is in millisecond (poll). |
||||
* UDA v1.1 says : |
||||
* The TTL for the IP packet SHOULD default to 2 and |
||||
* SHOULD be configurable. */ |
||||
struct UPNPDev * |
||||
ssdpDiscoverDevices(const char * const deviceTypes[], |
||||
int delay, const char * multicastif, |
||||
int localport, |
||||
int ipv6, unsigned char ttl, |
||||
int * error, |
||||
int searchalltypes) |
||||
{ |
||||
struct UPNPDev * tmp; |
||||
struct UPNPDev * devlist = 0; |
||||
unsigned int scope_id = 0; |
||||
int opt = 1; |
||||
static const char MSearchMsgFmt[] = |
||||
"M-SEARCH * HTTP/1.1\r\n" |
||||
"HOST: %s:" XSTR(SSDP_PORT) "\r\n" |
||||
"ST: %s\r\n" |
||||
"MAN: \"ssdp:discover\"\r\n" |
||||
"MX: %u\r\n" |
||||
"\r\n"; |
||||
int deviceIndex; |
||||
char bufr[1536]; /* reception and emission buffer */ |
||||
int sudp; |
||||
int n; |
||||
struct sockaddr_storage sockudp_r; |
||||
unsigned int mx; |
||||
#ifdef NO_GETADDRINFO |
||||
struct sockaddr_storage sockudp_w; |
||||
#else |
||||
int rv; |
||||
struct addrinfo hints, *servinfo, *p; |
||||
#endif |
||||
#ifdef _WIN32 |
||||
MIB_IPFORWARDROW ip_forward; |
||||
unsigned long _ttl = (unsigned long)ttl; |
||||
#endif |
||||
int linklocal = 1; |
||||
|
||||
if(error) |
||||
*error = MINISSDPC_UNKNOWN_ERROR; |
||||
|
||||
if(localport==UPNP_LOCAL_PORT_SAME) |
||||
localport = SSDP_PORT; |
||||
|
||||
#ifdef _WIN32 |
||||
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP); |
||||
#else |
||||
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0); |
||||
#endif |
||||
if(sudp < 0) |
||||
{ |
||||
if(error) |
||||
*error = MINISSDPC_SOCKET_ERROR; |
||||
PRINT_SOCKET_ERROR("socket"); |
||||
return NULL; |
||||
} |
||||
/* reception */ |
||||
memset(&sockudp_r, 0, sizeof(struct sockaddr_storage)); |
||||
if(ipv6) { |
||||
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r; |
||||
p->sin6_family = AF_INET6; |
||||
if(localport > 0 && localport < 65536) |
||||
p->sin6_port = htons((unsigned short)localport); |
||||
p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */ |
||||
} else { |
||||
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; |
||||
p->sin_family = AF_INET; |
||||
if(localport > 0 && localport < 65536) |
||||
p->sin_port = htons((unsigned short)localport); |
||||
p->sin_addr.s_addr = INADDR_ANY; |
||||
} |
||||
#ifdef _WIN32 |
||||
/* This code could help us to use the right Network interface for
|
||||
* SSDP multicast traffic */ |
||||
/* Get IP associated with the index given in the ip_forward struct
|
||||
* in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ |
||||
if(!ipv6 |
||||
&& (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) { |
||||
DWORD dwRetVal = 0; |
||||
PMIB_IPADDRTABLE pIPAddrTable; |
||||
DWORD dwSize = 0; |
||||
#ifdef DEBUG |
||||
IN_ADDR IPAddr; |
||||
#endif |
||||
int i; |
||||
#ifdef DEBUG |
||||
printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); |
||||
#endif |
||||
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); |
||||
if(pIPAddrTable) { |
||||
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { |
||||
free(pIPAddrTable); |
||||
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); |
||||
} |
||||
} |
||||
if(pIPAddrTable) { |
||||
dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); |
||||
if (dwRetVal == NO_ERROR) { |
||||
#ifdef DEBUG |
||||
printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); |
||||
#endif |
||||
for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { |
||||
#ifdef DEBUG |
||||
printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); |
||||
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; |
||||
printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); |
||||
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; |
||||
printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); |
||||
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; |
||||
printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); |
||||
printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); |
||||
printf("\tType and State[%d]:", i); |
||||
printf("\n"); |
||||
#endif |
||||
if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { |
||||
/* Set the address of this interface to be used */ |
||||
struct in_addr mc_if; |
||||
memset(&mc_if, 0, sizeof(mc_if)); |
||||
mc_if.s_addr = pIPAddrTable->table[i].dwAddr; |
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { |
||||
PRINT_SOCKET_ERROR("setsockopt"); |
||||
} |
||||
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; |
||||
#ifndef DEBUG |
||||
break; |
||||
#endif |
||||
} |
||||
} |
||||
} |
||||
free(pIPAddrTable); |
||||
pIPAddrTable = NULL; |
||||
} |
||||
} |
||||
#endif /* _WIN32 */ |
||||
|
||||
#ifdef _WIN32 |
||||
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) |
||||
#else |
||||
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) |
||||
#endif |
||||
{ |
||||
if(error) |
||||
*error = MINISSDPC_SOCKET_ERROR; |
||||
PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)"); |
||||
return NULL; |
||||
} |
||||
|
||||
#ifdef _WIN32 |
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0) |
||||
#else /* _WIN32 */ |
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) |
||||
#endif /* _WIN32 */ |
||||
{ |
||||
/* not a fatal error */ |
||||
PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)"); |
||||
} |
||||
|
||||
if(multicastif) |
||||
{ |
||||
if(ipv6) { |
||||
#if !defined(_WIN32) |
||||
/* according to MSDN, if_nametoindex() is supported since
|
||||
* MS Windows Vista and MS Windows Server 2008. |
||||
* http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
|
||||
unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ |
||||
if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) |
||||
{ |
||||
PRINT_SOCKET_ERROR("setsockopt"); |
||||
} |
||||
#else |
||||
#ifdef DEBUG |
||||
printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); |
||||
#endif |
||||
#endif |
||||
} else { |
||||
struct in_addr mc_if; |
||||
mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ |
||||
if(mc_if.s_addr != INADDR_NONE) |
||||
{ |
||||
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; |
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) |
||||
{ |
||||
PRINT_SOCKET_ERROR("setsockopt"); |
||||
} |
||||
} else { |
||||
#ifdef HAS_IP_MREQN |
||||
/* was not an ip address, try with an interface name */ |
||||
struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ |
||||
memset(&reqn, 0, sizeof(struct ip_mreqn)); |
||||
reqn.imr_ifindex = if_nametoindex(multicastif); |
||||
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) |
||||
{ |
||||
PRINT_SOCKET_ERROR("setsockopt"); |
||||
} |
||||
#else |
||||
#ifdef DEBUG |
||||
printf("Setting of multicast interface not supported with interface name.\n"); |
||||
#endif |
||||
#endif |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* Before sending the packed, we first "bind" in order to be able
|
||||
* to receive the response */ |
||||
if (bind(sudp, (const struct sockaddr *)&sockudp_r, |
||||
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) |
||||
{ |
||||
if(error) |
||||
*error = MINISSDPC_SOCKET_ERROR; |
||||
PRINT_SOCKET_ERROR("bind"); |
||||
closesocket(sudp); |
||||
return NULL; |
||||
} |
||||
|
||||
if(error) |
||||
*error = MINISSDPC_SUCCESS; |
||||
/* Calculating maximum response time in seconds */ |
||||
mx = ((unsigned int)delay) / 1000u; |
||||
if(mx == 0) { |
||||
mx = 1; |
||||
delay = 1000; |
||||
} |
||||
/* receiving SSDP response packet */ |
||||
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) { |
||||
/* sending the SSDP M-SEARCH packet */ |
||||
n = snprintf(bufr, sizeof(bufr), |
||||
MSearchMsgFmt, |
||||
ipv6 ? |
||||
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") |
||||
: UPNP_MCAST_ADDR, |
||||
deviceTypes[deviceIndex], mx); |
||||
if ((unsigned int)n >= sizeof(bufr)) { |
||||
if(error) |
||||
*error = MINISSDPC_MEMORY_ERROR; |
||||
goto error; |
||||
} |
||||
#ifdef DEBUG |
||||
/*printf("Sending %s", bufr);*/ |
||||
printf("Sending M-SEARCH request to %s with ST: %s\n", |
||||
ipv6 ? |
||||
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") |
||||
: UPNP_MCAST_ADDR, |
||||
deviceTypes[deviceIndex]); |
||||
#endif |
||||
#ifdef NO_GETADDRINFO |
||||
/* the following code is not using getaddrinfo */ |
||||
/* emission */ |
||||
memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); |
||||
if(ipv6) { |
||||
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; |
||||
p->sin6_family = AF_INET6; |
||||
p->sin6_port = htons(SSDP_PORT); |
||||
inet_pton(AF_INET6, |
||||
linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, |
||||
&(p->sin6_addr)); |
||||
} else { |
||||
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; |
||||
p->sin_family = AF_INET; |
||||
p->sin_port = htons(SSDP_PORT); |
||||
p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); |
||||
} |
||||
n = sendto(sudp, bufr, n, 0, &sockudp_w, |
||||
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); |
||||
if (n < 0) { |
||||
if(error) |
||||
*error = MINISSDPC_SOCKET_ERROR; |
||||
PRINT_SOCKET_ERROR("sendto"); |
||||
break; |
||||
} |
||||
#else /* #ifdef NO_GETADDRINFO */ |
||||
memset(&hints, 0, sizeof(hints)); |
||||
hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */ |
||||
hints.ai_socktype = SOCK_DGRAM; |
||||
/*hints.ai_flags = */ |
||||
if ((rv = getaddrinfo(ipv6 |
||||
? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) |
||||
: UPNP_MCAST_ADDR, |
||||
XSTR(SSDP_PORT), &hints, &servinfo)) != 0) { |
||||
if(error) |
||||
*error = MINISSDPC_SOCKET_ERROR; |
||||
#ifdef _WIN32 |
||||
fprintf(stderr, "getaddrinfo() failed: %d\n", rv); |
||||
#else |
||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); |
||||
#endif |
||||
break; |
||||
} |
||||
for(p = servinfo; p; p = p->ai_next) { |
||||
n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); |
||||
if (n < 0) { |
||||
#ifdef DEBUG |
||||
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; |
||||
if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, |
||||
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { |
||||
fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); |
||||
} |
||||
#endif |
||||
PRINT_SOCKET_ERROR("sendto"); |
||||
continue; |
||||
} |
||||
} |
||||
freeaddrinfo(servinfo); |
||||
if(n < 0) { |
||||
if(error) |
||||
*error = MINISSDPC_SOCKET_ERROR; |
||||
break; |
||||
} |
||||
#endif /* #ifdef NO_GETADDRINFO */ |
||||
/* Waiting for SSDP REPLY packet to M-SEARCH
|
||||
* if searchalltypes is set, enter the loop only |
||||
* when the last deviceType is reached */ |
||||
if(!searchalltypes || !deviceTypes[deviceIndex + 1]) do { |
||||
n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id); |
||||
if (n < 0) { |
||||
/* error */ |
||||
if(error) |
||||
*error = MINISSDPC_SOCKET_ERROR; |
||||
goto error; |
||||
} else if (n == 0) { |
||||
/* no data or Time Out */ |
||||
#ifdef DEBUG |
||||
printf("NODATA or TIMEOUT\n"); |
||||
#endif /* DEBUG */ |
||||
if (devlist && !searchalltypes) { |
||||
/* found some devices, stop now*/ |
||||
if(error) |
||||
*error = MINISSDPC_SUCCESS; |
||||
goto error; |
||||
} |
||||
} else { |
||||
const char * descURL=NULL; |
||||
int urlsize=0; |
||||
const char * st=NULL; |
||||
int stsize=0; |
||||
const char * usn=NULL; |
||||
int usnsize=0; |
||||
parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize); |
||||
if(st&&descURL) { |
||||
#ifdef DEBUG |
||||
printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n", |
||||
stsize, st, usnsize, (usn?usn:""), urlsize, descURL); |
||||
#endif /* DEBUG */ |
||||
for(tmp=devlist; tmp; tmp = tmp->pNext) { |
||||
if(memcmp(tmp->descURL, descURL, urlsize) == 0 && |
||||
tmp->descURL[urlsize] == '\0' && |
||||
memcmp(tmp->st, st, stsize) == 0 && |
||||
tmp->st[stsize] == '\0' && |
||||
(usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) && |
||||
tmp->usn[usnsize] == '\0') |
||||
break; |
||||
} |
||||
/* at the exit of the loop above, tmp is null if
|
||||
* no duplicate device was found */ |
||||
if(tmp) |
||||
continue; |
||||
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize); |
||||
if(!tmp) { |
||||
/* memory allocation error */ |
||||
if(error) |
||||
*error = MINISSDPC_MEMORY_ERROR; |
||||
goto error; |
||||
} |
||||
tmp->pNext = devlist; |
||||
tmp->descURL = tmp->buffer; |
||||
tmp->st = tmp->buffer + 1 + urlsize; |
||||
tmp->usn = tmp->st + 1 + stsize; |
||||
memcpy(tmp->buffer, descURL, urlsize); |
||||
tmp->buffer[urlsize] = '\0'; |
||||
memcpy(tmp->st, st, stsize); |
||||
tmp->buffer[urlsize+1+stsize] = '\0'; |
||||
if(usn != NULL) |
||||
memcpy(tmp->usn, usn, usnsize); |
||||
tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0'; |
||||
tmp->scope_id = scope_id; |
||||
devlist = tmp; |
||||
} |
||||
} |
||||
} while(n > 0); |
||||
if(ipv6) { |
||||
/* switch linklocal flag */ |
||||
if(linklocal) { |
||||
linklocal = 0; |
||||
--deviceIndex; |
||||
} else { |
||||
linklocal = 1; |
||||
} |
||||
} |
||||
} |
||||
error: |
||||
closesocket(sudp); |
||||
return devlist; |
||||
} |
||||
|
||||
@ -0,0 +1,58 @@
|
||||
/* $Id: minissdpc.h,v 1.7 2015/10/08 16:15:47 nanard Exp $ */ |
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard |
||||
* Copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subjects to the conditions detailed |
||||
* in the LICENCE file provided within this distribution */ |
||||
#ifndef MINISSDPC_H_INCLUDED |
||||
#define MINISSDPC_H_INCLUDED |
||||
|
||||
#include "miniupnpc_declspec.h" |
||||
#include "upnpdev.h" |
||||
|
||||
/* error codes : */ |
||||
#define MINISSDPC_SUCCESS (0) |
||||
#define MINISSDPC_UNKNOWN_ERROR (-1) |
||||
#define MINISSDPC_SOCKET_ERROR (-101) |
||||
#define MINISSDPC_MEMORY_ERROR (-102) |
||||
#define MINISSDPC_INVALID_INPUT (-103) |
||||
#define MINISSDPC_INVALID_SERVER_REPLY (-104) |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) |
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev * |
||||
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error); |
||||
|
||||
MINIUPNP_LIBSPEC int |
||||
connectToMiniSSDPD(const char * socketpath); |
||||
|
||||
MINIUPNP_LIBSPEC int |
||||
disconnectFromMiniSSDPD(int fd); |
||||
|
||||
MINIUPNP_LIBSPEC int |
||||
requestDevicesFromMiniSSDPD(int fd, const char * devtype); |
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev * |
||||
receiveDevicesFromMiniSSDPD(int fd, int * error); |
||||
|
||||
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */ |
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev * |
||||
ssdpDiscoverDevices(const char * const deviceTypes[], |
||||
int delay, const char * multicastif, |
||||
int localport, |
||||
int ipv6, unsigned char ttl, |
||||
int * error, |
||||
int searchalltypes); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
||||
|
||||
@ -0,0 +1,684 @@
|
||||
/* $Id: miniupnpc.c,v 1.141 2015/10/26 17:05:07 nanard Exp $ */ |
||||
/* vim: tabstop=4 shiftwidth=4 noexpandtab */ |
||||
/* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD |
||||
* copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subjet to the conditions detailed in the |
||||
* provided LICENSE file. */ |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#ifdef _WIN32 |
||||
/* Win32 Specific includes and defines */ |
||||
#include <winsock2.h> |
||||
#include <ws2tcpip.h> |
||||
#include <io.h> |
||||
#include <iphlpapi.h> |
||||
#define snprintf _snprintf |
||||
#define strdup _strdup |
||||
#ifndef strncasecmp |
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400) |
||||
#define strncasecmp _memicmp |
||||
#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ |
||||
#define strncasecmp memicmp |
||||
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ |
||||
#endif /* #ifndef strncasecmp */ |
||||
#define MAXHOSTNAMELEN 64 |
||||
#else /* #ifdef _WIN32 */ |
||||
/* Standard POSIX includes */ |
||||
#include <unistd.h> |
||||
#if defined(__amigaos__) && !defined(__amigaos4__) |
||||
/* Amiga OS 3 specific stuff */ |
||||
#define socklen_t int |
||||
#else |
||||
#include <sys/select.h> |
||||
#endif |
||||
#include <sys/socket.h> |
||||
#include <sys/types.h> |
||||
#include <sys/param.h> |
||||
#include <netinet/in.h> |
||||
#include <arpa/inet.h> |
||||
#include <netdb.h> |
||||
#include <net/if.h> |
||||
#if !defined(__amigaos__) && !defined(__amigaos4__) |
||||
#include <poll.h> |
||||
#endif |
||||
#include <strings.h> |
||||
#include <errno.h> |
||||
#define closesocket close |
||||
#endif /* #else _WIN32 */ |
||||
#ifdef __GNU__ |
||||
#define MAXHOSTNAMELEN 64 |
||||
#endif |
||||
|
||||
|
||||
#include "miniupnpc.h" |
||||
#include "minissdpc.h" |
||||
#include "miniwget.h" |
||||
#include "minisoap.h" |
||||
#include "minixml.h" |
||||
#include "upnpcommands.h" |
||||
#include "connecthostport.h" |
||||
|
||||
/* compare the begining of a string with a constant string */ |
||||
#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) |
||||
|
||||
#ifndef MAXHOSTNAMELEN |
||||
#define MAXHOSTNAMELEN 64 |
||||
#endif |
||||
|
||||
#define SOAPPREFIX "s" |
||||
#define SERVICEPREFIX "u" |
||||
#define SERVICEPREFIX2 'u' |
||||
|
||||
/* root description parsing */ |
||||
MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data) |
||||
{ |
||||
struct xmlparser parser; |
||||
/* xmlparser object */ |
||||
parser.xmlstart = buffer; |
||||
parser.xmlsize = bufsize; |
||||
parser.data = data; |
||||
parser.starteltfunc = IGDstartelt; |
||||
parser.endeltfunc = IGDendelt; |
||||
parser.datafunc = IGDdata; |
||||
parser.attfunc = 0; |
||||
parsexml(&parser); |
||||
#ifdef DEBUG |
||||
printIGD(data); |
||||
#endif |
||||
} |
||||
|
||||
/* simpleUPnPcommand2 :
|
||||
* not so simple ! |
||||
* return values : |
||||
* pointer - OK |
||||
* NULL - error */ |
||||
char * simpleUPnPcommand2(int s, const char * url, const char * service, |
||||
const char * action, struct UPNParg * args, |
||||
int * bufsize, const char * httpversion) |
||||
{ |
||||
char hostname[MAXHOSTNAMELEN+1]; |
||||
unsigned short port = 0; |
||||
char * path; |
||||
char soapact[128]; |
||||
char soapbody[2048]; |
||||
int soapbodylen; |
||||
char * buf; |
||||
int n; |
||||
|
||||
*bufsize = 0; |
||||
snprintf(soapact, sizeof(soapact), "%s#%s", service, action); |
||||
if(args==NULL) |
||||
{ |
||||
soapbodylen = snprintf(soapbody, sizeof(soapbody), |
||||
"<?xml version=\"1.0\"?>\r\n" |
||||
"<" SOAPPREFIX ":Envelope " |
||||
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " |
||||
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" |
||||
"<" SOAPPREFIX ":Body>" |
||||
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" |
||||
"</" SERVICEPREFIX ":%s>" |
||||
"</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>" |
||||
"\r\n", action, service, action); |
||||
if ((unsigned int)soapbodylen >= sizeof(soapbody)) |
||||
return NULL; |
||||
} |
||||
else |
||||
{ |
||||
char * p; |
||||
const char * pe, * pv; |
||||
const char * const pend = soapbody + sizeof(soapbody); |
||||
soapbodylen = snprintf(soapbody, sizeof(soapbody), |
||||
"<?xml version=\"1.0\"?>\r\n" |
||||
"<" SOAPPREFIX ":Envelope " |
||||
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " |
||||
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" |
||||
"<" SOAPPREFIX ":Body>" |
||||
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", |
||||
action, service); |
||||
if ((unsigned int)soapbodylen >= sizeof(soapbody)) |
||||
return NULL; |
||||
p = soapbody + soapbodylen; |
||||
while(args->elt) |
||||
{ |
||||
if(p >= pend) /* check for space to write next byte */ |
||||
return NULL; |
||||
*(p++) = '<'; |
||||
|
||||
pe = args->elt; |
||||
while(p < pend && *pe) |
||||
*(p++) = *(pe++); |
||||
|
||||
if(p >= pend) /* check for space to write next byte */ |
||||
return NULL; |
||||
*(p++) = '>'; |
||||
|
||||
if((pv = args->val)) |
||||
{ |
||||
while(p < pend && *pv) |
||||
*(p++) = *(pv++); |
||||
} |
||||
|
||||
if((p+2) > pend) /* check for space to write next 2 bytes */ |
||||
return NULL; |
||||
*(p++) = '<'; |
||||
*(p++) = '/'; |
||||
|
||||
pe = args->elt; |
||||
while(p < pend && *pe) |
||||
*(p++) = *(pe++); |
||||
|
||||
if(p >= pend) /* check for space to write next byte */ |
||||
return NULL; |
||||
*(p++) = '>'; |
||||
|
||||
args++; |
||||
} |
||||
if((p+4) > pend) /* check for space to write next 4 bytes */ |
||||
return NULL; |
||||
*(p++) = '<'; |
||||
*(p++) = '/'; |
||||
*(p++) = SERVICEPREFIX2; |
||||
*(p++) = ':'; |
||||
|
||||
pe = action; |
||||
while(p < pend && *pe) |
||||
*(p++) = *(pe++); |
||||
|
||||
strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n", |
||||
pend - p); |
||||
if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */ |
||||
return NULL; |
||||
} |
||||
if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; |
||||
if(s < 0) { |
||||
s = connecthostport(hostname, port, 0); |
||||
if(s < 0) { |
||||
/* failed to connect */ |
||||
return NULL; |
||||
} |
||||
} |
||||
|
||||
n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); |
||||
if(n<=0) { |
||||
#ifdef DEBUG |
||||
printf("Error sending SOAP request\n"); |
||||
#endif |
||||
closesocket(s); |
||||
return NULL; |
||||
} |
||||
|
||||
buf = getHTTPResponse(s, bufsize); |
||||
#ifdef DEBUG |
||||
if(*bufsize > 0 && buf) |
||||
{ |
||||
printf("SOAP Response :\n%.*s\n", *bufsize, buf); |
||||
} |
||||
#endif |
||||
closesocket(s); |
||||
return buf; |
||||
} |
||||
|
||||
/* simpleUPnPcommand :
|
||||
* not so simple ! |
||||
* return values : |
||||
* pointer - OK |
||||
* NULL - error */ |
||||
char * simpleUPnPcommand(int s, const char * url, const char * service, |
||||
const char * action, struct UPNParg * args, |
||||
int * bufsize) |
||||
{ |
||||
char * buf; |
||||
|
||||
#if 1 |
||||
buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); |
||||
#else |
||||
buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0"); |
||||
if (!buf || *bufsize == 0) |
||||
{ |
||||
#if DEBUG |
||||
printf("Error or no result from SOAP request; retrying with HTTP/1.1\n"); |
||||
#endif |
||||
buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); |
||||
} |
||||
#endif |
||||
return buf; |
||||
} |
||||
|
||||
/* upnpDiscoverDevices() :
|
||||
* return a chained list of all devices found or NULL if |
||||
* no devices was found. |
||||
* It is up to the caller to free the chained list |
||||
* delay is in millisecond (poll). |
||||
* UDA v1.1 says : |
||||
* The TTL for the IP packet SHOULD default to 2 and |
||||
* SHOULD be configurable. */ |
||||
MINIUPNP_LIBSPEC struct UPNPDev * |
||||
upnpDiscoverDevices(const char * const deviceTypes[], |
||||
int delay, const char * multicastif, |
||||
const char * minissdpdsock, int localport, |
||||
int ipv6, unsigned char ttl, |
||||
int * error, |
||||
int searchalltypes) |
||||
{ |
||||
struct UPNPDev * tmp; |
||||
struct UPNPDev * devlist = 0; |
||||
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) |
||||
int deviceIndex; |
||||
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ |
||||
|
||||
if(error) |
||||
*error = UPNPDISCOVER_UNKNOWN_ERROR; |
||||
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) |
||||
/* first try to get infos from minissdpd ! */ |
||||
if(!minissdpdsock) |
||||
minissdpdsock = "/var/run/minissdpd.sock"; |
||||
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) { |
||||
struct UPNPDev * minissdpd_devlist; |
||||
int only_rootdevice = 1; |
||||
minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex], |
||||
minissdpdsock, 0); |
||||
if(minissdpd_devlist) { |
||||
#ifdef DEBUG |
||||
printf("returned by MiniSSDPD: %s\t%s\n", |
||||
minissdpd_devlist->st, minissdpd_devlist->descURL); |
||||
#endif /* DEBUG */ |
||||
if(!strstr(minissdpd_devlist->st, "rootdevice")) |
||||
only_rootdevice = 0; |
||||
for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) { |
||||
#ifdef DEBUG |
||||
printf("returned by MiniSSDPD: %s\t%s\n", |
||||
tmp->pNext->st, tmp->pNext->descURL); |
||||
#endif /* DEBUG */ |
||||
if(!strstr(tmp->st, "rootdevice")) |
||||
only_rootdevice = 0; |
||||
} |
||||
tmp->pNext = devlist; |
||||
devlist = minissdpd_devlist; |
||||
if(!searchalltypes && !only_rootdevice) |
||||
break; |
||||
} |
||||
} |
||||
for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) { |
||||
/* We return what we have found if it was not only a rootdevice */ |
||||
if(!strstr(tmp->st, "rootdevice")) { |
||||
if(error) |
||||
*error = UPNPDISCOVER_SUCCESS; |
||||
return devlist; |
||||
} |
||||
} |
||||
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ |
||||
|
||||
/* direct discovery if minissdpd responses are not sufficient */ |
||||
{ |
||||
struct UPNPDev * discovered_devlist; |
||||
discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport, |
||||
ipv6, ttl, error, searchalltypes); |
||||
if(devlist == NULL) |
||||
devlist = discovered_devlist; |
||||
else { |
||||
for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext); |
||||
tmp->pNext = discovered_devlist; |
||||
} |
||||
} |
||||
return devlist; |
||||
} |
||||
|
||||
/* upnpDiscover() Discover IGD device */ |
||||
MINIUPNP_LIBSPEC struct UPNPDev * |
||||
upnpDiscover(int delay, const char * multicastif, |
||||
const char * minissdpdsock, int localport, |
||||
int ipv6, unsigned char ttl, |
||||
int * error) |
||||
{ |
||||
static const char * const deviceList[] = { |
||||
#if 0 |
||||
"urn:schemas-upnp-org:device:InternetGatewayDevice:2", |
||||
"urn:schemas-upnp-org:service:WANIPConnection:2", |
||||
#endif |
||||
"urn:schemas-upnp-org:device:InternetGatewayDevice:1", |
||||
"urn:schemas-upnp-org:service:WANIPConnection:1", |
||||
"urn:schemas-upnp-org:service:WANPPPConnection:1", |
||||
"upnp:rootdevice", |
||||
/*"ssdp:all",*/ |
||||
0 |
||||
}; |
||||
return upnpDiscoverDevices(deviceList, |
||||
delay, multicastif, minissdpdsock, localport, |
||||
ipv6, ttl, error, 0); |
||||
} |
||||
|
||||
/* upnpDiscoverAll() Discover all UPnP devices */ |
||||
MINIUPNP_LIBSPEC struct UPNPDev * |
||||
upnpDiscoverAll(int delay, const char * multicastif, |
||||
const char * minissdpdsock, int localport, |
||||
int ipv6, unsigned char ttl, |
||||
int * error) |
||||
{ |
||||
static const char * const deviceList[] = { |
||||
/*"upnp:rootdevice",*/ |
||||
"ssdp:all", |
||||
0 |
||||
}; |
||||
return upnpDiscoverDevices(deviceList, |
||||
delay, multicastif, minissdpdsock, localport, |
||||
ipv6, ttl, error, 0); |
||||
} |
||||
|
||||
/* upnpDiscoverDevice() Discover a specific device */ |
||||
MINIUPNP_LIBSPEC struct UPNPDev * |
||||
upnpDiscoverDevice(const char * device, int delay, const char * multicastif, |
||||
const char * minissdpdsock, int localport, |
||||
int ipv6, unsigned char ttl, |
||||
int * error) |
||||
{ |
||||
const char * const deviceList[] = { |
||||
device, |
||||
0 |
||||
}; |
||||
return upnpDiscoverDevices(deviceList, |
||||
delay, multicastif, minissdpdsock, localport, |
||||
ipv6, ttl, error, 0); |
||||
} |
||||
|
||||
static char * |
||||
build_absolute_url(const char * baseurl, const char * descURL, |
||||
const char * url, unsigned int scope_id) |
||||
{ |
||||
int l, n; |
||||
char * s; |
||||
const char * base; |
||||
char * p; |
||||
#if defined(IF_NAMESIZE) && !defined(_WIN32) |
||||
char ifname[IF_NAMESIZE]; |
||||
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ |
||||
char scope_str[8]; |
||||
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ |
||||
|
||||
if( (url[0] == 'h') |
||||
&&(url[1] == 't') |
||||
&&(url[2] == 't') |
||||
&&(url[3] == 'p') |
||||
&&(url[4] == ':') |
||||
&&(url[5] == '/') |
||||
&&(url[6] == '/')) |
||||
return strdup(url); |
||||
base = (baseurl[0] == '\0') ? descURL : baseurl; |
||||
n = strlen(base); |
||||
if(n > 7) { |
||||
p = strchr(base + 7, '/'); |
||||
if(p) |
||||
n = p - base; |
||||
} |
||||
l = n + strlen(url) + 1; |
||||
if(url[0] != '/') |
||||
l++; |
||||
if(scope_id != 0) { |
||||
#if defined(IF_NAMESIZE) && !defined(_WIN32) |
||||
if(if_indextoname(scope_id, ifname)) { |
||||
l += 3 + strlen(ifname); /* 3 == strlen(%25) */ |
||||
} |
||||
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ |
||||
/* under windows, scope is numerical */ |
||||
l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id); |
||||
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ |
||||
} |
||||
s = malloc(l); |
||||
if(s == NULL) return NULL; |
||||
memcpy(s, base, n); |
||||
if(scope_id != 0) { |
||||
s[n] = '\0'; |
||||
if(0 == memcmp(s, "http://[fe80:", 13)) { |
||||
/* this is a linklocal IPv6 address */ |
||||
p = strchr(s, ']'); |
||||
if(p) { |
||||
/* insert %25<scope> into URL */ |
||||
#if defined(IF_NAMESIZE) && !defined(_WIN32) |
||||
memmove(p + 3 + strlen(ifname), p, strlen(p) + 1); |
||||
memcpy(p, "%25", 3); |
||||
memcpy(p + 3, ifname, strlen(ifname)); |
||||
n += 3 + strlen(ifname); |
||||
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ |
||||
memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1); |
||||
memcpy(p, "%25", 3); |
||||
memcpy(p + 3, scope_str, strlen(scope_str)); |
||||
n += 3 + strlen(scope_str); |
||||
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ |
||||
} |
||||
} |
||||
} |
||||
if(url[0] != '/') |
||||
s[n++] = '/'; |
||||
memcpy(s + n, url, l - n); |
||||
return s; |
||||
} |
||||
|
||||
/* Prepare the Urls for usage...
|
||||
*/ |
||||
MINIUPNP_LIBSPEC void |
||||
GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, |
||||
const char * descURL, unsigned int scope_id) |
||||
{ |
||||
/* strdup descURL */ |
||||
urls->rootdescURL = strdup(descURL); |
||||
|
||||
/* get description of WANIPConnection */ |
||||
urls->ipcondescURL = build_absolute_url(data->urlbase, descURL, |
||||
data->first.scpdurl, scope_id); |
||||
urls->controlURL = build_absolute_url(data->urlbase, descURL, |
||||
data->first.controlurl, scope_id); |
||||
urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL, |
||||
data->CIF.controlurl, scope_id); |
||||
urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL, |
||||
data->IPv6FC.controlurl, scope_id); |
||||
|
||||
#ifdef DEBUG |
||||
printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL); |
||||
printf("urls->controlURL='%s'\n", urls->controlURL); |
||||
printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF); |
||||
printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC); |
||||
#endif |
||||
} |
||||
|
||||
MINIUPNP_LIBSPEC void |
||||
FreeUPNPUrls(struct UPNPUrls * urls) |
||||
{ |
||||
if(!urls) |
||||
return; |
||||
free(urls->controlURL); |
||||
urls->controlURL = 0; |
||||
free(urls->ipcondescURL); |
||||
urls->ipcondescURL = 0; |
||||
free(urls->controlURL_CIF); |
||||
urls->controlURL_CIF = 0; |
||||
free(urls->controlURL_6FC); |
||||
urls->controlURL_6FC = 0; |
||||
free(urls->rootdescURL); |
||||
urls->rootdescURL = 0; |
||||
} |
||||
|
||||
int |
||||
UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) |
||||
{ |
||||
char status[64]; |
||||
unsigned int uptime; |
||||
status[0] = '\0'; |
||||
UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, |
||||
status, &uptime, NULL); |
||||
if(0 == strcmp("Connected", status)) |
||||
return 1; |
||||
else if(0 == strcmp("Up", status)) /* Also accept "Up" */ |
||||
return 1; |
||||
else |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/* UPNP_GetValidIGD() :
|
||||
* return values : |
||||
* -1 = Internal error |
||||
* 0 = NO IGD found |
||||
* 1 = A valid connected IGD has been found |
||||
* 2 = A valid IGD has been found but it reported as |
||||
* not connected |
||||
* 3 = an UPnP device has been found but was not recognized as an IGD |
||||
* |
||||
* In any positive non zero return case, the urls and data structures |
||||
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to |
||||
* free allocated memory. |
||||
*/ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetValidIGD(struct UPNPDev * devlist, |
||||
struct UPNPUrls * urls, |
||||
struct IGDdatas * data, |
||||
char * lanaddr, int lanaddrlen) |
||||
{ |
||||
struct xml_desc { |
||||
char * xml; |
||||
int size; |
||||
int is_igd; |
||||
} * desc = NULL; |
||||
struct UPNPDev * dev; |
||||
int ndev = 0; |
||||
int i; |
||||
int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ |
||||
int n_igd = 0; |
||||
char extIpAddr[16]; |
||||
if(!devlist) |
||||
{ |
||||
#ifdef DEBUG |
||||
printf("Empty devlist\n"); |
||||
#endif |
||||
return 0; |
||||
} |
||||
/* counting total number of devices in the list */ |
||||
for(dev = devlist; dev; dev = dev->pNext) |
||||
ndev++; |
||||
if(ndev > 0) |
||||
{ |
||||
desc = calloc(ndev, sizeof(struct xml_desc)); |
||||
if(!desc) |
||||
return -1; /* memory allocation error */ |
||||
} |
||||
/* Step 1 : downloading descriptions and testing type */ |
||||
for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) |
||||
{ |
||||
/* we should choose an internet gateway device.
|
||||
* with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ |
||||
desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), |
||||
lanaddr, lanaddrlen, |
||||
dev->scope_id); |
||||
#ifdef DEBUG |
||||
if(!desc[i].xml) |
||||
{ |
||||
printf("error getting XML description %s\n", dev->descURL); |
||||
} |
||||
#endif |
||||
if(desc[i].xml) |
||||
{ |
||||
memset(data, 0, sizeof(struct IGDdatas)); |
||||
memset(urls, 0, sizeof(struct UPNPUrls)); |
||||
parserootdesc(desc[i].xml, desc[i].size, data); |
||||
if(COMPARE(data->CIF.servicetype, |
||||
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) |
||||
{ |
||||
desc[i].is_igd = 1; |
||||
n_igd++; |
||||
} |
||||
} |
||||
} |
||||
/* iterate the list to find a device depending on state */ |
||||
for(state = 1; state <= 3; state++) |
||||
{ |
||||
for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) |
||||
{ |
||||
if(desc[i].xml) |
||||
{ |
||||
memset(data, 0, sizeof(struct IGDdatas)); |
||||
memset(urls, 0, sizeof(struct UPNPUrls)); |
||||
parserootdesc(desc[i].xml, desc[i].size, data); |
||||
if(desc[i].is_igd || state >= 3 ) |
||||
{ |
||||
GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); |
||||
|
||||
/* in state 2 and 3 we dont test if device is connected ! */ |
||||
if(state >= 2) |
||||
goto free_and_return; |
||||
#ifdef DEBUG |
||||
printf("UPNPIGD_IsConnected(%s) = %d\n", |
||||
urls->controlURL, |
||||
UPNPIGD_IsConnected(urls, data)); |
||||
#endif |
||||
/* checks that status is connected AND there is a external IP address assigned */ |
||||
if(UPNPIGD_IsConnected(urls, data) |
||||
&& (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) |
||||
goto free_and_return; |
||||
FreeUPNPUrls(urls); |
||||
if(data->second.servicetype[0] != '\0') { |
||||
#ifdef DEBUG |
||||
printf("We tried %s, now we try %s !\n", |
||||
data->first.servicetype, data->second.servicetype); |
||||
#endif |
||||
/* swaping WANPPPConnection and WANIPConnection ! */ |
||||
memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); |
||||
memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); |
||||
memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); |
||||
GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); |
||||
#ifdef DEBUG |
||||
printf("UPNPIGD_IsConnected(%s) = %d\n", |
||||
urls->controlURL, |
||||
UPNPIGD_IsConnected(urls, data)); |
||||
#endif |
||||
if(UPNPIGD_IsConnected(urls, data) |
||||
&& (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) |
||||
goto free_and_return; |
||||
FreeUPNPUrls(urls); |
||||
} |
||||
} |
||||
memset(data, 0, sizeof(struct IGDdatas)); |
||||
} |
||||
} |
||||
} |
||||
state = 0; |
||||
free_and_return: |
||||
if(desc) { |
||||
for(i = 0; i < ndev; i++) { |
||||
if(desc[i].xml) { |
||||
free(desc[i].xml); |
||||
} |
||||
} |
||||
free(desc); |
||||
} |
||||
return state; |
||||
} |
||||
|
||||
/* UPNP_GetIGDFromUrl()
|
||||
* Used when skipping the discovery process. |
||||
* return value : |
||||
* 0 - Not ok |
||||
* 1 - OK */ |
||||
int |
||||
UPNP_GetIGDFromUrl(const char * rootdescurl, |
||||
struct UPNPUrls * urls, |
||||
struct IGDdatas * data, |
||||
char * lanaddr, int lanaddrlen) |
||||
{ |
||||
char * descXML; |
||||
int descXMLsize = 0; |
||||
descXML = miniwget_getaddr(rootdescurl, &descXMLsize, |
||||
lanaddr, lanaddrlen, 0); |
||||
if(descXML) { |
||||
memset(data, 0, sizeof(struct IGDdatas)); |
||||
memset(urls, 0, sizeof(struct UPNPUrls)); |
||||
parserootdesc(descXML, descXMLsize, data); |
||||
free(descXML); |
||||
descXML = NULL; |
||||
GetUPNPUrls(urls, data, rootdescurl, 0); |
||||
return 1; |
||||
} else { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,45 @@
|
||||
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_AddAnyPortMapping |
||||
UPNP_DeletePortMapping |
||||
UPNP_DeletePortMappingRange |
||||
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,152 @@
|
||||
/* $Id: miniupnpc.h,v 1.48 2015/10/08 16:19:40 nanard Exp $ */ |
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author: Thomas Bernard |
||||
* Copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subjects to the conditions detailed |
||||
* in the LICENCE file provided within this distribution */ |
||||
#ifndef MINIUPNPC_H_INCLUDED |
||||
#define MINIUPNPC_H_INCLUDED |
||||
|
||||
#include "miniupnpc_declspec.h" |
||||
#include "igd_desc_parse.h" |
||||
#include "upnpdev.h" |
||||
|
||||
/* error codes : */ |
||||
#define UPNPDISCOVER_SUCCESS (0) |
||||
#define UPNPDISCOVER_UNKNOWN_ERROR (-1) |
||||
#define UPNPDISCOVER_SOCKET_ERROR (-101) |
||||
#define UPNPDISCOVER_MEMORY_ERROR (-102) |
||||
|
||||
/* versions : */ |
||||
#define MINIUPNPC_VERSION "1.9.20151026" |
||||
#define MINIUPNPC_API_VERSION 15 |
||||
|
||||
/* Source port:
|
||||
Using "1" as an alias for 1900 for backwards compatability |
||||
(presuming one would have used that for the "sameport" parameter) */ |
||||
#define UPNP_LOCAL_PORT_ANY 0 |
||||
#define UPNP_LOCAL_PORT_SAME 1 |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/* Structures definitions : */ |
||||
struct UPNParg { const char * elt; const char * val; }; |
||||
|
||||
char * |
||||
simpleUPnPcommand(int, const char *, const char *, |
||||
const char *, struct UPNParg *, |
||||
int *); |
||||
|
||||
/* 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 localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent |
||||
* from the source port 1900 (same as destination port), if set to |
||||
* UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will |
||||
* be attempted as the source port. |
||||
* "searchalltypes" parameter is useful when searching several types, |
||||
* if 0, the discovery will stop with the first type returning results. |
||||
* TTL should default to 2. */ |
||||
MINIUPNP_LIBSPEC struct UPNPDev * |
||||
upnpDiscover(int delay, const char * multicastif, |
||||
const char * minissdpdsock, int localport, |
||||
int ipv6, unsigned char ttl, |
||||
int * error); |
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev * |
||||
upnpDiscoverAll(int delay, const char * multicastif, |
||||
const char * minissdpdsock, int localport, |
||||
int ipv6, unsigned char ttl, |
||||
int * error); |
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev * |
||||
upnpDiscoverDevice(const char * device, int delay, const char * multicastif, |
||||
const char * minissdpdsock, int localport, |
||||
int ipv6, unsigned char ttl, |
||||
int * error); |
||||
|
||||
MINIUPNP_LIBSPEC struct UPNPDev * |
||||
upnpDiscoverDevices(const char * const deviceTypes[], |
||||
int delay, const char * multicastif, |
||||
const char * minissdpdsock, int localport, |
||||
int ipv6, unsigned char ttl, |
||||
int * error, |
||||
int searchalltypes); |
||||
|
||||
/* parserootdesc() :
|
||||
* parse root XML description of a UPnP device and fill the IGDdatas |
||||
* structure. */ |
||||
MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); |
||||
|
||||
/* structure used to get fast access to urls
|
||||
* controlURL: controlURL of the WANIPConnection |
||||
* ipcondescURL: url of the description of the WANIPConnection |
||||
* controlURL_CIF: controlURL of the WANCommonInterfaceConfig |
||||
* controlURL_6FC: controlURL of the WANIPv6FirewallControl |
||||
*/ |
||||
struct UPNPUrls { |
||||
char * controlURL; |
||||
char * ipcondescURL; |
||||
char * controlURL_CIF; |
||||
char * controlURL_6FC; |
||||
char * rootdescURL; |
||||
}; |
||||
|
||||
/* UPNP_GetValidIGD() :
|
||||
* return values : |
||||
* 0 = NO IGD found |
||||
* 1 = A valid connected IGD has been found |
||||
* 2 = A valid IGD has been found but it reported as |
||||
* not connected |
||||
* 3 = an UPnP device has been found but was not recognized as an IGD |
||||
* |
||||
* In any non zero return case, the urls and data structures |
||||
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to |
||||
* free allocated memory. |
||||
*/ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetValidIGD(struct UPNPDev * devlist, |
||||
struct UPNPUrls * urls, |
||||
struct IGDdatas * data, |
||||
char * lanaddr, int lanaddrlen); |
||||
|
||||
/* UPNP_GetIGDFromUrl()
|
||||
* Used when skipping the discovery process. |
||||
* When succeding, urls, data, and lanaddr arguments are set. |
||||
* return value : |
||||
* 0 - Not ok |
||||
* 1 - OK */ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetIGDFromUrl(const char * rootdescurl, |
||||
struct UPNPUrls * urls, |
||||
struct IGDdatas * data, |
||||
char * lanaddr, int lanaddrlen); |
||||
|
||||
MINIUPNP_LIBSPEC void |
||||
GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, |
||||
const char *, unsigned int); |
||||
|
||||
MINIUPNP_LIBSPEC void |
||||
FreeUPNPUrls(struct UPNPUrls *); |
||||
|
||||
/* return 0 or 1 */ |
||||
MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); |
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
||||
|
||||
@ -0,0 +1,21 @@
|
||||
#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED |
||||
#define MINIUPNPC_DECLSPEC_H_INCLUDED |
||||
|
||||
#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB) |
||||
/* for windows dll */ |
||||
#ifdef MINIUPNP_EXPORTS |
||||
#define MINIUPNP_LIBSPEC __declspec(dllexport) |
||||
#else |
||||
#define MINIUPNP_LIBSPEC __declspec(dllimport) |
||||
#endif |
||||
#else |
||||
#if defined(__GNUC__) && __GNUC__ >= 4 |
||||
/* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ |
||||
#define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default"))) |
||||
#else |
||||
#define MINIUPNP_LIBSPEC |
||||
#endif |
||||
#endif |
||||
|
||||
#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */ |
||||
|
||||
@ -0,0 +1,695 @@
|
||||
/* $Id: miniupnpcmodule.c,v 1.29 2015/10/26 17:01:30 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 MINIUPNP_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() */ |
||||
unsigned int localport; /* 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" |
||||
}, |
||||
{"localport", T_UINT, offsetof(UPnPObject, localport), |
||||
0/*READWRITE*/, |
||||
"If localport is set to UPNP_LOCAL_PORT_SAME(1) " |
||||
"SSDP packets will be sent from the source port " |
||||
"1900 (same as destination port), if set to " |
||||
"UPNP_LOCAL_PORT_ANY(0) system assign a source " |
||||
"port, any other value will be attempted as the " |
||||
"source port" |
||||
}, |
||||
/* T_STRING is allways readonly :( */ |
||||
{"multicastif", T_STRING, offsetof(UPnPObject, multicastif), |
||||
0, "IP of the network interface to be used for multicast operations" |
||||
}, |
||||
{"minissdpdsocket", T_STRING, offsetof(UPnPObject, minissdpdsocket), |
||||
0, "path of the MiniSSDPd unix socket" |
||||
}, |
||||
{NULL} |
||||
}; |
||||
|
||||
|
||||
static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds) |
||||
{ |
||||
char* multicastif = NULL; |
||||
char* minissdpdsocket = NULL; |
||||
static char *kwlist[] = { |
||||
"multicastif", "minissdpdsocket", "discoverdelay", |
||||
"localport", NULL |
||||
}; |
||||
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist, |
||||
&multicastif, |
||||
&minissdpdsocket, |
||||
&self->discoverdelay, |
||||
&self->localport)) |
||||
return -1; |
||||
|
||||
if(self->localport>1 && |
||||
(self->localport>65534||self->localport<1024)) { |
||||
PyErr_SetString(PyExc_Exception, "Invalid localport value"); |
||||
return -1; |
||||
} |
||||
if(multicastif) |
||||
self->multicastif = strdup(multicastif); |
||||
if(minissdpdsocket) |
||||
self->minissdpdsocket = strdup(minissdpdsocket); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void |
||||
UPnPObject_dealloc(UPnPObject *self) |
||||
{ |
||||
freeUPNPDevlist(self->devlist); |
||||
FreeUPNPUrls(&self->urls); |
||||
free(self->multicastif); |
||||
free(self->minissdpdsocket); |
||||
Py_TYPE(self)->tp_free((PyObject*)self); |
||||
} |
||||
|
||||
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*/, |
||||
self->multicastif, |
||||
self->minissdpdsocket, |
||||
(int)self->localport, |
||||
0/*ip v6*/, |
||||
2/* TTL */, |
||||
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 |
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) |
||||
return Py_BuildValue("I", i); |
||||
#else |
||||
return Py_BuildValue("i", (int)i); |
||||
#endif |
||||
} |
||||
|
||||
static PyObject * |
||||
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 |
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) |
||||
return Py_BuildValue("I", i); |
||||
#else |
||||
return Py_BuildValue("i", (int)i); |
||||
#endif |
||||
} |
||||
|
||||
static PyObject * |
||||
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 |
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) |
||||
return Py_BuildValue("I", i); |
||||
#else |
||||
return Py_BuildValue("i", (int)i); |
||||
#endif |
||||
} |
||||
|
||||
static PyObject * |
||||
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 |
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) |
||||
return Py_BuildValue("I", i); |
||||
#else |
||||
return Py_BuildValue("i", (int)i); |
||||
#endif |
||||
} |
||||
|
||||
static PyObject * |
||||
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) { |
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) |
||||
return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror); |
||||
#else |
||||
return Py_BuildValue("(s,i,s)", status, (int)uptime, lastconnerror); |
||||
#endif |
||||
} else { |
||||
/* TODO: have our own exception type ! */ |
||||
PyErr_SetString(PyExc_Exception, strupnperror(r)); |
||||
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; |
||||
} |
||||
} |
||||
|
||||
/* AddAnyPortMapping(externalPort, protocol, internalHost, internalPort, desc,
|
||||
* remoteHost) |
||||
* protocol is 'UDP' or 'TCP' */ |
||||
static PyObject * |
||||
UPnP_addanyportmapping(UPnPObject *self, PyObject *args) |
||||
{ |
||||
char extPort[6]; |
||||
unsigned short ePort; |
||||
char inPort[6]; |
||||
unsigned short iPort; |
||||
char reservedPort[6]; |
||||
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_AddAnyPortMapping(self->urls.controlURL, self->data.first.servicetype, |
||||
extPort, inPort, host, desc, proto, |
||||
remoteHost, leaseDuration, reservedPort); |
||||
Py_END_ALLOW_THREADS |
||||
if(r==UPNPCOMMAND_SUCCESS) { |
||||
return Py_BuildValue("i", atoi(reservedPort)); |
||||
} else { |
||||
/* 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; |
||||
} |
||||
} |
||||
|
||||
/* DeletePortMappingRange(extPort, proto, removeHost='')
|
||||
* proto = 'UDP', 'TCP' */ |
||||
static PyObject * |
||||
UPnP_deleteportmappingrange(UPnPObject *self, PyObject *args) |
||||
{ |
||||
char extPortStart[6]; |
||||
unsigned short ePortStart; |
||||
char extPortEnd[6]; |
||||
unsigned short ePortEnd; |
||||
const char * proto; |
||||
unsigned char manage; |
||||
char manageStr[1]; |
||||
int r; |
||||
if(!PyArg_ParseTuple(args, "HHsb", &ePortStart, &ePortEnd, &proto, &manage)) |
||||
return NULL; |
||||
Py_BEGIN_ALLOW_THREADS |
||||
sprintf(extPortStart, "%hu", ePortStart); |
||||
sprintf(extPortEnd, "%hu", ePortEnd); |
||||
sprintf(manageStr, "%hhu", manage); |
||||
r = UPNP_DeletePortMappingRange(self->urls.controlURL, self->data.first.servicetype, |
||||
extPortStart, extPortEnd, proto, manageStr); |
||||
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) { |
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) |
||||
return Py_BuildValue("I", n); |
||||
#else |
||||
return Py_BuildValue("i", (int)n); |
||||
#endif |
||||
} else { |
||||
/* TODO: have our own exception type ! */ |
||||
PyErr_SetString(PyExc_Exception, strupnperror(r)); |
||||
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); |
||||
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) |
||||
return Py_BuildValue("(H,s,(s,H),s,s,s,I)", |
||||
ePort, protocol, intClient, iPort, |
||||
desc, enabled, rHost, dur); |
||||
#else |
||||
return Py_BuildValue("(i,s,(s,i),s,s,s,i)", |
||||
(int)ePort, protocol, intClient, (int)iPort, |
||||
desc, enabled, rHost, (int)dur); |
||||
#endif |
||||
} |
||||
else |
||||
{ |
||||
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" |
||||
}, |
||||
{"addanyportmapping", (PyCFunction)UPnP_addanyportmapping, METH_VARARGS, |
||||
"add a port mapping, IGD to select alternative if necessary" |
||||
}, |
||||
{"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS, |
||||
"delete a port mapping" |
||||
}, |
||||
{"deleteportmappingrange", (PyCFunction)UPnP_deleteportmappingrange, METH_VARARGS, |
||||
"delete a range of port mappings" |
||||
}, |
||||
{"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 */ |
||||
(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) |
||||
#if PY_MAJOR_VERSION >= 3 |
||||
return 0; |
||||
#else |
||||
return; |
||||
#endif |
||||
|
||||
#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,15 @@
|
||||
#ifndef MINIUPNPCSTRINGS_H_INCLUDED |
||||
#define MINIUPNPCSTRINGS_H_INCLUDED |
||||
|
||||
#define OS_STRING "${CMAKE_SYSTEM_NAME}" |
||||
#define MINIUPNPC_VERSION_STRING "${MINIUPNPC_VERSION}" |
||||
|
||||
#if 0 |
||||
/* according to "UPnP Device Architecture 1.0" */ |
||||
#define UPNP_VERSION_STRING "UPnP/1.0" |
||||
#else |
||||
/* according to "UPnP Device Architecture 1.1" */ |
||||
#define UPNP_VERSION_STRING "UPnP/1.1" |
||||
#endif |
||||
|
||||
#endif |
||||
@ -0,0 +1,23 @@
|
||||
/* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */ |
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard |
||||
* Copyright (c) 2005-2014 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" |
||||
|
||||
#if 0 |
||||
/* according to "UPnP Device Architecture 1.0" */ |
||||
#define UPNP_VERSION_STRING "UPnP/1.0" |
||||
#else |
||||
/* according to "UPnP Device Architecture 1.1" */ |
||||
#define UPNP_VERSION_STRING "UPnP/1.1" |
||||
#endif |
||||
|
||||
#endif |
||||
|
||||
@ -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,626 @@
|
||||
/* $Id: miniwget.c,v 1.72 2015/10/26 17:05:08 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subject to the conditions detailed in the |
||||
* LICENCE file provided in this distribution. */ |
||||
|
||||
#include <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 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 |
||||
#include <strings.h> |
||||
#endif /* #else _WIN32 */ |
||||
#ifdef __GNU__ |
||||
#define MAXHOSTNAMELEN 64 |
||||
#endif /* __GNU__ */ |
||||
|
||||
#ifndef MIN |
||||
#define MIN(x,y) (((x)<(y))?(x):(y)) |
||||
#endif /* MIN */ |
||||
|
||||
|
||||
#include "miniupnpcstrings.h" |
||||
#include "miniwget.h" |
||||
#include "connecthostport.h" |
||||
#include "receivedata.h" |
||||
|
||||
#ifndef MAXHOSTNAMELEN |
||||
#define MAXHOSTNAMELEN 64 |
||||
#endif |
||||
|
||||
/*
|
||||
* Read a HTTP response from a socket. |
||||
* Process Content-Length and Transfer-encoding headers. |
||||
* return a pointer to the content buffer, which length is saved |
||||
* to the length parameter. |
||||
*/ |
||||
void * |
||||
getHTTPResponse(int s, int * size) |
||||
{ |
||||
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); |
||||
if(header_buf == NULL) |
||||
{ |
||||
#ifdef DEBUG |
||||
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse"); |
||||
#endif /* DEBUG */ |
||||
*size = -1; |
||||
return NULL; |
||||
} |
||||
content_buf = malloc(content_buf_len); |
||||
if(content_buf == NULL) |
||||
{ |
||||
free(header_buf); |
||||
#ifdef DEBUG |
||||
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse"); |
||||
#endif /* DEBUG */ |
||||
*size = -1; |
||||
return NULL; |
||||
} |
||||
chunksize_buf[0] = '\0'; |
||||
chunksize_buf_index = 0; |
||||
|
||||
while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0) |
||||
{ |
||||
if(endofheaders == 0) |
||||
{ |
||||
int i; |
||||
int linestart=0; |
||||
int colon=0; |
||||
int valuestart=0; |
||||
if(header_buf_used + n > header_buf_len) { |
||||
char * tmp = realloc(header_buf, header_buf_used + n); |
||||
if(tmp == NULL) { |
||||
/* memory allocation error */ |
||||
free(header_buf); |
||||
free(content_buf); |
||||
*size = -1; |
||||
return NULL; |
||||
} |
||||
header_buf = tmp; |
||||
header_buf_len = header_buf_used + n; |
||||
} |
||||
memcpy(header_buf + header_buf_used, buf, n); |
||||
header_buf_used += n; |
||||
/* search for CR LF CR LF (end of headers)
|
||||
* recognize also LF LF */ |
||||
i = 0; |
||||
while(i < ((int)header_buf_used-1) && (endofheaders == 0)) { |
||||
if(header_buf[i] == '\r') { |
||||
i++; |
||||
if(header_buf[i] == '\n') { |
||||
i++; |
||||
if(i < (int)header_buf_used && header_buf[i] == '\r') { |
||||
i++; |
||||
if(i < (int)header_buf_used && header_buf[i] == '\n') { |
||||
endofheaders = i+1; |
||||
} |
||||
} |
||||
} |
||||
} else if(header_buf[i] == '\n') { |
||||
i++; |
||||
if(header_buf[i] == '\n') { |
||||
endofheaders = i+1; |
||||
} |
||||
} |
||||
i++; |
||||
} |
||||
if(endofheaders == 0) |
||||
continue; |
||||
/* parse header lines */ |
||||
for(i = 0; i < endofheaders - 1; i++) { |
||||
if(colon <= linestart && header_buf[i]==':') |
||||
{ |
||||
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) |
||||
{ |
||||
char * tmp; |
||||
if(content_length >= (int)(content_buf_used + bytestocopy)) { |
||||
content_buf_len = content_length; |
||||
} else { |
||||
content_buf_len = content_buf_used + bytestocopy; |
||||
} |
||||
tmp = realloc(content_buf, content_buf_len); |
||||
if(tmp == NULL) { |
||||
/* memory allocation error */ |
||||
free(content_buf); |
||||
free(header_buf); |
||||
*size = -1; |
||||
return NULL; |
||||
} |
||||
content_buf = tmp; |
||||
} |
||||
memcpy(content_buf + content_buf_used, buf + i, bytestocopy); |
||||
content_buf_used += bytestocopy; |
||||
i += bytestocopy; |
||||
chunksize -= bytestocopy; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
/* not chunked */ |
||||
if(content_length > 0 |
||||
&& (int)(content_buf_used + n) > content_length) { |
||||
/* skipping additional bytes */ |
||||
n = content_length - content_buf_used; |
||||
} |
||||
if(content_buf_used + n > content_buf_len) |
||||
{ |
||||
char * tmp; |
||||
if(content_length >= (int)(content_buf_used + n)) { |
||||
content_buf_len = content_length; |
||||
} else { |
||||
content_buf_len = content_buf_used + n; |
||||
} |
||||
tmp = realloc(content_buf, content_buf_len); |
||||
if(tmp == NULL) { |
||||
/* memory allocation error */ |
||||
free(content_buf); |
||||
free(header_buf); |
||||
*size = -1; |
||||
return NULL; |
||||
} |
||||
content_buf = tmp; |
||||
} |
||||
memcpy(content_buf + content_buf_used, buf, n); |
||||
content_buf_used += n; |
||||
} |
||||
} |
||||
/* use the Content-Length header value if available */ |
||||
if(content_length > 0 && (int)content_buf_used >= content_length) |
||||
{ |
||||
#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_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" |
||||
|
||||
"\r\n", |
||||
path, httpversion, host, port); |
||||
if ((unsigned int)len >= sizeof(buf)) |
||||
{ |
||||
closesocket(s); |
||||
return NULL; |
||||
} |
||||
sent = 0; |
||||
/* sending the HTTP request */ |
||||
while(sent < len) |
||||
{ |
||||
n = send(s, buf+sent, len-sent, 0); |
||||
if(n < 0) |
||||
{ |
||||
perror("send"); |
||||
closesocket(s); |
||||
return NULL; |
||||
} |
||||
else |
||||
{ |
||||
sent += n; |
||||
} |
||||
} |
||||
content = getHTTPResponse(s, size); |
||||
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.10 2015/07/21 13:16:55 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subject to the conditions detailed in the |
||||
* LICENCE file provided in this distribution. |
||||
* */ |
||||
#ifndef MINIWGET_H_INCLUDED |
||||
#define MINIWGET_H_INCLUDED |
||||
|
||||
#include "miniupnpc_declspec.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size); |
||||
|
||||
MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int); |
||||
|
||||
MINIUPNP_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,163 @@
|
||||
/* $Id: minixmlvalid.c,v 1.7 2015/07/15 12:41:15 nanard Exp $ */ |
||||
/* MiniUPnP Project
|
||||
* http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
|
||||
* minixmlvalid.c : |
||||
* validation program for the minixml parser |
||||
* |
||||
* (c) 2006-2011 Thomas Bernard */ |
||||
|
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include "minixml.h" |
||||
|
||||
/* xml event structure */ |
||||
struct event { |
||||
enum { ELTSTART, ELTEND, ATT, CHARDATA } type; |
||||
const char * data; |
||||
int len; |
||||
}; |
||||
|
||||
struct eventlist { |
||||
int n; |
||||
struct event * events; |
||||
}; |
||||
|
||||
/* compare 2 xml event lists
|
||||
* return 0 if the two lists are equals */ |
||||
int evtlistcmp(struct eventlist * a, struct eventlist * b) |
||||
{ |
||||
int i; |
||||
struct event * ae, * be; |
||||
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); |
||||
if(evtlist.events == NULL) |
||||
{ |
||||
fprintf(stderr, "Memory allocation error.\n"); |
||||
return -1; |
||||
} |
||||
memset(&parser, 0, sizeof(parser)); |
||||
parser.xmlstart = xml; |
||||
parser.xmlsize = size; |
||||
parser.data = &evtlist; |
||||
parser.starteltfunc = startelt; |
||||
parser.endeltfunc = endelt; |
||||
parser.datafunc = chardata; |
||||
parsexml(&parser); |
||||
printf("%d events\n", evtlist.n); |
||||
/* compare */ |
||||
evtlistref.n = sizeof(evtref)/sizeof(struct event); |
||||
evtlistref.events = (struct event *)evtref; |
||||
r = evtlistcmp(&evtlistref, &evtlist); |
||||
free(evtlist.events); |
||||
return r; |
||||
} |
||||
|
||||
int main(int argc, char * * argv) |
||||
{ |
||||
int r; |
||||
(void)argc; (void)argv; |
||||
|
||||
r = testxmlparser(xmldata, sizeof(xmldata)-1); |
||||
if(r) |
||||
printf("minixml validation test failed\n"); |
||||
return r; |
||||
} |
||||
|
||||
@ -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,283 @@
|
||||
<?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;MINIUPNP_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;MINIUPNP_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="..\minissdpc.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="..\upnpdev.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="..\connecthostport.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="..\declspec.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="..\igd_desc_parse.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="..\minisoap.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="..\minissdpc.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="..\upnpdev.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="_DEBUG;_CONSOLE;MINIUPNP_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="NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;MINIUPNP_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,172 @@
|
||||
/* $Id: portlistingparse.c,v 1.9 2015/07/15 12:41:13 nanard Exp $ */ |
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2011-2015 Thomas Bernard |
||||
* This software is subject to the conditions detailed |
||||
* in the LICENCE file provided within the distribution */ |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#ifdef DEBUG |
||||
#include <stdio.h> |
||||
#endif /* DEBUG */ |
||||
#include "portlistingparse.h" |
||||
#include "minixml.h" |
||||
|
||||
/* 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)); |
||||
if(pm == NULL) |
||||
{ |
||||
/* malloc error */ |
||||
#ifdef DEBUG |
||||
fprintf(stderr, "%s: error allocating memory", |
||||
"startelt"); |
||||
#endif /* DEBUG */ |
||||
return; |
||||
} |
||||
pm->l_next = pdata->l_head; /* insert in list */ |
||||
pdata->l_head = pm; |
||||
} |
||||
} |
||||
|
||||
/* End element handler */ |
||||
static void |
||||
endelt(void * d, const char * name, int l) |
||||
{ |
||||
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; |
||||
(void)name; |
||||
(void)l; |
||||
pdata->curelt = PortMappingEltNone; |
||||
} |
||||
|
||||
/* Data handler */ |
||||
static void |
||||
data(void * d, const char * data, int l) |
||||
{ |
||||
struct PortMapping * pm; |
||||
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; |
||||
pm = pdata->l_head; |
||||
if(!pm) |
||||
return; |
||||
if(l > 63) |
||||
l = 63; |
||||
switch(pdata->curelt) |
||||
{ |
||||
case NewRemoteHost: |
||||
memcpy(pm->remoteHost, data, l); |
||||
pm->remoteHost[l] = '\0'; |
||||
break; |
||||
case NewExternalPort: |
||||
pm->externalPort = (unsigned short)atoui(data, l); |
||||
break; |
||||
case NewProtocol: |
||||
if(l > 3) |
||||
l = 3; |
||||
memcpy(pm->protocol, data, l); |
||||
pm->protocol[l] = '\0'; |
||||
break; |
||||
case NewInternalPort: |
||||
pm->internalPort = (unsigned short)atoui(data, l); |
||||
break; |
||||
case NewInternalClient: |
||||
memcpy(pm->internalClient, data, l); |
||||
pm->internalClient[l] = '\0'; |
||||
break; |
||||
case NewEnabled: |
||||
pm->enabled = (unsigned char)atoui(data, l); |
||||
break; |
||||
case NewDescription: |
||||
memcpy(pm->description, data, l); |
||||
pm->description[l] = '\0'; |
||||
break; |
||||
case NewLeaseTime: |
||||
pm->leaseTime = atoui(data, l); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
|
||||
/* Parse the PortMappingList XML document for IGD version 2
|
||||
*/ |
||||
void |
||||
ParsePortListing(const char * buffer, int bufsize, |
||||
struct PortMappingParserData * pdata) |
||||
{ |
||||
struct xmlparser parser; |
||||
|
||||
memset(pdata, 0, sizeof(struct PortMappingParserData)); |
||||
/* 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->l_head) != NULL) |
||||
{ |
||||
/* remove from list */ |
||||
pdata->l_head = pm->l_next; |
||||
free(pm); |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,65 @@
|
||||
/* $Id: portlistingparse.h,v 1.11 2015/07/21 13:16:55 nanard Exp $ */ |
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2011-2015 Thomas Bernard |
||||
* This software is subject to the conditions detailed |
||||
* in the LICENCE file provided within the distribution */ |
||||
#ifndef PORTLISTINGPARSE_H_INCLUDED |
||||
#define PORTLISTINGPARSE_H_INCLUDED |
||||
|
||||
#include "miniupnpc_declspec.h" |
||||
/* for the definition of UNSIGNED_INTEGER */ |
||||
#include "miniupnpctypes.h" |
||||
|
||||
#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 { |
||||
struct PortMapping * l_next; /* list next element */ |
||||
UNSIGNED_INTEGER leaseTime; |
||||
unsigned short externalPort; |
||||
unsigned short internalPort; |
||||
char remoteHost[64]; |
||||
char internalClient[64]; |
||||
char description[64]; |
||||
char protocol[4]; |
||||
unsigned char enabled; |
||||
}; |
||||
|
||||
struct PortMappingParserData { |
||||
struct PortMapping * l_head; /* list head */ |
||||
portMappingElt curelt; |
||||
}; |
||||
|
||||
MINIUPNP_LIBSPEC void |
||||
ParsePortListing(const char * buffer, int bufsize, |
||||
struct PortMappingParserData * pdata); |
||||
|
||||
MINIUPNP_LIBSPEC void |
||||
FreePortListing(struct PortMappingParserData * pdata); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
||||
@ -0,0 +1,88 @@
|
||||
#! /usr/bin/python |
||||
# vim: tabstop=2 shiftwidth=2 expandtab |
||||
# 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 |
||||
|
||||
try: |
||||
import argparse |
||||
parser = argparse.ArgumentParser() |
||||
parser.add_argument('-m', '--multicastif') |
||||
parser.add_argument('-p', '--minissdpdsocket') |
||||
parser.add_argument('-d', '--discoverdelay', type=int, default=200) |
||||
parser.add_argument('-z', '--localport', type=int, default=0) |
||||
# create the object |
||||
u = miniupnpc.UPnP(**vars(parser.parse_args())) |
||||
except: |
||||
print 'argparse not available' |
||||
i = 1 |
||||
multicastif = None |
||||
minissdpdsocket = None |
||||
discoverdelay = 200 |
||||
localport = 0 |
||||
while i < len(sys.argv): |
||||
print sys.argv[i] |
||||
if sys.argv[i] == '-m' or sys.argv[i] == '--multicastif': |
||||
multicastif = sys.argv[i+1] |
||||
elif sys.argv[i] == '-p' or sys.argv[i] == '--minissdpdsocket': |
||||
minissdpdsocket = sys.argv[i+1] |
||||
elif sys.argv[i] == '-d' or sys.argv[i] == '--discoverdelay': |
||||
discoverdelay = int(sys.argv[i+1]) |
||||
elif sys.argv[i] == '-z' or sys.argv[i] == '--localport': |
||||
localport = int(sys.argv[i+1]) |
||||
else: |
||||
raise Exception('invalid argument %s' % sys.argv[i]) |
||||
i += 2 |
||||
# create the object |
||||
u = miniupnpc.UPnP(multicastif, minissdpdsocket, discoverdelay, localport) |
||||
|
||||
print 'inital(default) values :' |
||||
print ' discoverdelay', u.discoverdelay |
||||
print ' lanaddr', u.lanaddr |
||||
print ' multicastif', u.multicastif |
||||
print ' minissdpdsocket', u.minissdpdsocket |
||||
#u.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 'total bytes : sent', u.totalbytesent(), 'received', u.totalbytereceived() |
||||
print 'total packets : sent', u.totalpacketsent(), 'received', u.totalpacketreceived() |
||||
|
||||
#print u.addportmapping(64000, 'TCP', |
||||
# '192.168.1.166', 63000, 'port mapping test', '') |
||||
#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) |
||||
try: |
||||
print u.getportmappingnumberofentries() |
||||
except Exception, e: |
||||
print 'GetPortMappingNumberOfEntries() is not supported :', e |
||||
|
||||
@ -0,0 +1,105 @@
|
||||
/* $Id: receivedata.c,v 1.6 2014/11/13 13:51:52 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* Website : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2011-2014 Thomas Bernard |
||||
* This software is subject to the conditions detailed in the |
||||
* LICENCE file provided in this distribution. */ |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#ifdef _WIN32 |
||||
#include <winsock2.h> |
||||
#include <ws2tcpip.h> |
||||
#else /* _WIN32 */ |
||||
#include <unistd.h> |
||||
#if defined(__amigaos__) && !defined(__amigaos4__) |
||||
#define socklen_t int |
||||
#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ |
||||
#include <sys/select.h> |
||||
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ |
||||
#include <sys/socket.h> |
||||
#include <netinet/in.h> |
||||
#if !defined(__amigaos__) && !defined(__amigaos4__) |
||||
#include <poll.h> |
||||
#endif /* !defined(__amigaos__) && !defined(__amigaos4__) */ |
||||
#include <errno.h> |
||||
#define MINIUPNPC_IGNORE_EINTR |
||||
#endif /* _WIN32 */ |
||||
|
||||
#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 |
||||
struct sockaddr_storage src_addr; |
||||
socklen_t src_addr_len = sizeof(src_addr); |
||||
#endif /* MINIUPNPC_GET_SRC_ADDR */ |
||||
int n; |
||||
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) |
||||
/* using poll */ |
||||
struct pollfd fds[1]; /* for the poll */ |
||||
#ifdef MINIUPNPC_IGNORE_EINTR |
||||
do { |
||||
#endif /* MINIUPNPC_IGNORE_EINTR */ |
||||
fds[0].fd = socket; |
||||
fds[0].events = POLLIN; |
||||
n = poll(fds, 1, timeout); |
||||
#ifdef MINIUPNPC_IGNORE_EINTR |
||||
} while(n < 0 && errno == EINTR); |
||||
#endif /* MINIUPNPC_IGNORE_EINTR */ |
||||
if(n < 0) { |
||||
PRINT_SOCKET_ERROR("poll"); |
||||
return -1; |
||||
} else if(n == 0) { |
||||
/* timeout */ |
||||
return 0; |
||||
} |
||||
#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ |
||||
/* 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 /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ |
||||
#if MINIUPNPC_GET_SRC_ADDR |
||||
memset(&src_addr, 0, sizeof(src_addr)); |
||||
n = recvfrom(socket, data, length, 0, |
||||
(struct sockaddr *)&src_addr, &src_addr_len); |
||||
#else /* MINIUPNPC_GET_SRC_ADDR */ |
||||
n = recv(socket, data, length, 0); |
||||
#endif /* MINIUPNPC_GET_SRC_ADDR */ |
||||
if(n<0) { |
||||
PRINT_SOCKET_ERROR("recv"); |
||||
} |
||||
#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 /* DEBUG */ |
||||
if(scope_id) |
||||
*scope_id = src_addr6->sin6_scope_id; |
||||
} |
||||
#endif /* MINIUPNPC_GET_SRC_ADDR */ |
||||
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,28 @@
|
||||
#! /usr/bin/python |
||||
# vim: tabstop=8 shiftwidth=8 expandtab |
||||
# $Id: setup.py,v 1.12 2015/10/26 17:03:17 nanard Exp $ |
||||
# the MiniUPnP Project (c) 2007-2014 Thomas Bernard |
||||
# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ |
||||
# |
||||
# python script to build the miniupnpc module under unix |
||||
# |
||||
# replace libminiupnpc.a by libminiupnpc.so for shared library usage |
||||
try: |
||||
from setuptools import setup, Extension |
||||
except ImportError: |
||||
from distutils.core import setup, Extension |
||||
from distutils import sysconfig |
||||
sysconfig.get_config_vars()["OPT"] = '' |
||||
sysconfig.get_config_vars()["CFLAGS"] = '' |
||||
setup(name="miniupnpc", |
||||
version=open('VERSION').read().strip(), |
||||
author='Thomas BERNARD', |
||||
author_email='miniupnp@free.fr', |
||||
license=open('LICENSE').read(), |
||||
url='http://miniupnp.free.fr/', |
||||
description='miniUPnP client', |
||||
ext_modules=[ |
||||
Extension(name="miniupnpc", sources=["miniupnpcmodule.c"], |
||||
extra_objects=["libminiupnpc.a"]) |
||||
]) |
||||
|
||||
@ -0,0 +1,28 @@
|
||||
#! /usr/bin/python |
||||
# vim: tabstop=8 shiftwidth=8 expandtab |
||||
# $Id: setupmingw32.py,v 1.10 2015/10/26 17:03:17 nanard Exp $ |
||||
# the MiniUPnP Project (c) 2007-2014 Thomas Bernard |
||||
# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ |
||||
# |
||||
# python script to build the miniupnpc module under windows (using mingw32) |
||||
# |
||||
try: |
||||
from setuptools import setup, Extension |
||||
except ImportError: |
||||
from distutils.core import setup, Extension |
||||
from distutils import sysconfig |
||||
sysconfig.get_config_vars()["OPT"] = '' |
||||
sysconfig.get_config_vars()["CFLAGS"] = '' |
||||
setup(name="miniupnpc", |
||||
version=open('VERSION').read().strip(), |
||||
author='Thomas BERNARD', |
||||
author_email='miniupnp@free.fr', |
||||
license=open('LICENSE').read(), |
||||
url='http://miniupnp.free.fr/', |
||||
description='miniUPnP client', |
||||
ext_modules=[ |
||||
Extension(name="miniupnpc", sources=["miniupnpcmodule.c"], |
||||
libraries=["ws2_32", "iphlpapi"], |
||||
extra_objects=["libminiupnpc.a"]) |
||||
]) |
||||
|
||||
@ -0,0 +1,14 @@
|
||||
# values for linksys_WAG200G_desc.xml |
||||
|
||||
CIF: |
||||
servicetype = urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 |
||||
controlurl = /upnp/control/WANCommonIFC1 |
||||
eventsuburl = /upnp/event/WANCommonIFC1 |
||||
scpdurl = /cmnicfg.xml |
||||
|
||||
first: |
||||
servicetype = urn:schemas-upnp-org:service:WANPPPConnection:1 |
||||
controlurl = /upnp/control/WANPPPConn1 |
||||
eventsuburl = /upnp/event/WANPPPConn1 |
||||
scpdurl = /pppcfg.xml |
||||
|
||||
@ -0,0 +1,110 @@
|
||||
<?xml version="1.0"?> |
||||
<root xmlns="urn:schemas-upnp-org:device-1-0"> |
||||
<specVersion> |
||||
<major>1</major> |
||||
<minor>0</minor> |
||||
</specVersion> |
||||
<URLBase>http://192.168.1.1:49152</URLBase> |
||||
<device> |
||||
<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType> |
||||
<friendlyName>LINKSYS WAG200G Gateway</friendlyName> |
||||
<manufacturer>LINKSYS</manufacturer> |
||||
<manufacturerURL>http://www.linksys.com</manufacturerURL> |
||||
<modelDescription>LINKSYS WAG200G Gateway</modelDescription> |
||||
<modelName>Wireless-G ADSL Home Gateway</modelName> |
||||
<modelNumber>WAG200G</modelNumber> |
||||
<modelURL>http://www.linksys.com</modelURL> |
||||
<serialNumber>123456789</serialNumber> |
||||
<UDN>uuid:8ca2eb37-1dd2-11b2-86f1-001a709b5aa8</UDN> |
||||
<UPC>WAG200G</UPC> |
||||
<serviceList> |
||||
<service> |
||||
<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType> |
||||
<serviceId>urn:upnp-org:serviceId:L3Forwarding1</serviceId> |
||||
<controlURL>/upnp/control/L3Forwarding1</controlURL> |
||||
<eventSubURL>/upnp/event/L3Forwarding1</eventSubURL> |
||||
<SCPDURL>/l3frwd.xml</SCPDURL> |
||||
</service> |
||||
</serviceList> |
||||
<deviceList> |
||||
<device> |
||||
<deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType> |
||||
<friendlyName>WANDevice</friendlyName> |
||||
<manufacturer>LINKSYS</manufacturer> |
||||
<manufacturerURL>http://www.linksys.com/</manufacturerURL> |
||||
<modelDescription>Residential Gateway</modelDescription> |
||||
<modelName>Internet Connection Sharing</modelName> |
||||
<modelNumber>1</modelNumber> |
||||
<modelURL>http://www.linksys.com/</modelURL> |
||||
<serialNumber>0000001</serialNumber> |
||||
<UDN>uuid:8ca2eb36-1dd2-11b2-86f1-001a709b5aa8</UDN> |
||||
<UPC>WAG200G</UPC> |
||||
<serviceList> |
||||
<service> |
||||
<serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType> |
||||
<serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId> |
||||
<controlURL>/upnp/control/WANCommonIFC1</controlURL> |
||||
<eventSubURL>/upnp/event/WANCommonIFC1</eventSubURL> |
||||
<SCPDURL>/cmnicfg.xml</SCPDURL> |
||||
</service> |
||||
</serviceList> |
||||
<deviceList> |
||||
<device> |
||||
<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType> |
||||
<friendlyName>WANConnectionDevice</friendlyName> |
||||
<manufacturer>LINKSYS</manufacturer> |
||||
<manufacturerURL>http://www.linksys.com/</manufacturerURL> |
||||
<modelDescription>Residential Gateway</modelDescription> |
||||
<modelName>Internet Connection Sharing</modelName> |
||||
<modelNumber>1</modelNumber> |
||||
<modelURL>http://www.linksys.com/</modelURL> |
||||
<serialNumber>0000001</serialNumber> |
||||
<UDN>uuid:8ca2eb37-1dd2-11b2-86f0-001a709b5aa8</UDN> |
||||
<UPC>WAG200G</UPC> |
||||
<serviceList> |
||||
<service> |
||||
<serviceType>urn:schemas-upnp-org:service:WANEthernetLinkConfig:1</serviceType> |
||||
<serviceId>urn:upnp-org:serviceId:WANEthLinkC1</serviceId> |
||||
<controlURL>/upnp/control/WANEthLinkC1</controlURL> |
||||
<eventSubURL>/upnp/event/WANEthLinkC1</eventSubURL> |
||||
<SCPDURL>/wanelcfg.xml</SCPDURL> |
||||
</service> |
||||
<service> |
||||
<serviceType>urn:schemas-upnp-org:service:WANPPPConnection:1</serviceType> |
||||
<serviceId>urn:upnp-org:serviceId:WANPPPConn1</serviceId> |
||||
<controlURL>/upnp/control/WANPPPConn1</controlURL> |
||||
<eventSubURL>/upnp/event/WANPPPConn1</eventSubURL> |
||||
<SCPDURL>/pppcfg.xml</SCPDURL> |
||||
</service> |
||||
</serviceList> |
||||
</device> |
||||
</deviceList> |
||||
</device> |
||||
<device> |
||||
<deviceType>urn:schemas-upnp-org:device:LANDevice:1</deviceType> |
||||
<friendlyName>LANDevice</friendlyName> |
||||
<manufacturer>LINKSYS</manufacturer> |
||||
<manufacturerURL>http://www.linksys.com/</manufacturerURL> |
||||
<modelDescription>Residential Gateway</modelDescription> |
||||
<modelName>Residential Gateway</modelName> |
||||
<modelNumber>1</modelNumber> |
||||
<modelURL>http://www.linksys.com/</modelURL> |
||||
<serialNumber>0000001</serialNumber> |
||||
<UDN>uuid:8ca2eb36-1dd2-11b2-86f0-001a709b5aa |
||||
8</UDN> |
||||
<UPC>WAG200G</UPC> |
||||
<serviceList> |
||||
<service> |
||||
<serviceType>urn:schemas-upnp-org:service:LANHostConfigManagement:1</serviceType> |
||||
<serviceId>urn:upnp-org:serviceId:LANHostCfg1</serviceId> |
||||
<controlURL>/upnp/control/LANHostCfg1</controlURL> |
||||
<eventSubURL>/upnp/event/LANHostCfg1</eventSubURL> |
||||
<SCPDURL>/lanhostc.xml</SCPDURL> |
||||
</service> |
||||
</serviceList> |
||||
</device> |
||||
</deviceList> |
||||
<presentationURL>http://192.168.1.1/index.htm</presentationURL> |
||||
</device> |
||||
</root> |
||||
|
||||
@ -0,0 +1,20 @@
|
||||
# values for new_LiveBox_desc.xml |
||||
|
||||
CIF: |
||||
servicetype = urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1 |
||||
controlurl = /87895a19/upnp/control/WANCommonIFC1 |
||||
eventsuburl = /87895a19/upnp/control/WANCommonIFC1 |
||||
scpdurl = /87895a19/gateicfgSCPD.xml |
||||
|
||||
first: |
||||
servicetype = urn:schemas-upnp-org:service:WANPPPConnection:2 |
||||
controlurl = /87895a19/upnp/control/WANIPConn1 |
||||
eventsuburl = /87895a19/upnp/control/WANIPConn1 |
||||
scpdurl = /87895a19/gateconnSCPD_PPP.xml |
||||
|
||||
IPv6FC: |
||||
servicetype = urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 |
||||
controlurl = /87895a19/upnp/control/WANIPv6FwCtrl1 |
||||
eventsuburl = /87895a19/upnp/control/WANIPv6FwCtrl1 |
||||
scpdurl = /87895a19/wanipv6fwctrlSCPD.xml |
||||
|
||||
@ -0,0 +1,90 @@
|
||||
<?xml version="1.0"?> |
||||
<root xmlns="urn:schemas-upnp-org:device-1-0"> |
||||
<specVersion> |
||||
<major>1</major> |
||||
<minor>0</minor> |
||||
</specVersion> |
||||
<device> |
||||
<pnpx:X_hardwareId xmlns:pnpx="http://schemas.microsoft.com/windows/pnpx/2005/11">VEN_0129&DEV_0000&SUBSYS_03&REV_250417</pnpx:X_hardwareId> |
||||
<pnpx:X_compatibleId xmlns:pnpx="http://schemas.microsoft.com/windows/pnpx/2005/11">GenericUmPass</pnpx:X_compatibleId> |
||||
<pnpx:X_deviceCategory xmlns:pnpx="http://schemas.microsoft.com/windows/pnpx/2005/11">NetworkInfrastructure.Gateway</pnpx:X_deviceCategory> |
||||
<df:X_deviceCategory xmlns:df="http://schemas.microsoft.com/windows/2008/09/devicefoundation">Network.Gateway</df:X_deviceCategory> |
||||
<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:2</deviceType> |
||||
<friendlyName>Orange Livebox</friendlyName> |
||||
<manufacturer>Sagemcom</manufacturer> |
||||
<manufacturerURL>http://www.sagemcom.com/</manufacturerURL> |
||||
<modelName>Residential Livebox,(DSL,WAN Ethernet)</modelName> |
||||
<UDN>uuid:87895a19-50f9-3736-a87f-115c230155f8</UDN> |
||||
<modelDescription>Sagemcom,fr,SG30_sip-fr-4.28.35.1</modelDescription> |
||||
<modelNumber>3</modelNumber> |
||||
<serialNumber>LK14129DP441489</serialNumber> |
||||
<presentationURL>http://192.168.1.1</presentationURL> |
||||
<UPC></UPC> |
||||
<iconList> |
||||
<icon> |
||||
<mimetype>image/png</mimetype> |
||||
<width>16</width> |
||||
<height>16</height> |
||||
<depth>8</depth> |
||||
<url>/87895a19/ligd.png</url> |
||||
</icon> |
||||
</iconList> |
||||
<deviceList> |
||||
<device> |
||||
<deviceType>urn:schemas-upnp-org:device:WANDevice:2</deviceType> |
||||
<friendlyName>WANDevice</friendlyName> |
||||
<manufacturer>Sagemcom</manufacturer> |
||||
<manufacturerURL>http://www.sagemcom.com/</manufacturerURL> |
||||
<modelDescription>WAN Device on Sagemcom,fr,SG30_sip-fr-4.28.35.1</modelDescription> |
||||
<modelName>Residential Livebox,(DSL,WAN Ethernet)</modelName> |
||||
<modelNumber>3</modelNumber> |
||||
<modelURL>http://www.sagemcom.com/</modelURL> |
||||
<serialNumber>LK14129DP441489</serialNumber> |
||||
<presentationURL>http://192.168.1.1</presentationURL> |
||||
<UDN>uuid:e2397374-53d8-3fc6-8306-593ba1a34625</UDN> |
||||
<UPC></UPC> |
||||
<serviceList> |
||||
<service> |
||||
<serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType> |
||||
<serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId> |
||||
<controlURL>/87895a19/upnp/control/WANCommonIFC1</controlURL> |
||||
<eventSubURL>/87895a19/upnp/control/WANCommonIFC1</eventSubURL> |
||||
<SCPDURL>/87895a19/gateicfgSCPD.xml</SCPDURL> |
||||
</service> |
||||
</serviceList> |
||||
<deviceList> |
||||
<device> |
||||
<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:2</deviceType> |
||||
<friendlyName>WANConnectionDevice</friendlyName> |
||||
<manufacturer>Sagemcom</manufacturer> |
||||
<manufacturerURL>http://www.sagemcom.com/</manufacturerURL> |
||||
<modelDescription>WanConnectionDevice on Sagemcom,fr,SG30_sip-fr-4.28.35.1</modelDescription> |
||||
<modelName>Residential Livebox,(DSL,WAN Ethernet)</modelName> |
||||
<modelNumber>3</modelNumber> |
||||
<modelURL>http://www.sagemcom.com/</modelURL> |
||||
<serialNumber>LK14129DP441489</serialNumber> |
||||
<presentationURL>http://192.168.1.1</presentationURL> |
||||
<UDN>uuid:44598a08-288e-32c9-8a4d-d3c008ede331</UDN> |
||||
<UPC></UPC> |
||||
<serviceList> |
||||
<service> |
||||
<serviceType>urn:schemas-upnp-org:service:WANPPPConnection:2</serviceType> |
||||
<serviceId>urn:upnp-org:serviceId:WANIPConn1</serviceId> |
||||
<controlURL>/87895a19/upnp/control/WANIPConn1</controlURL> |
||||
<eventSubURL>/87895a19/upnp/control/WANIPConn1</eventSubURL> |
||||
<SCPDURL>/87895a19/gateconnSCPD_PPP.xml</SCPDURL> |
||||
</service> |
||||
<service> |
||||
<serviceType>urn:schemas-upnp-org:service:WANIPv6FirewallControl:1</serviceType> |
||||
<serviceId>urn:upnp-org:serviceId:WANIPv6FwCtrl1</serviceId> |
||||
<controlURL>/87895a19/upnp/control/WANIPv6FwCtrl1</controlURL> |
||||
<eventSubURL>/87895a19/upnp/control/WANIPv6FwCtrl1</eventSubURL> |
||||
<SCPDURL>/87895a19/wanipv6fwctrlSCPD.xml</SCPDURL> |
||||
</service> |
||||
</serviceList> |
||||
</device> |
||||
</deviceList> |
||||
</device> |
||||
</deviceList> |
||||
</device> |
||||
</root> |
||||
@ -0,0 +1,187 @@
|
||||
/* $Id: testigddescparse.c,v 1.10 2015/08/06 09:55:24 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2008-2015 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" |
||||
|
||||
/* count number of differences */ |
||||
int compare_service(struct IGDdatas_service * s, FILE * f) |
||||
{ |
||||
int n = 0; |
||||
char line[1024]; |
||||
|
||||
while(fgets(line, sizeof(line), f)) { |
||||
char * value; |
||||
char * equal; |
||||
char * name; |
||||
char * parsedvalue; |
||||
int l; |
||||
l = strlen(line); |
||||
while((l > 0) && ((line[l-1] == '\r') || (line[l-1] == '\n') || (line[l-1] == ' '))) |
||||
line[--l] = '\0'; |
||||
if(l == 0) |
||||
break; /* end on blank line */ |
||||
if(line[0] == '#') |
||||
continue; /* skip comments */ |
||||
equal = strchr(line, '='); |
||||
if(equal == NULL) { |
||||
fprintf(stderr, "Warning, line does not contain '=' : %s\n", line); |
||||
continue; |
||||
} |
||||
*equal = '\0'; |
||||
name = line; |
||||
while(*name == ' ' || *name == '\t') |
||||
name++; |
||||
l = strlen(name); |
||||
while((l > 0) && (name[l-1] == ' ' || name[l-1] == '\t')) |
||||
name[--l] = '\0'; |
||||
value = equal + 1; |
||||
while(*value == ' ' || *value == '\t') |
||||
value++; |
||||
if(strcmp(name, "controlurl") == 0) |
||||
parsedvalue = s->controlurl; |
||||
else if(strcmp(name, "eventsuburl") == 0) |
||||
parsedvalue = s->eventsuburl; |
||||
else if(strcmp(name, "scpdurl") == 0) |
||||
parsedvalue = s->scpdurl; |
||||
else if(strcmp(name, "servicetype") == 0) |
||||
parsedvalue = s->servicetype; |
||||
else { |
||||
fprintf(stderr, "unknown field '%s'\n", name); |
||||
continue; |
||||
} |
||||
if(0 != strcmp(parsedvalue, value)) { |
||||
fprintf(stderr, "difference : '%s' != '%s'\n", parsedvalue, value); |
||||
n++; |
||||
} |
||||
} |
||||
return n; |
||||
} |
||||
|
||||
int compare_igd(struct IGDdatas * p, FILE * f) |
||||
{ |
||||
int n = 0; |
||||
char line[1024]; |
||||
struct IGDdatas_service * s; |
||||
|
||||
while(fgets(line, sizeof(line), f)) { |
||||
char * colon; |
||||
int l = (int)strlen(line); |
||||
while((l > 0) && (line[l-1] == '\r' || (line[l-1] == '\n'))) |
||||
line[--l] = '\0'; |
||||
if(l == 0 || line[0] == '#') |
||||
continue; /* skip blank lines and comments */ |
||||
colon = strchr(line, ':'); |
||||
if(colon == NULL) { |
||||
fprintf(stderr, "Warning, no ':' : %s\n", line); |
||||
continue; |
||||
} |
||||
s = NULL; |
||||
*colon = '\0'; |
||||
if(strcmp(line, "CIF") == 0) |
||||
s = &p->CIF; |
||||
else if(strcmp(line, "first") == 0) |
||||
s = &p->first; |
||||
else if(strcmp(line, "second") == 0) |
||||
s = &p->second; |
||||
else if(strcmp(line, "IPv6FC") == 0) |
||||
s = &p->IPv6FC; |
||||
else { |
||||
s = NULL; |
||||
fprintf(stderr, "*** unknown service '%s' ***\n", line); |
||||
n++; |
||||
continue; |
||||
} |
||||
n += compare_service(s, f); |
||||
} |
||||
if(n > 0) |
||||
fprintf(stderr, "*** %d difference%s ***\n", n, (n > 1) ? "s" : ""); |
||||
return n; |
||||
} |
||||
|
||||
int test_igd_desc_parse(char * buffer, int len, FILE * f) |
||||
{ |
||||
int n; |
||||
struct IGDdatas igd; |
||||
struct xmlparser parser; |
||||
struct UPNPUrls urls; |
||||
|
||||
memset(&igd, 0, sizeof(struct IGDdatas)); |
||||
memset(&parser, 0, sizeof(struct xmlparser)); |
||||
parser.xmlstart = buffer; |
||||
parser.xmlsize = len; |
||||
parser.data = &igd; |
||||
parser.starteltfunc = IGDstartelt; |
||||
parser.endeltfunc = IGDendelt; |
||||
parser.datafunc = IGDdata; |
||||
parsexml(&parser); |
||||
#ifdef DEBUG |
||||
printIGD(&igd); |
||||
#endif /* DEBUG */ |
||||
GetUPNPUrls(&urls, &igd, "http://fake/desc/url/file.xml", 0); |
||||
printf("ipcondescURL='%s'\n", urls.ipcondescURL); |
||||
printf("controlURL='%s'\n", urls.controlURL); |
||||
printf("controlURL_CIF='%s'\n", urls.controlURL_CIF); |
||||
n = f ? compare_igd(&igd, f) : 0; |
||||
FreeUPNPUrls(&urls); |
||||
return n; |
||||
} |
||||
|
||||
int main(int argc, char * * argv) |
||||
{ |
||||
FILE * f; |
||||
char * buffer; |
||||
int len; |
||||
int r; |
||||
if(argc<2) { |
||||
fprintf(stderr, "Usage: %s file.xml [file.values]\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); |
||||
if(!buffer) { |
||||
fprintf(stderr, "Memory allocation error.\n"); |
||||
fclose(f); |
||||
return 1; |
||||
} |
||||
r = (int)fread(buffer, 1, len, f); |
||||
if(r != len) { |
||||
fprintf(stderr, "Failed to read file %s. %d out of %d bytes.\n", |
||||
argv[1], r, len); |
||||
fclose(f); |
||||
free(buffer); |
||||
return 1; |
||||
} |
||||
fclose(f); |
||||
f = NULL; |
||||
if(argc > 2) { |
||||
f = fopen(argv[2], "r"); |
||||
if(!f) { |
||||
fprintf(stderr, "Cannot open %s for reading.\n", argv[2]); |
||||
free(buffer); |
||||
return 1; |
||||
} |
||||
} |
||||
r = test_igd_desc_parse(buffer, len, f); |
||||
free(buffer); |
||||
if(f) |
||||
fclose(f); |
||||
return r; |
||||
} |
||||
|
||||
@ -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.13 2015/09/03 17:57:44 nanard Exp $ |
||||
# project miniupnp : http://miniupnp.free.fr/ |
||||
# (c) 2011-2015 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 -t 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,89 @@
|
||||
/* $Id: testminixml.c,v 1.10 2014/11/17 17:19:13 nanard Exp $
|
||||
* MiniUPnP project |
||||
* Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard. |
||||
* Copyright (c) 2005-2014 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); |
||||
#ifdef DEBUG |
||||
printIGD(&data); |
||||
#endif /* DEBUG */ |
||||
} |
||||
|
||||
/* ----- 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,151 @@
|
||||
/* $Id: testportlistingparse.c,v 1.2 2014/11/01 10:37:32 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2014 Thomas Bernard |
||||
* This software is subject to the conditions detailed in the |
||||
* LICENCE file provided in this distribution. |
||||
* */ |
||||
|
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include "portlistingparse.h" |
||||
|
||||
struct port_mapping { |
||||
unsigned int leasetime; |
||||
unsigned short externalport; |
||||
unsigned short internalport; |
||||
const char * remotehost; |
||||
const char * client; |
||||
const char * proto; |
||||
const char * desc; |
||||
unsigned char enabled; |
||||
}; |
||||
|
||||
/* return the number of differences */ |
||||
int test(const char * portListingXml, int portListingXmlLen, |
||||
const struct port_mapping * ref, int count) |
||||
{ |
||||
int i; |
||||
int r = 0; |
||||
struct PortMappingParserData data; |
||||
struct PortMapping * pm; |
||||
|
||||
memset(&data, 0, sizeof(data)); |
||||
ParsePortListing(portListingXml, portListingXmlLen, &data); |
||||
for(i = 0, pm = data.l_head; |
||||
(pm != NULL) && (i < count); |
||||
i++, pm = pm->l_next) { |
||||
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", |
||||
i, pm->protocol, pm->externalPort, pm->internalClient, |
||||
pm->internalPort, |
||||
pm->description, pm->remoteHost, |
||||
(unsigned)pm->leaseTime); |
||||
if(0 != strcmp(pm->protocol, ref[i].proto)) { |
||||
printf("protocol : '%s' != '%s'\n", pm->protocol, ref[i].proto); |
||||
r++; |
||||
} |
||||
if(pm->externalPort != ref[i].externalport) { |
||||
printf("externalPort : %hu != %hu\n", |
||||
pm->externalPort, ref[i].externalport); |
||||
r++; |
||||
} |
||||
if(0 != strcmp(pm->internalClient, ref[i].client)) { |
||||
printf("client : '%s' != '%s'\n", |
||||
pm->internalClient, ref[i].client); |
||||
r++; |
||||
} |
||||
if(pm->internalPort != ref[i].internalport) { |
||||
printf("internalPort : %hu != %hu\n", |
||||
pm->internalPort, ref[i].internalport); |
||||
r++; |
||||
} |
||||
if(0 != strcmp(pm->description, ref[i].desc)) { |
||||
printf("description : '%s' != '%s'\n", |
||||
pm->description, ref[i].desc); |
||||
r++; |
||||
} |
||||
if(0 != strcmp(pm->remoteHost, ref[i].remotehost)) { |
||||
printf("remoteHost : '%s' != '%s'\n", |
||||
pm->remoteHost, ref[i].remotehost); |
||||
r++; |
||||
} |
||||
if((unsigned)pm->leaseTime != ref[i].leasetime) { |
||||
printf("leaseTime : %u != %u\n", |
||||
(unsigned)pm->leaseTime, ref[i].leasetime); |
||||
r++; |
||||
} |
||||
if(pm->enabled != ref[i].enabled) { |
||||
printf("enabled : %d != %d\n", |
||||
(int)pm->enabled, (int)ref[i].enabled); |
||||
r++; |
||||
} |
||||
} |
||||
if((i != count) || (pm != NULL)) { |
||||
printf("count mismatch : i=%d count=%d pm=%p\n", i, count, pm); |
||||
r++; |
||||
} |
||||
FreePortListing(&data); |
||||
return r; |
||||
} |
||||
|
||||
const char test_document[] = |
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" |
||||
"<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\"\n" |
||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n" |
||||
"xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection " |
||||
"http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">\n" |
||||
" <p:PortMappingEntry>\n" |
||||
" <p:NewRemoteHost></p:NewRemoteHost>\n" |
||||
" <p:NewExternalPort>5002</p:NewExternalPort>\n" |
||||
" <p:NewProtocol>UDP</p:NewProtocol>\n" |
||||
" <p:NewInternalPort>4001</p:NewInternalPort>\n" |
||||
" <p:NewInternalClient>192.168.1.123</p:NewInternalClient>\n" |
||||
" <p:NewEnabled>1</p:NewEnabled>\n" |
||||
" <p:NewDescription>xxx</p:NewDescription>\n" |
||||
" <p:NewLeaseTime>0</p:NewLeaseTime>\n" |
||||
" </p:PortMappingEntry>\n" |
||||
" <p:PortMappingEntry>\n" |
||||
" <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>\n" |
||||
" <p:NewExternalPort>2345</p:NewExternalPort>\n" |
||||
" <p:NewProtocol>TCP</p:NewProtocol>\n" |
||||
" <p:NewInternalPort>2349</p:NewInternalPort>\n" |
||||
" <p:NewInternalClient>192.168.1.137</p:NewInternalClient>\n" |
||||
" <p:NewEnabled>1</p:NewEnabled>\n" |
||||
" <p:NewDescription>dooom</p:NewDescription>\n" |
||||
" <p:NewLeaseTime>346</p:NewLeaseTime>\n" |
||||
" </p:PortMappingEntry>\n" |
||||
" <p:PortMappingEntry>\n" |
||||
" <p:NewRemoteHost>134.231.2.11</p:NewRemoteHost>\n" |
||||
" <p:NewExternalPort>12345</p:NewExternalPort>\n" |
||||
" <p:NewProtocol>TCP</p:NewProtocol>\n" |
||||
" <p:NewInternalPort>12345</p:NewInternalPort>\n" |
||||
" <p:NewInternalClient>192.168.1.137</p:NewInternalClient>\n" |
||||
" <p:NewEnabled>1</p:NewEnabled>\n" |
||||
" <p:NewDescription>dooom A</p:NewDescription>\n" |
||||
" <p:NewLeaseTime>347</p:NewLeaseTime>\n" |
||||
" </p:PortMappingEntry>\n" |
||||
"</p:PortMappingList>"; |
||||
|
||||
#define PORT_MAPPINGS_COUNT 3 |
||||
const struct port_mapping port_mappings[PORT_MAPPINGS_COUNT] = { |
||||
{347, 12345, 12345, "134.231.2.11", "192.168.1.137", "TCP", "dooom A", 1}, |
||||
{346, 2345, 2349, "202.233.2.1", "192.168.1.137", "TCP", "dooom", 1}, |
||||
{0, 5002, 4001, "", "192.168.1.123", "UDP", "xxx", 1} |
||||
}; |
||||
|
||||
/* --- main --- */ |
||||
int main(void) |
||||
{ |
||||
int r; |
||||
r = test(test_document, sizeof(test_document) - 1, |
||||
port_mappings, PORT_MAPPINGS_COUNT); |
||||
if(r == 0) { |
||||
printf("test of portlistingparse OK\n"); |
||||
return 0; |
||||
} else { |
||||
printf("test FAILED (%d differences counted)\n", r); |
||||
return 1; |
||||
} |
||||
} |
||||
|
||||
@ -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> |
||||
|
||||
@ -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> |
||||
|
||||
@ -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,833 @@
|
||||
/* $Id: upnpc.c,v 1.112 2015/10/08 16:15:48 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subject to the conditions detailed in the |
||||
* LICENCE file provided in this distribution. */ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <time.h> |
||||
#ifdef _WIN32 |
||||
#include <winsock2.h> |
||||
#define snprintf _snprintf |
||||
#else |
||||
/* for IPPROTO_TCP / IPPROTO_UDP */ |
||||
#include <netinet/in.h> |
||||
#endif |
||||
#include <ctype.h> |
||||
#include "miniwget.h" |
||||
#include "miniupnpc.h" |
||||
#include "upnpcommands.h" |
||||
#include "upnperrors.h" |
||||
#include "miniupnpcstrings.h" |
||||
|
||||
/* protofix() checks if protocol is "UDP" or "TCP"
|
||||
* returns NULL if not */ |
||||
const char * protofix(const char * proto) |
||||
{ |
||||
static const char proto_tcp[4] = { 'T', 'C', 'P', 0}; |
||||
static const char proto_udp[4] = { 'U', 'D', 'P', 0}; |
||||
int i, b; |
||||
for(i=0, b=1; i<4; i++) |
||||
b = b && ( (proto[i] == proto_tcp[i]) |
||||
|| (proto[i] == (proto_tcp[i] | 32)) ); |
||||
if(b) |
||||
return proto_tcp; |
||||
for(i=0, b=1; i<4; i++) |
||||
b = b && ( (proto[i] == proto_udp[i]) |
||||
|| (proto[i] == (proto_udp[i] | 32)) ); |
||||
if(b) |
||||
return proto_udp; |
||||
return 0; |
||||
} |
||||
|
||||
/* is_int() checks if parameter is an integer or not
|
||||
* 1 for integer |
||||
* 0 for not an integer */ |
||||
int is_int(char const* s) |
||||
{ |
||||
if(s == NULL) |
||||
return 0; |
||||
while(*s) { |
||||
/* #define isdigit(c) ((c) >= '0' && (c) <= '9') */ |
||||
if(!isdigit(*s)) |
||||
return 0; |
||||
s++; |
||||
} |
||||
return 1; |
||||
} |
||||
|
||||
static void DisplayInfos(struct UPNPUrls * urls, |
||||
struct IGDdatas * data) |
||||
{ |
||||
char externalIPAddress[40]; |
||||
char connectionType[64]; |
||||
char status[64]; |
||||
char lastconnerr[64]; |
||||
unsigned int uptime; |
||||
unsigned int 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.l_head; pm != NULL; pm = pm->l_next) |
||||
{ |
||||
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", |
||||
i, pm->protocol, pm->externalPort, pm->internalClient, |
||||
pm->internalPort, |
||||
pm->description, pm->remoteHost, |
||||
(unsigned)pm->leaseTime); |
||||
i++; |
||||
} |
||||
FreePortListing(&pdata); |
||||
} |
||||
else |
||||
{ |
||||
printf("GetListOfPortMappings() returned %d (%s)\n", |
||||
r, strupnperror(r)); |
||||
} |
||||
r = UPNP_GetListOfPortMappings(urls->controlURL, |
||||
data->first.servicetype, |
||||
"0", |
||||
"65535", |
||||
"UDP", |
||||
"1000", |
||||
&pdata); |
||||
if(r == UPNPCOMMAND_SUCCESS) |
||||
{ |
||||
for(pm = pdata.l_head; pm != NULL; pm = pm->l_next) |
||||
{ |
||||
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", |
||||
i, pm->protocol, pm->externalPort, pm->internalClient, |
||||
pm->internalPort, |
||||
pm->description, pm->remoteHost, |
||||
(unsigned)pm->leaseTime); |
||||
i++; |
||||
} |
||||
FreePortListing(&pdata); |
||||
} |
||||
else |
||||
{ |
||||
printf("GetListOfPortMappings() returned %d (%s)\n", |
||||
r, strupnperror(r)); |
||||
} |
||||
} |
||||
|
||||
/* Test function
|
||||
* 1 - get connection type |
||||
* 2 - get extenal ip address |
||||
* 3 - Add port mapping |
||||
* 4 - get this port mapping from the IGD */ |
||||
static void SetRedirectAndTest(struct UPNPUrls * urls, |
||||
struct IGDdatas * data, |
||||
const char * iaddr, |
||||
const char * iport, |
||||
const char * eport, |
||||
const char * proto, |
||||
const char * leaseDuration, |
||||
const char * description, |
||||
int addAny) |
||||
{ |
||||
char externalIPAddress[40]; |
||||
char intClient[40]; |
||||
char intPort[6]; |
||||
char reservedPort[6]; |
||||
char duration[16]; |
||||
int r; |
||||
|
||||
if(!iaddr || !iport || !eport || !proto) |
||||
{ |
||||
fprintf(stderr, "Wrong arguments\n"); |
||||
return; |
||||
} |
||||
proto = protofix(proto); |
||||
if(!proto) |
||||
{ |
||||
fprintf(stderr, "invalid protocol\n"); |
||||
return; |
||||
} |
||||
|
||||
r = UPNP_GetExternalIPAddress(urls->controlURL, |
||||
data->first.servicetype, |
||||
externalIPAddress); |
||||
if(r!=UPNPCOMMAND_SUCCESS) |
||||
printf("GetExternalIPAddress failed.\n"); |
||||
else |
||||
printf("ExternalIPAddress = %s\n", externalIPAddress); |
||||
|
||||
if (addAny) { |
||||
r = UPNP_AddAnyPortMapping(urls->controlURL, data->first.servicetype, |
||||
eport, iport, iaddr, description, |
||||
proto, 0, leaseDuration, reservedPort); |
||||
if(r==UPNPCOMMAND_SUCCESS) |
||||
eport = reservedPort; |
||||
else |
||||
printf("AddAnyPortMapping(%s, %s, %s) failed with code %d (%s)\n", |
||||
eport, iport, iaddr, r, strupnperror(r)); |
||||
} else { |
||||
r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, |
||||
eport, iport, iaddr, description, |
||||
proto, 0, leaseDuration); |
||||
if(r!=UPNPCOMMAND_SUCCESS) |
||||
printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", |
||||
eport, iport, iaddr, r, strupnperror(r)); |
||||
} |
||||
|
||||
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)); |
||||
else { |
||||
printf("InternalIP:Port = %s:%s\n", intClient, intPort); |
||||
printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n", |
||||
externalIPAddress, eport, proto, intClient, intPort, duration); |
||||
} |
||||
} |
||||
|
||||
static void |
||||
RemoveRedirect(struct UPNPUrls * urls, |
||||
struct IGDdatas * data, |
||||
const char * eport, |
||||
const char * proto, |
||||
const char * remoteHost) |
||||
{ |
||||
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, remoteHost); |
||||
printf("UPNP_DeletePortMapping() returned : %d\n", r); |
||||
} |
||||
|
||||
static void |
||||
RemoveRedirectRange(struct UPNPUrls * urls, |
||||
struct IGDdatas * data, |
||||
const char * ePortStart, char const * ePortEnd, |
||||
const char * proto, const char * manage) |
||||
{ |
||||
int r; |
||||
|
||||
if (!manage) |
||||
manage = "0"; |
||||
|
||||
if(!proto || !ePortStart || !ePortEnd) |
||||
{ |
||||
fprintf(stderr, "invalid arguments\n"); |
||||
return; |
||||
} |
||||
proto = protofix(proto); |
||||
if(!proto) |
||||
{ |
||||
fprintf(stderr, "protocol invalid\n"); |
||||
return; |
||||
} |
||||
r = UPNP_DeletePortMappingRange(urls->controlURL, data->first.servicetype, ePortStart, ePortEnd, proto, manage); |
||||
printf("UPNP_DeletePortMappingRange() 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 localport = UPNP_LOCAL_PORT_ANY; |
||||
int retcode = 0; |
||||
int error = 0; |
||||
int ipv6 = 0; |
||||
unsigned char ttl = 2; /* defaulting to 2 */ |
||||
const char * description = 0; |
||||
|
||||
#ifdef _WIN32 |
||||
WSADATA wsaData; |
||||
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); |
||||
if(nResult != NO_ERROR) |
||||
{ |
||||
fprintf(stderr, "WSAStartup() failed.\n"); |
||||
return -1; |
||||
} |
||||
#endif |
||||
printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING); |
||||
printf(" (c) 2005-2015 Thomas Bernard.\n"); |
||||
printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n" |
||||
"for more information.\n"); |
||||
/* command line processing */ |
||||
for(i=1; i<argc; i++) |
||||
{ |
||||
if(0 == strcmp(argv[i], "--help") || 0 == strcmp(argv[i], "-h")) |
||||
{ |
||||
command = 0; |
||||
break; |
||||
} |
||||
if(argv[i][0] == '-') |
||||
{ |
||||
if(argv[i][1] == 'u') |
||||
rootdescurl = argv[++i]; |
||||
else if(argv[i][1] == 'm') |
||||
multicastif = argv[++i]; |
||||
else if(argv[i][1] == 'z') |
||||
{ |
||||
char junk; |
||||
if(sscanf(argv[++i], "%d%c", &localport, &junk)!=1 || |
||||
localport<0 || localport>65535 || |
||||
(localport >1 && localport < 1024)) |
||||
{ |
||||
fprintf(stderr, "Invalid localport '%s'\n", argv[i]); |
||||
localport = UPNP_LOCAL_PORT_ANY; |
||||
break; |
||||
} |
||||
} |
||||
else if(argv[i][1] == 'p') |
||||
minissdpdpath = argv[++i]; |
||||
else if(argv[i][1] == '6') |
||||
ipv6 = 1; |
||||
else if(argv[i][1] == 'e') |
||||
description = argv[++i]; |
||||
else if(argv[i][1] == 't') |
||||
ttl = (unsigned char)atoi(argv[++i]); |
||||
else |
||||
{ |
||||
command = argv[i][1]; |
||||
i++; |
||||
commandargv = argv + i; |
||||
commandargc = argc - i; |
||||
break; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
fprintf(stderr, "option '%s' invalid\n", argv[i]); |
||||
} |
||||
} |
||||
|
||||
if(!command |
||||
|| (command == 'a' && commandargc<4) |
||||
|| (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 <remote host>\n\t\tDelete port redirection\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -n ip port external_port protocol [duration]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port redirections (for IGD:2 only)\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -r port1 [external_port1] protocol1 [port2 [external_port2] protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -G remote_ip remote_port internal_ip internal_port protocol\n\t\tGet Outbound Pinhole Timeout (for IGD:2 only)\n", argv[0]); |
||||
fprintf(stderr, " \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]); |
||||
fprintf(stderr, "\nprotocol is UDP or TCP\n"); |
||||
fprintf(stderr, "Options:\n"); |
||||
fprintf(stderr, " -e description : set description for port mapping.\n"); |
||||
fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n"); |
||||
fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n"); |
||||
fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n"); |
||||
fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n"); |
||||
fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n"); |
||||
fprintf(stderr, " -t ttl : set multicast TTL. Default value is 2.\n"); |
||||
return 1; |
||||
} |
||||
|
||||
if( rootdescurl |
||||
|| (devlist = upnpDiscover(2000, multicastif, minissdpdpath, |
||||
localport, ipv6, ttl, &error))) |
||||
{ |
||||
struct UPNPDev * device; |
||||
struct UPNPUrls urls; |
||||
struct IGDdatas data; |
||||
if(devlist) |
||||
{ |
||||
printf("List of UPNP devices found on the network :\n"); |
||||
for(device = devlist; device; device = device->pNext) |
||||
{ |
||||
printf(" desc: %s\n st: %s\n\n", |
||||
device->descURL, device->st); |
||||
} |
||||
} |
||||
else if(!rootdescurl) |
||||
{ |
||||
printf("upnpDiscover() error code=%d\n", error); |
||||
} |
||||
i = 1; |
||||
if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr))) |
||||
|| (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))) |
||||
{ |
||||
switch(i) { |
||||
case 1: |
||||
printf("Found valid IGD : %s\n", urls.controlURL); |
||||
break; |
||||
case 2: |
||||
printf("Found a (not connected?) IGD : %s\n", urls.controlURL); |
||||
printf("Trying to continue anyway\n"); |
||||
break; |
||||
case 3: |
||||
printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL); |
||||
printf("Trying to continue anyway\n"); |
||||
break; |
||||
default: |
||||
printf("Found device (igd ?) : %s\n", urls.controlURL); |
||||
printf("Trying to continue anyway\n"); |
||||
} |
||||
printf("Local LAN ip address : %s\n", lanaddr); |
||||
#if 0 |
||||
printf("getting \"%s\"\n", urls.ipcondescURL); |
||||
descXML = miniwget(urls.ipcondescURL, &descXMLsize); |
||||
if(descXML) |
||||
{ |
||||
/*fwrite(descXML, 1, descXMLsize, stdout);*/ |
||||
free(descXML); descXML = NULL; |
||||
} |
||||
#endif |
||||
|
||||
switch(command) |
||||
{ |
||||
case 'l': |
||||
DisplayInfos(&urls, &data); |
||||
ListRedirections(&urls, &data); |
||||
break; |
||||
case 'L': |
||||
NewListRedirections(&urls, &data); |
||||
break; |
||||
case 'a': |
||||
SetRedirectAndTest(&urls, &data, |
||||
commandargv[0], commandargv[1], |
||||
commandargv[2], commandargv[3], |
||||
(commandargc > 4)?commandargv[4]:"0", |
||||
description, 0); |
||||
break; |
||||
case 'd': |
||||
RemoveRedirect(&urls, &data, commandargv[0], commandargv[1], |
||||
commandargc > 2 ? commandargv[2] : NULL); |
||||
break; |
||||
case 'n': /* aNy */ |
||||
SetRedirectAndTest(&urls, &data, |
||||
commandargv[0], commandargv[1], |
||||
commandargv[2], commandargv[3], |
||||
(commandargc > 4)?commandargv[4]:"0", |
||||
description, 1); |
||||
break; |
||||
case 'N': |
||||
if (commandargc < 3) |
||||
fprintf(stderr, "too few arguments\n"); |
||||
|
||||
RemoveRedirectRange(&urls, &data, commandargv[0], commandargv[1], commandargv[2], |
||||
commandargc > 3 ? commandargv[3] : NULL); |
||||
break; |
||||
case 's': |
||||
GetConnectionStatus(&urls, &data); |
||||
break; |
||||
case 'r': |
||||
i = 0; |
||||
while(i<commandargc) |
||||
{ |
||||
if(!is_int(commandargv[i])) { |
||||
/* 1st parameter not an integer : error */ |
||||
fprintf(stderr, "command -r : %s is not an port number\n", commandargv[i]); |
||||
retcode = 1; |
||||
break; |
||||
} else if(is_int(commandargv[i+1])){ |
||||
/* 2nd parameter is an integer : <port> <external_port> <protocol> */ |
||||
SetRedirectAndTest(&urls, &data, |
||||
lanaddr, commandargv[i], |
||||
commandargv[i+1], commandargv[i+2], "0", |
||||
description, 0); |
||||
i+=3; /* 3 parameters parsed */ |
||||
} else { |
||||
/* 2nd parameter not an integer : <port> <protocol> */ |
||||
SetRedirectAndTest(&urls, &data, |
||||
lanaddr, commandargv[i], |
||||
commandargv[i], commandargv[i+1], "0", |
||||
description, 0); |
||||
i+=2; /* 2 parameters parsed */ |
||||
} |
||||
} |
||||
break; |
||||
case 'A': |
||||
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; |
||||
} |
||||
#ifdef _WIN32 |
||||
nResult = WSACleanup(); |
||||
if(nResult != NO_ERROR) { |
||||
fprintf(stderr, "WSACleanup() failed.\n"); |
||||
} |
||||
#endif /* _WIN32 */ |
||||
return retcode; |
||||
} |
||||
|
||||
@ -0,0 +1,348 @@
|
||||
/* $Id: upnpcommands.h,v 1.31 2015/07/21 13:16:55 nanard Exp $ */ |
||||
/* Miniupnp project : http://miniupnp.free.fr/
|
||||
* Author : Thomas Bernard |
||||
* Copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subject to the conditions detailed in the |
||||
* LICENCE file provided within this distribution */ |
||||
#ifndef UPNPCOMMANDS_H_INCLUDED |
||||
#define UPNPCOMMANDS_H_INCLUDED |
||||
|
||||
#include "upnpreplyparse.h" |
||||
#include "portlistingparse.h" |
||||
#include "miniupnpc_declspec.h" |
||||
#include "miniupnpctypes.h" |
||||
|
||||
/* MiniUPnPc return codes : */ |
||||
#define UPNPCOMMAND_SUCCESS (0) |
||||
#define UPNPCOMMAND_UNKNOWN_ERROR (-1) |
||||
#define UPNPCOMMAND_INVALID_ARGS (-2) |
||||
#define UPNPCOMMAND_HTTP_ERROR (-3) |
||||
#define UPNPCOMMAND_INVALID_RESPONSE (-4) |
||||
#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5) |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER |
||||
UPNP_GetTotalBytesSent(const char * controlURL, |
||||
const char * servicetype); |
||||
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER |
||||
UPNP_GetTotalBytesReceived(const char * controlURL, |
||||
const char * servicetype); |
||||
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER |
||||
UPNP_GetTotalPacketsSent(const char * controlURL, |
||||
const char * servicetype); |
||||
|
||||
MINIUPNP_LIBSPEC UNSIGNED_INTEGER |
||||
UPNP_GetTotalPacketsReceived(const char * controlURL, |
||||
const char * servicetype); |
||||
|
||||
/* UPNP_GetStatusInfo()
|
||||
* status and lastconnerror are 64 byte buffers |
||||
* Return values : |
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR |
||||
* or a UPnP Error code */ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetStatusInfo(const char * controlURL, |
||||
const char * servicetype, |
||||
char * status, |
||||
unsigned int * uptime, |
||||
char * lastconnerror); |
||||
|
||||
/* UPNP_GetConnectionTypeInfo()
|
||||
* argument connectionType is a 64 character buffer |
||||
* Return Values : |
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR |
||||
* or a UPnP Error code */ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetConnectionTypeInfo(const char * controlURL, |
||||
const char * servicetype, |
||||
char * connectionType); |
||||
|
||||
/* UPNP_GetExternalIPAddress() call the corresponding UPNP method.
|
||||
* if the third arg is not null the value is copied to it. |
||||
* at least 16 bytes must be available |
||||
* |
||||
* Return values : |
||||
* 0 : SUCCESS |
||||
* NON ZERO : ERROR Either an UPnP error code or an unknown error. |
||||
* |
||||
* possible UPnP Errors : |
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control. |
||||
* 501 Action Failed - See UPnP Device Architecture section on Control. */ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetExternalIPAddress(const char * controlURL, |
||||
const char * servicetype, |
||||
char * extIpAdd); |
||||
|
||||
/* UPNP_GetLinkLayerMaxBitRates()
|
||||
* call WANCommonInterfaceConfig:1#GetCommonLinkProperties |
||||
* |
||||
* return values : |
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR |
||||
* or a UPnP Error Code. */ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetLinkLayerMaxBitRates(const char* controlURL, |
||||
const char* servicetype, |
||||
unsigned int * bitrateDown, |
||||
unsigned int * bitrateUp); |
||||
|
||||
/* UPNP_AddPortMapping()
|
||||
* if desc is NULL, it will be defaulted to "libminiupnpc" |
||||
* remoteHost is usually NULL because IGD don't support it. |
||||
* |
||||
* Return values : |
||||
* 0 : SUCCESS |
||||
* NON ZERO : ERROR. Either an UPnP error code or an unknown error. |
||||
* |
||||
* List of possible UPnP errors for AddPortMapping : |
||||
* errorCode errorDescription (short) - Description (long) |
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control. |
||||
* 501 Action Failed - See UPnP Device Architecture section on Control. |
||||
* 606 Action not authorized - The action requested REQUIRES authorization and |
||||
* the sender was not authorized. |
||||
* 715 WildCardNotPermittedInSrcIP - The source IP address cannot be |
||||
* wild-carded |
||||
* 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded |
||||
* 718 ConflictInMappingEntry - The port mapping entry specified conflicts |
||||
* with a mapping assigned previously to another client |
||||
* 724 SamePortValuesRequired - Internal and External port values |
||||
* must be the same |
||||
* 725 OnlyPermanentLeasesSupported - The NAT implementation only supports |
||||
* permanent lease times on port mappings |
||||
* 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard |
||||
* and cannot be a specific IP address or DNS name |
||||
* 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and |
||||
* cannot be a specific port value |
||||
* 728 NoPortMapsAvailable - There are not enough free ports available to |
||||
* complete port mapping. |
||||
* 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed |
||||
* due to conflict with other mechanisms. |
||||
* 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded |
||||
*/ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_AddPortMapping(const char * controlURL, const char * servicetype, |
||||
const char * extPort, |
||||
const char * inPort, |
||||
const char * inClient, |
||||
const char * desc, |
||||
const char * proto, |
||||
const char * remoteHost, |
||||
const char * leaseDuration); |
||||
|
||||
/* UPNP_AddAnyPortMapping()
|
||||
* if desc is NULL, it will be defaulted to "libminiupnpc" |
||||
* remoteHost is usually NULL because IGD don't support it. |
||||
* |
||||
* Return values : |
||||
* 0 : SUCCESS |
||||
* NON ZERO : ERROR. Either an UPnP error code or an unknown error. |
||||
* |
||||
* List of possible UPnP errors for AddPortMapping : |
||||
* errorCode errorDescription (short) - Description (long) |
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control. |
||||
* 501 Action Failed - See UPnP Device Architecture section on Control. |
||||
* 606 Action not authorized - The action requested REQUIRES authorization and |
||||
* the sender was not authorized. |
||||
* 715 WildCardNotPermittedInSrcIP - The source IP address cannot be |
||||
* wild-carded |
||||
* 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded |
||||
* 728 NoPortMapsAvailable - There are not enough free ports available to |
||||
* complete port mapping. |
||||
* 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed |
||||
* due to conflict with other mechanisms. |
||||
* 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded |
||||
*/ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, |
||||
const char * extPort, |
||||
const char * inPort, |
||||
const char * inClient, |
||||
const char * desc, |
||||
const char * proto, |
||||
const char * remoteHost, |
||||
const char * leaseDuration, |
||||
char * reservedPort); |
||||
|
||||
/* UPNP_DeletePortMapping()
|
||||
* Use same argument values as what was used for AddPortMapping(). |
||||
* remoteHost is usually NULL because IGD don't support it. |
||||
* Return Values : |
||||
* 0 : SUCCESS |
||||
* NON ZERO : error. Either an UPnP error code or an undefined error. |
||||
* |
||||
* List of possible UPnP errors for DeletePortMapping : |
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control. |
||||
* 606 Action not authorized - The action requested REQUIRES authorization |
||||
* and the sender was not authorized. |
||||
* 714 NoSuchEntryInArray - The specified value does not exist in the array */ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, |
||||
const char * extPort, const char * proto, |
||||
const char * remoteHost); |
||||
|
||||
/* UPNP_DeletePortRangeMapping()
|
||||
* Use same argument values as what was used for AddPortMapping(). |
||||
* remoteHost is usually NULL because IGD don't support it. |
||||
* Return Values : |
||||
* 0 : SUCCESS |
||||
* NON ZERO : error. Either an UPnP error code or an undefined error. |
||||
* |
||||
* List of possible UPnP errors for DeletePortMapping : |
||||
* 606 Action not authorized - The action requested REQUIRES authorization |
||||
* and the sender was not authorized. |
||||
* 730 PortMappingNotFound - This error message is returned if no port |
||||
* mapping is found in the specified range. |
||||
* 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, |
||||
const char * extPortStart, const char * extPortEnd, |
||||
const char * proto, |
||||
const char * manage); |
||||
|
||||
/* UPNP_GetPortMappingNumberOfEntries()
|
||||
* not supported by all routers */ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetPortMappingNumberOfEntries(const char* controlURL, |
||||
const char* servicetype, |
||||
unsigned int * num); |
||||
|
||||
/* UPNP_GetSpecificPortMappingEntry()
|
||||
* retrieves an existing port mapping |
||||
* params : |
||||
* in extPort |
||||
* in proto |
||||
* in remoteHost |
||||
* out intClient (16 bytes) |
||||
* out intPort (6 bytes) |
||||
* out desc (80 bytes) |
||||
* out enabled (4 bytes) |
||||
* out leaseDuration (16 bytes) |
||||
* |
||||
* return value : |
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR |
||||
* or a UPnP Error Code. |
||||
* |
||||
* List of possible UPnP errors for _GetSpecificPortMappingEntry : |
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control. |
||||
* 501 Action Failed - See UPnP Device Architecture section on Control. |
||||
* 606 Action not authorized - The action requested REQUIRES authorization |
||||
* and the sender was not authorized. |
||||
* 714 NoSuchEntryInArray - The specified value does not exist in the array. |
||||
*/ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetSpecificPortMappingEntry(const char * controlURL, |
||||
const char * servicetype, |
||||
const char * extPort, |
||||
const char * proto, |
||||
const char * remoteHost, |
||||
char * intClient, |
||||
char * intPort, |
||||
char * desc, |
||||
char * enabled, |
||||
char * leaseDuration); |
||||
|
||||
/* UPNP_GetGenericPortMappingEntry()
|
||||
* params : |
||||
* in index |
||||
* out extPort (6 bytes) |
||||
* out intClient (16 bytes) |
||||
* out intPort (6 bytes) |
||||
* out protocol (4 bytes) |
||||
* out desc (80 bytes) |
||||
* out enabled (4 bytes) |
||||
* out rHost (64 bytes) |
||||
* out duration (16 bytes) |
||||
* |
||||
* return value : |
||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR |
||||
* or a UPnP Error Code. |
||||
* |
||||
* Possible UPNP Error codes : |
||||
* 402 Invalid Args - See UPnP Device Architecture section on Control. |
||||
* 606 Action not authorized - The action requested REQUIRES authorization |
||||
* and the sender was not authorized. |
||||
* 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds |
||||
*/ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetGenericPortMappingEntry(const char * controlURL, |
||||
const char * servicetype, |
||||
const char * index, |
||||
char * extPort, |
||||
char * intClient, |
||||
char * intPort, |
||||
char * protocol, |
||||
char * desc, |
||||
char * enabled, |
||||
char * rHost, |
||||
char * duration); |
||||
|
||||
/* UPNP_GetListOfPortMappings() Available in IGD v2
|
||||
* |
||||
* |
||||
* Possible UPNP Error codes : |
||||
* 606 Action not Authorized |
||||
* 730 PortMappingNotFound - no port mapping is found in the specified range. |
||||
* 733 InconsistantParameters - NewStartPort and NewEndPort values are not |
||||
* consistent. |
||||
*/ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetListOfPortMappings(const char * controlURL, |
||||
const char * servicetype, |
||||
const char * startPort, |
||||
const char * endPort, |
||||
const char * protocol, |
||||
const char * numberOfPorts, |
||||
struct PortMappingParserData * data); |
||||
|
||||
/* IGD:2, functions for service WANIPv6FirewallControl:1 */ |
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetFirewallStatus(const char * controlURL, |
||||
const char * servicetype, |
||||
int * firewallEnabled, |
||||
int * inboundPinholeAllowed); |
||||
|
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, |
||||
const char * remoteHost, |
||||
const char * remotePort, |
||||
const char * intClient, |
||||
const char * intPort, |
||||
const char * proto, |
||||
int * opTimeout); |
||||
|
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_AddPinhole(const char * controlURL, const char * servicetype, |
||||
const char * remoteHost, |
||||
const char * remotePort, |
||||
const char * intClient, |
||||
const char * intPort, |
||||
const char * proto, |
||||
const char * leaseTime, |
||||
char * uniqueID); |
||||
|
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, |
||||
const char * uniqueID, |
||||
const char * leaseTime); |
||||
|
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); |
||||
|
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, |
||||
const char * uniqueID, int * isWorking); |
||||
|
||||
MINIUPNP_LIBSPEC int |
||||
UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, |
||||
const char * uniqueID, int * packets); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
||||
|
||||
@ -0,0 +1,23 @@
|
||||
/* $Id: upnpdev.c,v 1.1 2015/08/28 12:14:19 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD |
||||
* copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subjet to the conditions detailed in the |
||||
* provided LICENSE file. */ |
||||
#include <stdlib.h> |
||||
#include "upnpdev.h" |
||||
|
||||
/* freeUPNPDevlist() should be used to
|
||||
* free the chained list returned by upnpDiscover() */ |
||||
void freeUPNPDevlist(struct UPNPDev * devlist) |
||||
{ |
||||
struct UPNPDev * next; |
||||
while(devlist) |
||||
{ |
||||
next = devlist->pNext; |
||||
free(devlist); |
||||
devlist = next; |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,36 @@
|
||||
/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* Web : http://miniupnp.free.fr/
|
||||
* Author : Thomas BERNARD |
||||
* copyright (c) 2005-2015 Thomas Bernard |
||||
* This software is subjet to the conditions detailed in the |
||||
* provided LICENSE file. */ |
||||
#ifndef UPNPDEV_H_INCLUDED |
||||
#define UPNPDEV_H_INCLUDED |
||||
|
||||
#include "miniupnpc_declspec.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
struct UPNPDev { |
||||
struct UPNPDev * pNext; |
||||
char * descURL; |
||||
char * st; |
||||
unsigned int scope_id; |
||||
char * usn; |
||||
char buffer[3]; |
||||
}; |
||||
|
||||
/* freeUPNPDevlist()
|
||||
* free list returned by upnpDiscover() */ |
||||
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); |
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
|
||||
#endif /* UPNPDEV_H_INCLUDED */ |
||||
@ -0,0 +1,107 @@
|
||||
/* $Id: upnperrors.c,v 1.8 2014/06/10 09:41:48 nanard Exp $ */ |
||||
/* Project : miniupnp
|
||||
* Author : Thomas BERNARD |
||||
* copyright (c) 2007 Thomas Bernard |
||||
* All Right reserved. |
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* This software is subjet to the conditions detailed in the |
||||
* provided LICENCE file. */ |
||||
#include <string.h> |
||||
#include "upnperrors.h" |
||||
#include "upnpcommands.h" |
||||
#include "miniupnpc.h" |
||||
|
||||
const char * strupnperror(int err) |
||||
{ |
||||
const char * s = NULL; |
||||
switch(err) { |
||||
case UPNPCOMMAND_SUCCESS: |
||||
s = "Success"; |
||||
break; |
||||
case UPNPCOMMAND_UNKNOWN_ERROR: |
||||
s = "Miniupnpc Unknown Error"; |
||||
break; |
||||
case UPNPCOMMAND_INVALID_ARGS: |
||||
s = "Miniupnpc Invalid Arguments"; |
||||
break; |
||||
case UPNPCOMMAND_INVALID_RESPONSE: |
||||
s = "Miniupnpc Invalid response"; |
||||
break; |
||||
case UPNPDISCOVER_SOCKET_ERROR: |
||||
s = "Miniupnpc Socket error"; |
||||
break; |
||||
case UPNPDISCOVER_MEMORY_ERROR: |
||||
s = "Miniupnpc Memory allocation error"; |
||||
break; |
||||
case 401: |
||||
s = "Invalid Action"; |
||||
break; |
||||
case 402: |
||||
s = "Invalid Args"; |
||||
break; |
||||
case 501: |
||||
s = "Action Failed"; |
||||
break; |
||||
case 606: |
||||
s = "Action not authorized"; |
||||
break; |
||||
case 701: |
||||
s = "PinholeSpaceExhausted"; |
||||
break; |
||||
case 702: |
||||
s = "FirewallDisabled"; |
||||
break; |
||||
case 703: |
||||
s = "InboundPinholeNotAllowed"; |
||||
break; |
||||
case 704: |
||||
s = "NoSuchEntry"; |
||||
break; |
||||
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.6 2015/07/21 13:16:55 nanard Exp $ */ |
||||
/* (c) 2007-2015 Thomas Bernard
|
||||
* All rights reserved. |
||||
* MiniUPnP Project. |
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* This software is subjet to the conditions detailed in the |
||||
* provided LICENCE file. */ |
||||
#ifndef UPNPERRORS_H_INCLUDED |
||||
#define UPNPERRORS_H_INCLUDED |
||||
|
||||
#include "miniupnpc_declspec.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/* strupnperror()
|
||||
* Return a string description of the UPnP error code |
||||
* or NULL for undefinded errors */ |
||||
MINIUPNP_LIBSPEC const char * strupnperror(int err); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
||||
@ -0,0 +1,197 @@
|
||||
/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */ |
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2015 Thomas Bernard |
||||
* This software is subject to the conditions detailed |
||||
* in the LICENCE file provided within the distribution */ |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
|
||||
#include "upnpreplyparse.h" |
||||
#include "minixml.h" |
||||
|
||||
static void |
||||
NameValueParserStartElt(void * d, const char * name, int l) |
||||
{ |
||||
struct NameValueParserData * data = (struct NameValueParserData *)d; |
||||
data->topelt = 1; |
||||
if(l>63) |
||||
l = 63; |
||||
memcpy(data->curelt, name, l); |
||||
data->curelt[l] = '\0'; |
||||
data->cdata = NULL; |
||||
data->cdatalen = 0; |
||||
} |
||||
|
||||
static void |
||||
NameValueParserEndElt(void * d, const char * name, int l) |
||||
{ |
||||
struct NameValueParserData * data = (struct NameValueParserData *)d; |
||||
struct NameValue * nv; |
||||
(void)name; |
||||
(void)l; |
||||
if(!data->topelt) |
||||
return; |
||||
if(strcmp(data->curelt, "NewPortListing") != 0) |
||||
{ |
||||
int l; |
||||
/* standard case. Limited to n chars strings */ |
||||
l = data->cdatalen; |
||||
nv = malloc(sizeof(struct NameValue)); |
||||
if(nv == NULL) |
||||
{ |
||||
/* malloc error */ |
||||
#ifdef DEBUG |
||||
fprintf(stderr, "%s: error allocating memory", |
||||
"NameValueParserEndElt"); |
||||
#endif /* DEBUG */ |
||||
return; |
||||
} |
||||
if(l>=(int)sizeof(nv->value)) |
||||
l = sizeof(nv->value) - 1; |
||||
strncpy(nv->name, data->curelt, 64); |
||||
nv->name[63] = '\0'; |
||||
if(data->cdata != NULL) |
||||
{ |
||||
memcpy(nv->value, data->cdata, l); |
||||
nv->value[l] = '\0'; |
||||
} |
||||
else |
||||
{ |
||||
nv->value[0] = '\0'; |
||||
} |
||||
nv->l_next = data->l_head; /* insert in list */ |
||||
data->l_head = nv; |
||||
} |
||||
data->cdata = NULL; |
||||
data->cdatalen = 0; |
||||
data->topelt = 0; |
||||
} |
||||
|
||||
static void |
||||
NameValueParserGetData(void * d, const char * datas, int l) |
||||
{ |
||||
struct NameValueParserData * data = (struct NameValueParserData *)d; |
||||
if(strcmp(data->curelt, "NewPortListing") == 0) |
||||
{ |
||||
/* specific case for NewPortListing which is a XML Document */ |
||||
data->portListing = malloc(l + 1); |
||||
if(!data->portListing) |
||||
{ |
||||
/* malloc error */ |
||||
#ifdef DEBUG |
||||
fprintf(stderr, "%s: error allocating memory", |
||||
"NameValueParserGetData"); |
||||
#endif /* DEBUG */ |
||||
return; |
||||
} |
||||
memcpy(data->portListing, datas, l); |
||||
data->portListing[l] = '\0'; |
||||
data->portListingLength = l; |
||||
} |
||||
else |
||||
{ |
||||
/* standard case. */ |
||||
data->cdata = datas; |
||||
data->cdatalen = l; |
||||
} |
||||
} |
||||
|
||||
void |
||||
ParseNameValue(const char * buffer, int bufsize, |
||||
struct NameValueParserData * data) |
||||
{ |
||||
struct xmlparser parser; |
||||
data->l_head = NULL; |
||||
data->portListing = NULL; |
||||
data->portListingLength = 0; |
||||
/* init xmlparser object */ |
||||
parser.xmlstart = buffer; |
||||
parser.xmlsize = bufsize; |
||||
parser.data = data; |
||||
parser.starteltfunc = NameValueParserStartElt; |
||||
parser.endeltfunc = NameValueParserEndElt; |
||||
parser.datafunc = NameValueParserGetData; |
||||
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->l_head) != NULL) |
||||
{ |
||||
pdata->l_head = nv->l_next; |
||||
free(nv); |
||||
} |
||||
} |
||||
|
||||
char * |
||||
GetValueFromNameValueList(struct NameValueParserData * pdata, |
||||
const char * Name) |
||||
{ |
||||
struct NameValue * nv; |
||||
char * p = NULL; |
||||
for(nv = pdata->l_head; |
||||
(nv != NULL) && (p == NULL); |
||||
nv = nv->l_next) |
||||
{ |
||||
if(strcmp(nv->name, Name) == 0) |
||||
p = nv->value; |
||||
} |
||||
return p; |
||||
} |
||||
|
||||
#if 0 |
||||
/* useless now that minixml ignores namespaces by itself */ |
||||
char * |
||||
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, |
||||
const char * Name) |
||||
{ |
||||
struct NameValue * nv; |
||||
char * p = NULL; |
||||
char * pname; |
||||
for(nv = pdata->head.lh_first; |
||||
(nv != NULL) && (p == NULL); |
||||
nv = nv->entries.le_next) |
||||
{ |
||||
pname = strrchr(nv->name, ':'); |
||||
if(pname) |
||||
pname++; |
||||
else |
||||
pname = nv->name; |
||||
if(strcmp(pname, Name)==0) |
||||
p = nv->value; |
||||
} |
||||
return p; |
||||
} |
||||
#endif |
||||
|
||||
/* debug all-in-one function
|
||||
* do parsing then display to stdout */ |
||||
#ifdef DEBUG |
||||
void |
||||
DisplayNameValueList(char * buffer, int bufsize) |
||||
{ |
||||
struct NameValueParserData pdata; |
||||
struct NameValue * nv; |
||||
ParseNameValue(buffer, bufsize, &pdata); |
||||
for(nv = pdata.l_head; |
||||
nv != NULL; |
||||
nv = nv->l_next) |
||||
{ |
||||
printf("%s = %s\n", nv->name, nv->value); |
||||
} |
||||
ClearNameValueList(&pdata); |
||||
} |
||||
#endif /* DEBUG */ |
||||
|
||||
@ -0,0 +1,63 @@
|
||||
/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */ |
||||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* (c) 2006-2013 Thomas Bernard |
||||
* This software is subject to the conditions detailed |
||||
* in the LICENCE file provided within the distribution */ |
||||
|
||||
#ifndef UPNPREPLYPARSE_H_INCLUDED |
||||
#define UPNPREPLYPARSE_H_INCLUDED |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
struct NameValue { |
||||
struct NameValue * l_next; |
||||
char name[64]; |
||||
char value[128]; |
||||
}; |
||||
|
||||
struct NameValueParserData { |
||||
struct NameValue * l_head; |
||||
char curelt[64]; |
||||
char * portListing; |
||||
int portListingLength; |
||||
int topelt; |
||||
const char * cdata; |
||||
int cdatalen; |
||||
}; |
||||
|
||||
/* ParseNameValue() */ |
||||
void |
||||
ParseNameValue(const char * buffer, int bufsize, |
||||
struct NameValueParserData * data); |
||||
|
||||
/* ClearNameValueList() */ |
||||
void |
||||
ClearNameValueList(struct NameValueParserData * pdata); |
||||
|
||||
/* GetValueFromNameValueList() */ |
||||
char * |
||||
GetValueFromNameValueList(struct NameValueParserData * pdata, |
||||
const char * Name); |
||||
|
||||
#if 0 |
||||
/* GetValueFromNameValueListIgnoreNS() */ |
||||
char * |
||||
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, |
||||
const char * Name); |
||||
#endif |
||||
|
||||
/* DisplayNameValueList() */ |
||||
#ifdef DEBUG |
||||
void |
||||
DisplayNameValueList(char * buffer, int bufsize); |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
||||
|
||||
@ -0,0 +1,83 @@
|
||||
/* $Id: wingenminiupnpcstrings.c,v 1.4 2015/02/08 08:46:06 nanard Exp $ */ |
||||
/* Project: miniupnp
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* Author: Thomas Bernard |
||||
* Copyright (c) 2005-2015 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]); |
||||
fclose(fin); |
||||
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; |
||||
} |
||||
Loading…
Reference in new issue