1
0
Fork 0
forked from lthn/blockchain

Merge branch 'master' into develop

This commit is contained in:
crypro.zoidberg 2019-05-02 20:17:15 +02:00
commit 9c59ff35f7
437 changed files with 40813 additions and 232438 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "contrib/miniupnp"]
path = contrib/miniupnp
url = https://github.com/miniupnp/miniupnp

View file

@ -45,9 +45,14 @@ if (UNIX AND NOT APPLE)
find_package(Threads REQUIRED)
endif()
# TODO(unassigned): expand on types and versions, and then refactor.
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(CLANG TRUE)
endif()
if(MSVC)
add_definitions("/bigobj /Zm1000 /Z7 /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4503 /wd4345 /wd4091 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__")
add_definitions("/D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /D__SSE4_1__")
add_compile_options(/bigobj /Zm1000 /Z7 /MP2 /W3 /GS- /wd4996 /wd4503 /wd4345 /wd4091 /FIinline_c.h)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760 /DEBUG dbghelp.lib")
if(STATIC)
foreach(VAR CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE)
@ -66,7 +71,6 @@ else()
# if(NOT APPLE)
# set(WARNINGS "${WARNINGS} -Werror")
# endif()
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
set(WARNINGS "${WARNINGS} -Wno-shift-count-overflow -Wno-error=mismatched-tags -Wno-error=null-conversion -Wno-overloaded-shift-op-parentheses -Wno-error=shift-count-overflow -Wno-error=tautological-constant-out-of-range-compare -Wno-error=unused-private-field -Wno-error=unneeded-internal-declaration")
else()
@ -103,13 +107,15 @@ else()
else()
set(STATIC_ASSERT_FLAG "-Dstatic_assert=_Static_assert")
endif()
set(LINUX_LD_GOLD "")
set(LINUX_STATIC_ICU "")
if((NOT APPLE) AND (NOT MSVC))
set(LINUX_LD_GOLD "-fuse-ld=gold")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -ftemplate-depth-1024 -std=c++11 -D_GNU_SOURCE ${APPLE_FLAG} ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}")
if (NOT APPLE AND NOT MSVC)
if (CLANG)
set(LLVM_USE_LINKER "gold")
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
endif()
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LINUX_LD_GOLD} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LINUX_LD_GOLD} -fpermissive -ftemplate-depth-1024 -std=c++11 -D_GNU_SOURCE ${APPLE_FLAG} ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}")
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8))
set(DEBUG_FLAGS "-g3 -O0") #set(DEBUG_FLAGS "-g3 -Og")
else()
@ -152,7 +158,7 @@ endif()
message(STATUS "Boost: ${Boost_VERSION} from ${Boost_LIBRARY_DIRS}")
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/contrib/ethereum/libethash)
if(MINGW)
set(Boost_LIBRARIES "${Boost_LIBRARIES};ws2_32;mswsock")
elseif(NOT MSVC)
@ -196,8 +202,11 @@ else()
endif()
endif()
set(BUILD_TESTS FALSE CACHE BOOL "Build Zano tests")
add_subdirectory(contrib)
add_subdirectory(src)
add_subdirectory(tests)
if (BUILD_TESTS)
add_subdirectory(tests)
endif()

View file

@ -1,28 +1,77 @@
all: all-release
# Copyright (c) 2014-2019 Zano Project
# Copyright (c) 2014 The Cryptonote developers
# Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
cmake-debug:
mkdir -p build/debug
cd build/debug && cmake -D CMAKE_BUILD_TYPE=Debug ../..
# Define CMake generator
system := $(shell uname)
ifneq (, $(findstring MINGW, $(system)))
cmake_gen = -G 'MSYS Makefiles'
endif
build-debug: cmake-debug
cd build/debug && $(MAKE)
cmake = cmake $(cmake_gen)
test-debug: build-debug
cd build/debug && $(MAKE) test
cmake_debug = $(cmake) -D CMAKE_BUILD_TYPE=Debug
cmake_release = $(cmake) -D CMAKE_BUILD_TYPE=Release
all-debug: build-debug
cmake_gui = -D BUILD_GUI=ON
cmake_static = -D STATIC=ON
cmake_tests = -D BUILD_TESTS=ON
cmake-release:
mkdir -p build/release
cd build/release && cmake -D CMAKE_BUILD_TYPE=Release ../..
# Helper macro
define CMAKE
mkdir -p $1 && cd $1 && $2 ../../
endef
build-release: cmake-release
cd build/release && $(MAKE)
build = build
dir_debug = $(build)/debug
dir_release = $(build)/release
test-release: build-release
cd build/release && $(MAKE) test
all: release
all-release: build-release
release:
$(eval command += $(cmake_release))
$(call CMAKE,$(dir_release),$(command)) && $(MAKE)
debug:
$(eval command += $(cmake_debug))
$(call CMAKE,$(dir_debug),$(command)) && $(MAKE)
static: static-release
static-release:
$(eval command += $(cmake_release) $(cmake_static))
$(call CMAKE,$(dir_release),$(command)) && $(MAKE)
#
# GUI
#
gui: gui-release
gui-release:
$(eval command += $(cmake_release) $(cmake_gui))
$(call CMAKE,$(dir_release),$(command)) && $(MAKE)
gui-debug:
$(eval command += $(cmake_debug) $(cmake_gui))
$(call CMAKE,$(dir_debug),$(command)) && $(MAKE)
gui-static: gui-release-static
gui-release-static:
$(eval command += $(cmake_release) $(cmake_gui) $(cmake_static))
$(call CMAKE,$(dir_release),$(command)) && $(MAKE)
#
# Tests
#
test: test-release
test-release:
$(eval command += $(cmake_release) $(cmake_tests))
$(call CMAKE,$(dir_release),$(command)) && $(MAKE) && $(MAKE) test
test-debug:
$(eval command += $(cmake_debug) $(cmake_tests))
$(call CMAKE,$(dir_debug),$(command)) && $(MAKE) && $(MAKE) test
clean:
rm -rf build
@ -30,4 +79,4 @@ clean:
tags:
ctags -R --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ src contrib tests/gtest
.PHONY: all cmake-debug build-debug test-debug all-debug cmake-release build-release test-release all-release clean tags
.PHONY: all release debug static static-release gui gui-release gui-static gui-release-static gui-debug test test-release test-debug clean tags

View file

@ -1,10 +1,21 @@
Building
--------
### Cloning
Be sure to properly clone the repository:
`$ git clone --recursive https://github.com/hyle-team/zano.git`
or, if already cloned:
`$ cd zano/ && git submodule init && git submodule update`
### Dependencies
| component / version | minimum <br>(not recommended but may work) | recommended | most recent of what we have ever tested |
|--|--|--|--|
| gcc (Linux) | 5.4.0 | 7.2.0 | 7.2.0 |
| gcc (Linux) | 5.4.0 | 7.2.0 | 8.3.0 |
| llvm/clang (Linux) | UNKNOWN | 7.0.1 | 8.0.0 |
| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2015 (14.0 update 1) | 2015 (14.0 update 3) | 2017 (15.5.7) |
| [XCode](https://developer.apple.com/downloads/) (macOS) | 7.3.1 | 9.2 | 9.2 |
| [CMake](https://cmake.org/download/) | 2.8.6 | 3.4.1 | 3.11.0 |
@ -12,12 +23,16 @@ Building
| [Qt](https://download.qt.io/archive/qt/) (only for GUI) | 5.8.0 | 5.9.1 | 5.10.1 |
### Linux
Recommended OS version: Ubuntu 17.04 LTS.
1. Install dependencies: `sudo apt-get install build-essential git cmake unzip libicu-dev ocl-icd-opencl-dev mesa-common-dev libglu1-mesa-dev`
2. Install Qt and Boost
3. Set `BOOST_ROOT` and `QT_PREFIX_PATH` environment variables
4. `mkdir build` <br> `cd build` <br> `cmake -DBUILD_GUI=FALSE -DSTATIC=TRUE ..` <br> `make`
5. In order to build GUI, revise and run script at `/utils/build_script_linux.sh`
1. For server version: \
`$ sudo apt-get install -y build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev cmake git libboost-all-dev screen`\
For GUI version:\
`$ sudo apt-get install -y build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev cmake git libboost-all-dev screen mesa-common-dev libglu1-mesa-dev qt5-default qtwebengine5-dev`
2. `$ cd zano/ && make -j$(nproc) gui`
3. Look for the binaries, including the `Zano` GUI, in the build directory
### Windows
Recommended OS version: Windows 7 x64.

View file

@ -1,18 +1,19 @@
set(UPNPC_BUILD_STATIC ON CACHE BOOL "Build static library")
set(UPNPC_BUILD_SHARED OFF CACHE BOOL "Build shared library")
set(UPNPC_BUILD_TESTS OFF CACHE BOOL "Build test executables")
add_subdirectory(miniupnpc)
add_subdirectory(miniupnp/miniupnpc)
add_subdirectory(zlib)
add_subdirectory(db)
add_subdirectory(ethereum)
set_property(TARGET upnpc-static PROPERTY FOLDER "contrib")
set_property(TARGET upnpc-static PROPERTY FOLDER "contrib/miniupnp")
set_property(TARGET zlibstatic PROPERTY FOLDER "contrib")
set_property(TARGET lmdb PROPERTY FOLDER "contrib")
if(MSVC)
set_property(TARGET upnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -wd4244 -wd4267")
else()

View file

@ -2,6 +2,6 @@ add_subdirectory(liblmdb)
if(MSVC)
target_compile_options(lmdb PRIVATE /wd4996 /wd4503 /wd4345 /wd4267 /wd4244 /wd4146 /wd4333 /wd4172)
else()
target_compile_options(lmdb PRIVATE -Wno-discarded-qualifiers -Wno-empty-body -Wno-unused-but-set-variable)
# Warnings as used by LMDB itself (LMDB_0.9.23)
target_compile_options(lmdb PRIVATE -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized)
endif()

View file

@ -35,12 +35,11 @@ namespace eos {
// version of the linked boost archive library
const archive_version_type archive_version(
11
// #if BOOST_VERSION < 103700
// boost::archive::ARCHIVE_VERSION()
// #else
// boost::archive::BOOST_ARCHIVE_VERSION()
// #endif
#if BOOST_VERSION < 103700
boost::archive::ARCHIVE_VERSION()
#else
boost::archive::BOOST_ARCHIVE_VERSION()
#endif
);
/**

View file

@ -3,7 +3,7 @@
* \file portable_iarchive.hpp
* \brief Provides an archive to read from portable binary files.
* \author christian.pfligersdorffer@gmx.at
* \version 5.0
* \version 5.1
*
* This pair of archives brings the advantages of binary streams to the cross
* platform boost::serialization user. While being almost as fast as the native
@ -23,6 +23,9 @@
* chance it will instantly work for your specific setup. If you encounter
* problems or have suggestions please contact the author.
*
* \note Version 5.1 is now compatible with boost up to version 1.59. Thanks to
* ecotax for pointing to the issue with shared_ptr_helper.
*
* \note Version 5.0 is now compatible with boost up to version 1.49 and enables
* serialization of std::wstring by converting it to/from utf8 (thanks to
* Arash Abghari for this suggestion). With that all unit tests from the
@ -89,9 +92,7 @@
#include <boost/archive/basic_binary_iprimitive.hpp>
#include <boost/archive/basic_binary_iarchive.hpp>
#if BOOST_VERSION >= 105600
#include <boost/serialization/shared_ptr_helper.hpp>
#elif BOOST_VERSION >= 103500
#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
#include <boost/archive/shared_ptr_helper.hpp>
#endif
@ -115,14 +116,16 @@
#include <boost/math/fpclassify.hpp>
#elif BOOST_VERSION < 104800
#include <boost/spirit/home/support/detail/integer/endian.hpp>
// Boost 1.69 (Spirit.X2/X3) has dropped their own FP routines in favor of boost::math
#elif BOOST_VERSION < 106900
#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
#include <boost/spirit/home/support/detail/endian/endian.hpp>
#else
#include <boost/spirit/home/support/detail/endian/endian.hpp>
#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
#endif
// namespace alias
#if BOOST_VERSION < 103800
#if BOOST_VERSION < 103800 || BOOST_VERSION >= 106900
namespace fp = boost::math;
#else
namespace fp = boost::spirit::math;
@ -135,7 +138,7 @@ namespace endian = boost::detail;
namespace endian = boost::spirit::detail;
#endif
#ifndef BOOST_NO_STD_WSTRING
#if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING
// used for wstring to utf8 conversion
#include <boost/program_options/config.hpp>
#include <boost/program_options/detail/convert.hpp>
@ -190,9 +193,7 @@ namespace eos {
// load_override functions so we chose to stay one level higher
, public boost::archive::basic_binary_iarchive<portable_iarchive>
#if BOOST_VERSION >= 105600
// mix-in helper class for serializing shared_ptr does not exist anymore
#elif BOOST_VERSION >= 103500
#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
// mix-in helper class for serializing shared_ptr
, public boost::archive::detail::shared_ptr_helper
#endif
@ -349,7 +350,7 @@ namespace eos {
T temp = size < 0 ? -1 : 0;
load_binary(&temp, abs(size));
// load the value from little endian - is is then converted
// load the value from little endian - it is then converted
// to the target type T and fits it because size <= sizeof(T)
t = endian::load_little_endian<T, sizeof(T)>(&temp);
}

View file

@ -3,7 +3,7 @@
* \file portable_oarchive.hpp
* \brief Provides an archive to create portable binary files.
* \author christian.pfligersdorffer@gmx.at
* \version 5.0
* \version 5.1
*
* This pair of archives brings the advantages of binary streams to the cross
* platform boost::serialization user. While being almost as fast as the native
@ -23,6 +23,9 @@
* chance it will instantly work for your specific setup. If you encounter
* problems or have suggestions please contact the author.
*
* \note Version 5.1 is now compatible with boost up to version 1.59. Thanks to
* ecotax for pointing to the issue with shared_ptr_helper.
*
* \note Version 5.0 is now compatible with boost up to version 1.49 and enables
* serialization of std::wstring by converting it to/from utf8 (thanks to
* Arash Abghari for this suggestion). With that all unit tests from the
@ -91,15 +94,9 @@
#include <boost/utility/enable_if.hpp>
#include <boost/archive/basic_binary_oprimitive.hpp>
#include <boost/archive/basic_binary_oarchive.hpp>
#if BOOST_VERSION >= 105600
#include <boost/serialization/shared_ptr_helper.hpp>
#elif BOOST_VERSION >= 103500
#include <boost/archive/shared_ptr_helper.hpp>
#endif
#if BOOST_VERSION >= 104500
#include <boost/program_options/config.hpp>
#include <boost/program_options/detail/convert.hpp>
#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
#include <boost/archive/shared_ptr_helper.hpp>
#endif
// funny polymorphics
@ -122,14 +119,16 @@
#include <boost/math/fpclassify.hpp>
#elif BOOST_VERSION < 104800
#include <boost/spirit/home/support/detail/integer/endian.hpp>
// Boost 1.69 (Spirit.X2/X3) has dropped their own FP routines in favor of boost::math
#elif BOOST_VERSION < 106900
#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
#include <boost/spirit/home/support/detail/endian/endian.hpp>
#else
#include <boost/spirit/home/support/detail/endian/endian.hpp>
#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
#endif
// namespace alias fp_classify
#if BOOST_VERSION < 103800
#if BOOST_VERSION < 103800 || BOOST_VERSION >= 106900
namespace fp = boost::math;
#else
namespace fp = boost::spirit::math;
@ -142,7 +141,7 @@ namespace endian = boost::detail;
namespace endian = boost::spirit::detail;
#endif
#ifndef BOOST_NO_STD_WSTRING
#if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING
// used for wstring to utf8 conversion
#include <boost/program_options/config.hpp>
#include <boost/program_options/detail/convert.hpp>
@ -195,9 +194,7 @@ namespace eos {
// save_override functions so we chose to stay one level higher
, public boost::archive::basic_binary_oarchive<portable_oarchive>
#if BOOST_VERSION >= 105600
// mix-in helper class for serializing shared_ptr does not exist anymore
#elif BOOST_VERSION >= 103500
#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
// mix-in helper class for serializing shared_ptr
, public boost::archive::detail::shared_ptr_helper
#endif

View file

@ -422,7 +422,6 @@ namespace epee
std::string get_usage()
{
std::stringstream ss;
ss << "Commands: " << ENDL;
size_t max_command_len = 0;
for(auto& x:m_command_handlers)
if(x.first.size() > max_command_len)
@ -430,8 +429,7 @@ namespace epee
for(auto& x:m_command_handlers)
{
ss.width(max_command_len + 3);
ss << " " << std::left << x.first << " " << x.second.second << ENDL;
ss << " " << std::left << std::setw(max_command_len + 3) << x.first << " " << x.second.second << ENDL;
}
return ss.str();
}

View file

@ -51,6 +51,7 @@ namespace math_helper
average()
{
m_base = default_base;
m_count = 0;
}
bool set_base()
@ -71,6 +72,7 @@ namespace math_helper
CRITICAL_REGION_LOCAL(m_lock);
//#ifndef DEBUG_STUB
m_count++;
m_list.push_back(vl);
if(m_list.size() > m_base )
m_list.pop_front();
@ -106,9 +108,20 @@ namespace math_helper
return 0;
}
uint64_t& get_count()
{
return m_count;
}
void reset()
{
m_count = 0;
m_list.clear();
}
private:
unsigned int m_base;
unsigned int m_base;
uint64_t m_count;
std::list<value_type> m_list;
mutable critical_section m_lock;
};

View file

@ -389,22 +389,27 @@ namespace misc_utils
auto res = container.insert(typename t_container_type::value_type(key, AUTO_VAL_INIT(typename t_container_type::mapped_type())));
return res.first->second;
}
}
}
} // namespace misc_utils
} // namespace epee
template<typename T>
std::ostream& print_container_content(std::ostream& out, const T& v);
template<typename T>
std::ostream& operator<< (std::ostream& out, const std::vector<T>& v)
namespace std
{
return print_container_content(out, v);
}
template<typename T>
std::ostream& operator<< (std::ostream& out, const std::list<T>& v)
{
return print_container_content(out, v);
}
template<typename T>
std::ostream& operator<< (std::ostream& out, const std::vector<T>& v)
{
return print_container_content(out, v);
}
template<typename T>
std::ostream& operator<< (std::ostream& out, const std::list<T>& v)
{
return print_container_content(out, v);
}
} // namespace std
template<typename T>
std::ostream& print_container_content(std::ostream& out, const T& v)

View file

@ -893,12 +893,10 @@ namespace log_space
FAST_CRITICAL_REGION_END();
return true;
}
std::string get_thread_prefix()
{
FAST_CRITICAL_REGION_LOCAL(m_critical_sec);
return m_thr_prefix_strings[misc_utils::get_thread_string_id()];
}
std::string get_default_log_file()
@ -1160,7 +1158,6 @@ namespace log_space
}
static bool add_logger( ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4 )
{
logger* plogger = get_or_create_instance();
@ -1234,8 +1231,6 @@ POP_WARNINGS
}
#ifdef _MSC_VER
@ -1290,8 +1285,6 @@ POP_WARNINGS
return plogger->get_thread_prefix();
}
static std::string get_prefix_entry()
{
std::stringstream str_prefix;
@ -1587,8 +1580,6 @@ POP_WARNINGS
#endif
#define LOG_PRINT_NO_POSTFIX(mess, level) LOG_PRINT_NO_POSTFIX2(LOG_DEFAULT_TARGET, mess, level)
#define LOG_PRINT_NO_PREFIX(mess, level) LOG_PRINT_NO_PREFIX2(LOG_DEFAULT_TARGET, mess, level)
#define LOG_PRINT_NO_PREFIX_NO_POSTFIX(mess, level) LOG_PRINT_NO_PREFIX_NO_POSTFIX2(LOG_DEFAULT_TARGET, mess, level)
@ -1694,7 +1685,6 @@ POP_WARNINGS
#define CHECK_AND_ASSERT_MES2(expr, message) do{if(!(expr)) {LOG_ERROR(message); };}while(0)
#endif
}
POP_WARNINGS

View file

@ -111,6 +111,7 @@ namespace misc_utils
#if defined(__GNUC__)
#include <execinfo.h>
#include <boost/core/demangle.hpp>
#endif
inline std::string print_trace()
{
@ -125,9 +126,9 @@ namespace misc_utils
stack_depth = backtrace(stack_addrs, max_depth);
stack_strings = backtrace_symbols(stack_addrs, stack_depth);
for (size_t i = 1; i < stack_depth; i++) {
ss << stack_strings[i] << std::endl;
for (size_t i = 1; i < stack_depth; i++)
{
ss << boost::core::demangle(stack_strings[i]) << std::endl;
}
free(stack_strings); // malloc()ed by backtrace_symbols
#endif

View file

@ -316,6 +316,7 @@ DISABLE_VS_WARNINGS(4355)
send_guard.unlock();//manual unlock
LOG_ERROR("send to [" << print_connection_context_short(context) << ", (" << (void*)this << ")] que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection");
close();
shutdown();
return false;
}
@ -351,6 +352,8 @@ DISABLE_VS_WARNINGS(4355)
template<class t_protocol_handler>
bool connection<t_protocol_handler>::shutdown()
{
if (m_was_shutdown)
return true;
// Initiate graceful connection closure.
boost::system::error_code ignored_ec;
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);

View file

@ -137,6 +137,7 @@ namespace net_utils
bool m_is_stop_handling;
http::http_request_info m_query_info;
size_t m_len_summary, m_len_remain;
size_t m_precommand_line_chars;
config_type& m_config;
bool m_want_close;
protected:

View file

@ -33,8 +33,9 @@
#include "file_io_utils.h"
#include "net_parse_helpers.h"
#define HTTP_MAX_URI_LEN 9000
#define HTTP_MAX_HEADER_LEN 100000
#define HTTP_MAX_URI_LEN 9000
#define HTTP_MAX_PRE_COMMAND_LINE_CHARS 20
#define HTTP_MAX_HEADER_LEN 100000
PUSH_WARNINGS
DISABLE_GCC_WARNING(maybe-uninitialized)
@ -204,7 +205,8 @@ namespace net_utils
m_len_remain(0),
m_config(config),
m_want_close(false),
m_psnd_hndlr(psnd_hndlr)
m_psnd_hndlr(psnd_hndlr),
m_precommand_line_chars(0)
{
}
@ -217,6 +219,7 @@ namespace net_utils
m_body_transfer_type = http_body_transfer_undefined;
m_query_info.clear();
m_len_summary = 0;
m_precommand_line_chars = 0;
return true;
}
//--------------------------------------------------------------------------------------------
@ -257,11 +260,19 @@ namespace net_utils
if((m_cache[0] == '\r' || m_cache[0] == '\n'))
{
//some times it could be that before query line cold be few line breaks
//so we have to be calm without panic with assers
//so we have to be calm down without panic and asserts
m_cache.erase(0, 1);
//fixed bug with possible '\r\n' chars flood, thanks to @anonimal (https://github.com/anonimal) for pointing this
++m_precommand_line_chars;
if (m_precommand_line_chars > HTTP_MAX_PRE_COMMAND_LINE_CHARS)
{
LOG_ERROR("simple_http_connection_handler::handle_buff_in: Too long URI line");
m_state = http_state_error;
return false;
}
break;
}
if(std::string::npos != m_cache.find('\n', 0))
handle_invoke_query_line();
else
@ -269,7 +280,7 @@ namespace net_utils
m_is_stop_handling = true;
if(m_cache.size() > HTTP_MAX_URI_LEN)
{
LOG_ERROR("simple_http_connection_handler::handle_buff_out: Too long URI line");
LOG_ERROR("simple_http_connection_handler::handle_buff_in: Too long URI line");
m_state = http_state_error;
return false;
}
@ -297,10 +308,10 @@ namespace net_utils
case http_state_connection_close:
return false;
default:
LOG_ERROR("simple_http_connection_handler::handle_char_out: Wrong state: " << m_state);
LOG_ERROR("simple_http_connection_handler::handle_buff_in: Wrong state: " << m_state);
return false;
case http_state_error:
LOG_ERROR("simple_http_connection_handler::handle_char_out: Error state!!!");
LOG_ERROR("simple_http_connection_handler::handle_buff_in: Error state!!!");
return false;
}
@ -334,10 +345,10 @@ namespace net_utils
template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::handle_invoke_query_line()
{
LOG_FRAME("simple_http_connection_handler<t_connection_context>::handle_recognize_protocol_out(*)", LOG_LEVEL_3);
LOG_FRAME("simple_http_connection_handler<t_connection_context>::handle_invoke_query_line(*)", LOG_LEVEL_3);
STATIC_REGEXP_EXPR_1(rexp_match_command_line, "^(((OPTIONS)|(GET)|(HEAD)|(POST)|(PUT)|(DELETE)|(TRACE)) (\\S+) HTTP/(\\d+).(\\d+))\r?\n", boost::regex::icase | boost::regex::normal);
// 123 4 5 6 7 8 9 10 11 12
// 123 4 5 6 7 8 9 10 11 12
//size_t match_len = 0;
boost::smatch result;
if(boost::regex_search(m_cache, result, rexp_match_command_line, boost::match_default) && result[0].matched)
@ -682,4 +693,4 @@ namespace net_utils
POP_WARNINGS
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------

View file

@ -31,9 +31,10 @@ namespace epee
{
namespace string_tools
{
inline std::string print_fixed_decimal_point(uint64_t amount, size_t decimal_point)
template<typename t_number>
inline std::string print_fixed_decimal_point(t_number amount, size_t decimal_point)
{
std::string s = std::to_string(amount);
std::string s = boost::lexical_cast<std::string>(amount);
if (s.size() < decimal_point + 1)
{
s.insert(0, decimal_point + 1 - s.size(), '0');

View file

@ -125,6 +125,7 @@ namespace epee
template<class stl_container, class t_storage>
static bool serialize_stl_container_pod_val_as_blob(const stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
static_assert(std::is_trivial<typename stl_container::value_type>::value, "Item supposed to be 'trivial'(trivially copyable)");
if(!container.size()) return true;
std::string mb;
mb.resize(sizeof(typename stl_container::value_type)*container.size());
@ -140,6 +141,7 @@ namespace epee
template<class stl_container, class t_storage>
static bool unserialize_stl_container_pod_val_as_blob(stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
static_assert(std::is_trivial<typename stl_container::value_type>::value, "Item supposed to be 'trivial'(trivially copyable)");
container.clear();
std::string buff;
bool res = stg.get_value(pname, buff, hparent_section);

View file

@ -83,7 +83,7 @@ namespace epee
bool load_from_binary(const binarybuffer& target);
template<class trace_policy>
bool dump_as_xml(std::string& targetObj, const std::string& root_name = "");
bool dump_as_json(std::string& targetObj, size_t indent = 0);
bool dump_as_json(std::string& targetObj, size_t indent = 0, end_of_line_t eol = eol_crlf);
bool load_from_json(const std::string& source);
private:
@ -106,11 +106,11 @@ namespace epee
#pragma pack(pop)
};
inline
bool portable_storage::dump_as_json(std::string& buff, size_t indent)
bool portable_storage::dump_as_json(std::string& buff, size_t indent /* = 0 */, end_of_line_t eol /* = eol_crlf */)
{
TRY_ENTRY();
std::stringstream ss;
epee::serialization::dump_as_json(ss, m_root, indent);
epee::serialization::dump_as_json(ss, m_root, indent, eol);
buff = ss.str();
return true;
CATCH_ENTRY("portable_storage::dump_as_json", false)

View file

@ -69,6 +69,8 @@ namespace epee
{
namespace serialization
{
enum end_of_line_t { eol_crlf = 0, eol_lf = 1, eol_cr = 2, eol_space = 3 };
struct section;
/************************************************************************/

View file

@ -56,16 +56,16 @@ namespace epee
}
//-----------------------------------------------------------------------------------------------------------
template<class t_struct>
bool store_t_to_json(const t_struct& str_in, std::string& json_buff, size_t indent = 0)
bool store_t_to_json(const t_struct& str_in, std::string& json_buff, size_t indent = 0, end_of_line_t eol = eol_crlf)
{
portable_storage ps;
str_in.store(ps);
ps.dump_as_json(json_buff, indent);
ps.dump_as_json(json_buff, indent, eol);
return true;
}
//-----------------------------------------------------------------------------------------------------------
template<class t_struct>
std::string store_t_to_json(const t_struct& str_in, size_t indent = 0)
std::string store_t_to_json(const t_struct& str_in, size_t indent = 0, end_of_line_t eol = eol_crlf)
{
std::string json_buff;
store_t_to_json(str_in, json_buff, indent);

View file

@ -37,23 +37,23 @@ namespace epee
{
template<class t_stream>
void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent);
void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent);
void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const std::string& v, size_t indent);
void dump_as_json(t_stream& strm, const std::string& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const int8_t& v, size_t indent);
void dump_as_json(t_stream& strm, const int8_t& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent);
void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const bool& v, size_t indent);
void dump_as_json(t_stream& strm, const bool& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const double& v, size_t indent);
void dump_as_json(t_stream& strm, const double& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream, class t_type>
void dump_as_json(t_stream& strm, const t_type& v, size_t indent);
void dump_as_json(t_stream& strm, const t_type& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const section& sec, size_t indent);
void dump_as_json(t_stream& strm, const section& sec, size_t indent, end_of_line_t eol = eol_crlf);
inline std::string make_indent(size_t indent)
@ -66,7 +66,13 @@ namespace epee
{
t_stream& m_strm;
size_t m_indent;
array_entry_store_to_json_visitor(t_stream& strm, size_t indent):m_strm(strm), m_indent(indent){}
end_of_line_t m_eol;
array_entry_store_to_json_visitor(t_stream& strm, size_t indent, end_of_line_t eol)
: m_strm(strm)
, m_indent(indent)
, m_eol(eol)
{}
template<class t_type>
void operator()(const array_entry_t<t_type>& a)
@ -77,7 +83,7 @@ namespace epee
auto last_it = --a.m_array.end();
for(auto it = a.m_array.begin(); it != a.m_array.end(); it++)
{
dump_as_json(m_strm, *it, m_indent);
dump_as_json(m_strm, *it, m_indent, m_eol);
if(it != last_it)
m_strm << ",";
}
@ -91,50 +97,56 @@ namespace epee
{
t_stream& m_strm;
size_t m_indent;
storage_entry_store_to_json_visitor(t_stream& strm, size_t indent):m_strm(strm), m_indent(indent)
end_of_line_t m_eol;
storage_entry_store_to_json_visitor(t_stream& strm, size_t indent, end_of_line_t eol)
: m_strm(strm)
, m_indent(indent)
, m_eol(eol)
{}
//section, array_entry
template<class visited_type>
void operator()(const visited_type& v)
{
dump_as_json(m_strm, v, m_indent);
dump_as_json(m_strm, v, m_indent, m_eol);
}
};
template<class t_stream>
void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent)
void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent, end_of_line_t eol)
{
array_entry_store_to_json_visitor<t_stream> aesv(strm, indent);
array_entry_store_to_json_visitor<t_stream> aesv(strm, indent, eol);
boost::apply_visitor(aesv, ae);
}
template<class t_stream>
void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent)
void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent, end_of_line_t eol)
{
storage_entry_store_to_json_visitor<t_stream> sv(strm, indent);
storage_entry_store_to_json_visitor<t_stream> sv(strm, indent, eol);
boost::apply_visitor(sv, se);
}
template<class t_stream>
void dump_as_json(t_stream& strm, const std::string& v, size_t indent)
void dump_as_json(t_stream& strm, const std::string& v, size_t indent, end_of_line_t eol)
{
strm << "\"" << misc_utils::parse::transform_to_json_escape_sequence(v) << "\"";
}
template<class t_stream>
void dump_as_json(t_stream& strm, const int8_t& v, size_t indent)
void dump_as_json(t_stream& strm, const int8_t& v, size_t indent, end_of_line_t eol)
{
strm << static_cast<int32_t>(v);
}
template<class t_stream>
void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent)
void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent, end_of_line_t eol)
{
strm << static_cast<int32_t>(v);
}
template<class t_stream>
void dump_as_json(t_stream& strm, const bool& v, size_t indent)
void dump_as_json(t_stream& strm, const bool& v, size_t indent, end_of_line_t eol)
{
if(v)
strm << "true";
@ -143,23 +155,34 @@ namespace epee
}
template<class t_stream>
void dump_as_json(t_stream& strm, const double& v, size_t indent)
void dump_as_json(t_stream& strm, const double& v, size_t indent, end_of_line_t eol)
{
strm.precision(8);
strm << std::fixed << v;
}
template<class t_stream, class t_type>
void dump_as_json(t_stream& strm, const t_type& v, size_t /*indent*/)
void dump_as_json(t_stream& strm, const t_type& v, size_t indent, end_of_line_t eol)
{
strm << v;
}
template<class t_stream>
void dump_as_json(t_stream& strm, const section& sec, size_t indent)
void dump_as_json(t_stream& strm, const section& sec, size_t indent, end_of_line_t eol)
{
auto put_eol = [&]() {
switch (eol)
{
case eol_lf: strm << "\n"; break;
case eol_cr: strm << "\r"; break;
case eol_space: strm << " "; break;
default: strm << "\r\n"; break;
}
};
size_t local_indent = indent + 1;
strm << "{\r\n";
strm << "{";
put_eol();
std::string indent_str = make_indent(local_indent);
if(sec.m_entries.size())
{
@ -167,10 +190,10 @@ namespace epee
for(auto it = sec.m_entries.begin(); it!= sec.m_entries.end();it++)
{
strm << indent_str << "\"" << misc_utils::parse::transform_to_json_escape_sequence(it->first) << "\"" << ": ";
dump_as_json(strm, it->second, local_indent);
dump_as_json(strm, it->second, local_indent, eol);
if(it_last != it)
strm << ",";
strm << "\r\n";
put_eol();
}
}
strm << make_indent(indent) << "}";

View file

@ -648,9 +648,6 @@ POP_WARNINGS
return res;
}
//----------------------------------------------------------------------------
inline std::string cut_off_extension(const std::string& str)
{
std::string res;
@ -661,7 +658,17 @@ POP_WARNINGS
res = str.substr(0, pos);
return res;
}
//----------------------------------------------------------------------------
inline std::wstring cut_off_extension(const std::wstring& str)
{
std::wstring res;
std::wstring::size_type pos = str.rfind('.');
if (std::wstring::npos == pos)
return str;
res = str.substr(0, pos);
return res;
}
//----------------------------------------------------------------------------
// replaces all non-ascii characters with mask_character
inline std::string mask_non_ascii_chars(const std::string& str, const char mask_character = '?')

View file

@ -78,7 +78,7 @@ namespace epee
{
t_object t;
std::recursive_mutex m;
mutable std::recursive_mutex m;
template<typename t_proxy_object, typename t_proxy_lock_time_watching_policy>
friend class locked_object_proxy;
public:
@ -106,6 +106,16 @@ namespace epee
return locked_object_proxy<t_object, lock_time_watching_policy>(t, m);
}
locked_object_proxy<const t_object, lock_time_watching_policy> operator->() const
{
return locked_object_proxy<const t_object, lock_time_watching_policy>(t, m);
}
locked_object_proxy<const t_object, lock_time_watching_policy> operator*() const
{
return locked_object_proxy<const t_object, lock_time_watching_policy>(t, m);
}
/*locked_object_proxy<t_object> operator()()
{
return locked_object_proxy<t_object>(t, m);

View file

@ -701,6 +701,11 @@ namespace epee
#define CRITICAL_REGION_BEGIN1(x) CRITICAL_REGION_BEGIN_VAR(x, critical_region_var1)
#define CRITICAL_REGION_END() }
#define SHARED_CRITICAL_REGION_LOCAL(x) boost::shared_lock< boost::shared_mutex > critical_region_var(x)
#define EXCLUSIVE_CRITICAL_REGION_LOCAL(x) boost::unique_lock< boost::shared_mutex > critical_region_var(x)
#define SHARED_CRITICAL_REGION_BEGIN(x) { SHARED_CRITICAL_REGION_LOCAL(x)
#define EXCLUSIVE_CRITICAL_REGION_BEGIN(x) { EXCLUSIVE_CRITICAL_REGION_LOCAL(x)
}

View file

@ -0,0 +1,10 @@
add_subdirectory(libethash)
set_property(TARGET ethash PROPERTY FOLDER "contrib")
if(MSVC)
target_compile_options(ethash PRIVATE /wd4477 /wd4267)
else()
target_compile_options(ethash PRIVATE -Wno-format -Wno-aggregate-return -Wno-empty-body)
endif()

View file

@ -0,0 +1,33 @@
# ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
# Copyright 2018 Pawel Bylica.
# Licensed under the Apache License, Version 2.0. See the LICENSE file.
# set(include_dir ${PROJECT_SOURCE_DIR}/include)
add_library(
ethash
bit_manipulation.h
builtins.h
endianness.hpp
ethash/ethash.h
ethash/ethash.hpp
ethash-internal.hpp
ethash.cpp
ethash/hash_types.h
managed.cpp
ethash/keccak.h
ethash/keccak.hpp
keccak.c
keccakf800.c
keccakf1600.c
kiss99.hpp
primes.h
primes.c
ethash/progpow.hpp
progpow.cpp
)

View file

@ -0,0 +1,81 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018 Pawel Bylica.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#pragma once
#include "builtins.h"
#include "support/attributes.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
static inline uint32_t rotl32(uint32_t n, unsigned int c)
{
const unsigned int mask = 31;
c &= mask;
unsigned int neg_c = (unsigned int)(-(int)c);
return (n << c) | (n >> (neg_c & mask));
}
static inline uint32_t rotr32(uint32_t n, unsigned int c)
{
const unsigned int mask = 31;
c &= mask;
unsigned int neg_c = (unsigned int)(-(int)c);
return (n >> c) | (n << (neg_c & mask));
}
static inline uint32_t clz32(uint32_t x)
{
return x ? (uint32_t)__builtin_clz(x) : 32;
}
static inline uint32_t popcount32(uint32_t x)
{
return (uint32_t)__builtin_popcount(x);
}
static inline uint32_t mul_hi32(uint32_t x, uint32_t y)
{
return (uint32_t)(((uint64_t)x * (uint64_t)y) >> 32);
}
/** FNV 32-bit prime. */
static const uint32_t fnv_prime = 0x01000193;
/** FNV 32-bit offset basis. */
static const uint32_t fnv_offset_basis = 0x811c9dc5;
/**
* The implementation of FNV-1 hash.
*
* See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1_hash.
*/
NO_SANITIZE("unsigned-integer-overflow")
static inline uint32_t fnv1(uint32_t u, uint32_t v) noexcept
{
return (u * fnv_prime) ^ v;
}
/**
* The implementation of FNV-1a hash.
*
* See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash.
*/
NO_SANITIZE("unsigned-integer-overflow")
static inline uint32_t fnv1a(uint32_t u, uint32_t v) noexcept
{
return (u ^ v) * fnv_prime;
}
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,43 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018 Pawel Bylica.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
/**
* @file
* Implementation of GCC/clang builtins for MSVC compiler.
*/
#pragma once
#ifdef _MSC_VER
#include <intrin.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Returns the number of leading 0-bits in `x`, starting at the most significant bit position.
* If `x` is 0, the result is undefined.
*/
static inline int __builtin_clz(unsigned int x)
{
unsigned long most_significant_bit;
_BitScanReverse(&most_significant_bit, x);
return 31 - (int)most_significant_bit;
}
/**
* Returns the number of 1-bits in `x`.
*/
static inline int __builtin_popcount(unsigned int x)
{
return (int)__popcnt(x);
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,98 @@
// Copyright 2018 Pawel Bylica.
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
/// @file
/// This file contains helper functions to handle big-endian architectures.
/// The Ethash algorithm is naturally defined for little-endian architectures
/// so for those the helpers are just no-op empty functions.
/// For big-endian architectures we need 32-bit and 64-bit byte swapping in
/// some places.
#pragma once
#include <ethash/ethash.hpp>
#if _WIN32
#include <stdlib.h>
#define bswap32 _byteswap_ulong
#define bswap64 _byteswap_uint64
// On Windows assume little endian.
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
#define __BYTE_ORDER __LITTLE_ENDIAN
#elif __APPLE__
#include <machine/endian.h>
#define bswap32 __builtin_bswap32
#define bswap64 __builtin_bswap64
#else
#include <endian.h>
#define bswap32 __builtin_bswap32
#define bswap64 __builtin_bswap64
#endif
namespace ethash
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
struct le
{
static uint32_t uint32(uint32_t x) noexcept { return x; }
static uint64_t uint64(uint64_t x) noexcept { return x; }
static const hash1024& uint32s(const hash1024& h) noexcept { return h; }
static const hash512& uint32s(const hash512& h) noexcept { return h; }
static const hash256& uint32s(const hash256& h) noexcept { return h; }
};
struct be
{
static uint64_t uint64(uint64_t x) noexcept { return bswap64(x); }
};
#elif __BYTE_ORDER == __BIG_ENDIAN
struct le
{
static uint32_t uint32(uint32_t x) noexcept { return bswap32(x); }
static uint64_t uint64(uint64_t x) noexcept { return bswap64(x); }
static hash1024 uint32s(hash1024 h) noexcept
{
for (auto& w : h.word32s)
w = uint32(w);
return h;
}
static hash512 uint32s(hash512 h) noexcept
{
for (auto& w : h.word32s)
w = uint32(w);
return h;
}
static hash256 uint32s(hash256 h) noexcept
{
for (auto& w : h.word32s)
w = uint32(w);
return h;
}
};
struct be
{
static uint64_t uint64(uint64_t x) noexcept { return x; }
};
#endif
} // namespace ethash

View file

@ -0,0 +1,69 @@
// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
// Copyright 2018 Pawel Bylica.
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
/// @file
/// Contains declarations of internal ethash functions to allow them to be
/// unit-tested.
#pragma once
#include <ethash/ethash.hpp>
#include "endianness.hpp"
#include <memory>
#include <vector>
extern "C" struct ethash_epoch_context_full : ethash_epoch_context
{
ethash_hash1024* full_dataset;
constexpr ethash_epoch_context_full(int epoch_number, int light_cache_num_items,
const ethash_hash512* light_cache, const uint32_t* l1_cache, int full_dataset_num_items,
ethash_hash1024* full_dataset) noexcept
: ethash_epoch_context{epoch_number, light_cache_num_items, light_cache, l1_cache,
full_dataset_num_items},
full_dataset{full_dataset}
{}
};
namespace ethash
{
inline bool is_less_or_equal(const hash256& a, const hash256& b) noexcept
{
for (size_t i = 0; i < (sizeof(a) / sizeof(a.word64s[0])); ++i)
{
if (be::uint64(a.word64s[i]) > be::uint64(b.word64s[i]))
return false;
if (be::uint64(a.word64s[i]) < be::uint64(b.word64s[i]))
return true;
}
return true;
}
inline bool is_equal(const hash256& a, const hash256& b) noexcept
{
return std::memcmp(a.bytes, b.bytes, sizeof(a)) == 0;
}
void build_light_cache(hash512 cache[], int num_items, const hash256& seed) noexcept;
hash512 calculate_dataset_item_512(const epoch_context& context, int64_t index) noexcept;
hash1024 calculate_dataset_item_1024(const epoch_context& context, uint32_t index) noexcept;
hash2048 calculate_dataset_item_2048(const epoch_context& context, uint32_t index) noexcept;
namespace generic
{
using hash_fn_512 = hash512 (*)(const uint8_t* data, size_t size);
using build_light_cache_fn = void (*)(hash512 cache[], int num_items, const hash256& seed);
void build_light_cache(
hash_fn_512 hash_fn, hash512 cache[], int num_items, const hash256& seed) noexcept;
epoch_context_full* create_epoch_context(
build_light_cache_fn build_fn, int epoch_number, bool full) noexcept;
} // namespace generic
} // namespace ethash

View file

@ -0,0 +1,441 @@
// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
// Copyright 2018 Pawel Bylica.
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
#include "ethash-internal.hpp"
#include "bit_manipulation.h"
#include "endianness.hpp"
#include "primes.h"
#include "support/attributes.h"
#include <ethash/keccak.hpp>
#include <ethash/progpow.hpp>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <limits>
namespace ethash
{
// Internal constants:
constexpr static int light_cache_init_size = 1 << 24;
constexpr static int light_cache_growth = 1 << 17;
constexpr static int light_cache_rounds = 3;
constexpr static int full_dataset_init_size = 1 << 30;
constexpr static int full_dataset_growth = 1 << 23;
constexpr static int full_dataset_item_parents = 256;
// Verify constants:
static_assert(sizeof(hash512) == ETHASH_LIGHT_CACHE_ITEM_SIZE, "");
static_assert(sizeof(hash1024) == ETHASH_FULL_DATASET_ITEM_SIZE, "");
static_assert(light_cache_item_size == ETHASH_LIGHT_CACHE_ITEM_SIZE, "");
static_assert(full_dataset_item_size == ETHASH_FULL_DATASET_ITEM_SIZE, "");
namespace
{
using ::fnv1;
inline hash512 fnv1(const hash512& u, const hash512& v) noexcept
{
hash512 r;
for (size_t i = 0; i < sizeof(r) / sizeof(r.word32s[0]); ++i)
r.word32s[i] = fnv1(u.word32s[i], v.word32s[i]);
return r;
}
inline hash512 bitwise_xor(const hash512& x, const hash512& y) noexcept
{
hash512 z;
for (size_t i = 0; i < sizeof(z) / sizeof(z.word64s[0]); ++i)
z.word64s[i] = x.word64s[i] ^ y.word64s[i];
return z;
}
} // namespace
int find_epoch_number(const hash256& seed) noexcept
{
static constexpr int num_tries = 30000; // Divisible by 16.
// Thread-local cache of the last search.
static thread_local int cached_epoch_number = 0;
static thread_local hash256 cached_seed = {};
// Load from memory once (memory will be clobbered by keccak256()).
const uint32_t seed_part = seed.word32s[0];
const int e = cached_epoch_number;
hash256 s = cached_seed;
if (s.word32s[0] == seed_part)
return e;
// Try the next seed, will match for sequential epoch access.
s = keccak256(s);
if (s.word32s[0] == seed_part)
{
cached_seed = s;
cached_epoch_number = e + 1;
return e + 1;
}
// Search for matching seed starting from epoch 0.
s = {};
for (int i = 0; i < num_tries; ++i)
{
if (s.word32s[0] == seed_part)
{
cached_seed = s;
cached_epoch_number = i;
return i;
}
s = keccak256(s);
}
return -1;
}
namespace generic
{
void build_light_cache(
hash_fn_512 hash_fn, hash512 cache[], int num_items, const hash256& seed) noexcept
{
hash512 item = hash_fn(seed.bytes, sizeof(seed));
cache[0] = item;
for (int i = 1; i < num_items; ++i)
{
item = hash_fn(item.bytes, sizeof(item));
cache[i] = item;
}
for (int q = 0; q < light_cache_rounds; ++q)
{
for (int i = 0; i < num_items; ++i)
{
const uint32_t index_limit = static_cast<uint32_t>(num_items);
// Fist index: 4 first bytes of the item as little-endian integer.
const uint32_t t = le::uint32(cache[i].word32s[0]);
const uint32_t v = t % index_limit;
// Second index.
const uint32_t w = static_cast<uint32_t>(num_items + (i - 1)) % index_limit;
const hash512 x = bitwise_xor(cache[v], cache[w]);
cache[i] = hash_fn(x.bytes, sizeof(x));
}
}
}
epoch_context_full* create_epoch_context(
build_light_cache_fn build_fn, int epoch_number, bool full) noexcept
{
static_assert(sizeof(epoch_context_full) < sizeof(hash512), "epoch_context too big");
static constexpr size_t context_alloc_size = sizeof(hash512);
const int light_cache_num_items = calculate_light_cache_num_items(epoch_number);
const int full_dataset_num_items = calculate_full_dataset_num_items(epoch_number);
const size_t light_cache_size = get_light_cache_size(light_cache_num_items);
const size_t full_dataset_size =
full ? static_cast<size_t>(full_dataset_num_items) * sizeof(hash1024) :
progpow::l1_cache_size;
const size_t alloc_size = context_alloc_size + light_cache_size + full_dataset_size;
char* const alloc_data = static_cast<char*>(std::calloc(1, alloc_size));
if (!alloc_data)
return nullptr; // Signal out-of-memory by returning null pointer.
hash512* const light_cache = reinterpret_cast<hash512*>(alloc_data + context_alloc_size);
const hash256 epoch_seed = calculate_epoch_seed(epoch_number);
build_fn(light_cache, light_cache_num_items, epoch_seed);
uint32_t* const l1_cache =
reinterpret_cast<uint32_t*>(alloc_data + context_alloc_size + light_cache_size);
hash1024* full_dataset = full ? reinterpret_cast<hash1024*>(l1_cache) : nullptr;
epoch_context_full* const context = new (alloc_data) epoch_context_full{
epoch_number,
light_cache_num_items,
light_cache,
l1_cache,
full_dataset_num_items,
full_dataset,
};
auto* full_dataset_2048 = reinterpret_cast<hash2048*>(l1_cache);
for (uint32_t i = 0; i < progpow::l1_cache_size / sizeof(full_dataset_2048[0]); ++i)
full_dataset_2048[i] = calculate_dataset_item_2048(*context, i);
return context;
}
} // namespace generic
void build_light_cache(hash512 cache[], int num_items, const hash256& seed) noexcept
{
return generic::build_light_cache(keccak512, cache, num_items, seed);
}
struct item_state
{
const hash512* const cache;
const int64_t num_cache_items;
const uint32_t seed;
hash512 mix;
ALWAYS_INLINE item_state(const epoch_context& context, int64_t index) noexcept
: cache{context.light_cache},
num_cache_items{context.light_cache_num_items},
seed{static_cast<uint32_t>(index)}
{
mix = cache[index % num_cache_items];
mix.word32s[0] ^= le::uint32(seed);
mix = le::uint32s(keccak512(mix));
}
ALWAYS_INLINE void update(uint32_t round) noexcept
{
static constexpr size_t num_words = sizeof(mix) / sizeof(uint32_t);
const uint32_t t = fnv1(seed ^ round, mix.word32s[round % num_words]);
const int64_t parent_index = t % num_cache_items;
mix = fnv1(mix, le::uint32s(cache[parent_index]));
}
ALWAYS_INLINE hash512 final() noexcept { return keccak512(le::uint32s(mix)); }
};
hash512 calculate_dataset_item_512(const epoch_context& context, int64_t index) noexcept
{
item_state item0{context, index};
for (uint32_t j = 0; j < full_dataset_item_parents; ++j)
item0.update(j);
return item0.final();
}
/// Calculates a full dataset item
///
/// This consist of two 512-bit items produced by calculate_dataset_item_partial().
/// Here the computation is done interleaved for better performance.
hash1024 calculate_dataset_item_1024(const epoch_context& context, uint32_t index) noexcept
{
item_state item0{context, int64_t(index) * 2};
item_state item1{context, int64_t(index) * 2 + 1};
for (uint32_t j = 0; j < full_dataset_item_parents; ++j)
{
item0.update(j);
item1.update(j);
}
return hash1024{{item0.final(), item1.final()}};
}
hash2048 calculate_dataset_item_2048(const epoch_context& context, uint32_t index) noexcept
{
item_state item0{context, int64_t(index) * 4};
item_state item1{context, int64_t(index) * 4 + 1};
item_state item2{context, int64_t(index) * 4 + 2};
item_state item3{context, int64_t(index) * 4 + 3};
for (uint32_t j = 0; j < full_dataset_item_parents; ++j)
{
item0.update(j);
item1.update(j);
item2.update(j);
item3.update(j);
}
return hash2048{{item0.final(), item1.final(), item2.final(), item3.final()}};
}
namespace
{
using lookup_fn = hash1024 (*)(const epoch_context&, uint32_t);
inline hash512 hash_seed(const hash256& header_hash, uint64_t nonce) noexcept
{
nonce = le::uint64(nonce);
uint8_t init_data[sizeof(header_hash) + sizeof(nonce)];
std::memcpy(&init_data[0], &header_hash, sizeof(header_hash));
std::memcpy(&init_data[sizeof(header_hash)], &nonce, sizeof(nonce));
return keccak512(init_data, sizeof(init_data));
}
inline hash256 hash_final(const hash512& seed, const hash256& mix_hash)
{
uint8_t final_data[sizeof(seed) + sizeof(mix_hash)];
std::memcpy(&final_data[0], seed.bytes, sizeof(seed));
std::memcpy(&final_data[sizeof(seed)], mix_hash.bytes, sizeof(mix_hash));
return keccak256(final_data, sizeof(final_data));
}
inline hash256 hash_kernel(
const epoch_context& context, const hash512& seed, lookup_fn lookup) noexcept
{
static constexpr size_t num_words = sizeof(hash1024) / sizeof(uint32_t);
const uint32_t index_limit = static_cast<uint32_t>(context.full_dataset_num_items);
const uint32_t seed_init = le::uint32(seed.word32s[0]);
hash1024 mix{{le::uint32s(seed), le::uint32s(seed)}};
for (uint32_t i = 0; i < num_dataset_accesses; ++i)
{
const uint32_t p = fnv1(i ^ seed_init, mix.word32s[i % num_words]) % index_limit;
const hash1024 newdata = le::uint32s(lookup(context, p));
for (size_t j = 0; j < num_words; ++j)
mix.word32s[j] = fnv1(mix.word32s[j], newdata.word32s[j]);
}
hash256 mix_hash;
for (size_t i = 0; i < num_words; i += 4)
{
const uint32_t h1 = fnv1(mix.word32s[i], mix.word32s[i + 1]);
const uint32_t h2 = fnv1(h1, mix.word32s[i + 2]);
const uint32_t h3 = fnv1(h2, mix.word32s[i + 3]);
mix_hash.word32s[i / 4] = h3;
}
return le::uint32s(mix_hash);
}
} // namespace
result hash(const epoch_context& context, const hash256& header_hash, uint64_t nonce) noexcept
{
const hash512 seed = hash_seed(header_hash, nonce);
const hash256 mix_hash = hash_kernel(context, seed, calculate_dataset_item_1024);
return {hash_final(seed, mix_hash), mix_hash};
}
result hash(const epoch_context_full& context, const hash256& header_hash, uint64_t nonce) noexcept
{
static const auto lazy_lookup = [](const epoch_context& context, uint32_t index) noexcept
{
auto full_dataset = static_cast<const epoch_context_full&>(context).full_dataset;
hash1024& item = full_dataset[index];
if (item.word64s[0] == 0)
{
// TODO: Copy elision here makes it thread-safe?
item = calculate_dataset_item_1024(context, index);
}
return item;
};
const hash512 seed = hash_seed(header_hash, nonce);
const hash256 mix_hash = hash_kernel(context, seed, lazy_lookup);
return {hash_final(seed, mix_hash), mix_hash};
}
bool verify_final_hash(const hash256& header_hash, const hash256& mix_hash, uint64_t nonce,
const hash256& boundary) noexcept
{
const hash512 seed = hash_seed(header_hash, nonce);
return is_less_or_equal(hash_final(seed, mix_hash), boundary);
}
bool verify(const epoch_context& context, const hash256& header_hash, const hash256& mix_hash,
uint64_t nonce, const hash256& boundary) noexcept
{
const hash512 seed = hash_seed(header_hash, nonce);
if (!is_less_or_equal(hash_final(seed, mix_hash), boundary))
return false;
const hash256 expected_mix_hash = hash_kernel(context, seed, calculate_dataset_item_1024);
return is_equal(expected_mix_hash, mix_hash);
}
search_result search_light(const epoch_context& context, const hash256& header_hash,
const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept
{
const uint64_t end_nonce = start_nonce + iterations;
for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce)
{
result r = hash(context, header_hash, nonce);
if (is_less_or_equal(r.final_hash, boundary))
return {r, nonce};
}
return {};
}
search_result search(const epoch_context_full& context, const hash256& header_hash,
const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept
{
const uint64_t end_nonce = start_nonce + iterations;
for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce)
{
result r = hash(context, header_hash, nonce);
if (is_less_or_equal(r.final_hash, boundary))
return {r, nonce};
}
return {};
}
} // namespace ethash
using namespace ethash;
extern "C" {
ethash_hash256 ethash_calculate_epoch_seed(int epoch_number) noexcept
{
ethash_hash256 epoch_seed = {};
for (int i = 0; i < epoch_number; ++i)
epoch_seed = ethash_keccak256_32(epoch_seed.bytes);
return epoch_seed;
}
int ethash_calculate_light_cache_num_items(int epoch_number) noexcept
{
static constexpr int item_size = sizeof(hash512);
static constexpr int num_items_init = light_cache_init_size / item_size;
static constexpr int num_items_growth = light_cache_growth / item_size;
static_assert(
light_cache_init_size % item_size == 0, "light_cache_init_size not multiple of item size");
static_assert(
light_cache_growth % item_size == 0, "light_cache_growth not multiple of item size");
int num_items_upper_bound = num_items_init + epoch_number * num_items_growth;
int num_items = ethash_find_largest_prime(num_items_upper_bound);
return num_items;
}
int ethash_calculate_full_dataset_num_items(int epoch_number) noexcept
{
static constexpr int item_size = sizeof(hash1024);
static constexpr int num_items_init = full_dataset_init_size / item_size;
static constexpr int num_items_growth = full_dataset_growth / item_size;
static_assert(full_dataset_init_size % item_size == 0,
"full_dataset_init_size not multiple of item size");
static_assert(
full_dataset_growth % item_size == 0, "full_dataset_growth not multiple of item size");
int num_items_upper_bound = num_items_init + epoch_number * num_items_growth;
int num_items = ethash_find_largest_prime(num_items_upper_bound);
return num_items;
}
epoch_context* ethash_create_epoch_context(int epoch_number) noexcept
{
return generic::create_epoch_context(build_light_cache, epoch_number, false);
}
epoch_context_full* ethash_create_epoch_context_full(int epoch_number) noexcept
{
return generic::create_epoch_context(build_light_cache, epoch_number, true);
}
void ethash_destroy_epoch_context_full(epoch_context_full* context) noexcept
{
ethash_destroy_epoch_context(context);
}
void ethash_destroy_epoch_context(epoch_context* context) noexcept
{
context->~epoch_context();
std::free(context);
}
} // extern "C"

View file

@ -0,0 +1,99 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018 Pawel Bylica.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#pragma once
#include <ethash/hash_types.h>
#include <stdint.h>
#ifdef __cplusplus
#define NOEXCEPT noexcept
#else
#define NOEXCEPT
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* The Ethash algorithm revision implemented as specified in the Ethash spec
* https://github.com/ethereum/wiki/wiki/Ethash.
*/
#define ETHASH_REVISION "23"
#define ETHASH_EPOCH_LENGTH 30000
#define ETHASH_LIGHT_CACHE_ITEM_SIZE 64
#define ETHASH_FULL_DATASET_ITEM_SIZE 128
#define ETHASH_NUM_DATASET_ACCESSES 64
struct ethash_epoch_context
{
const int epoch_number;
const int light_cache_num_items;
const union ethash_hash512* const light_cache;
const uint32_t* const l1_cache;
const int full_dataset_num_items;
};
struct ethash_epoch_context_full;
/**
* Calculates the number of items in the light cache for given epoch.
*
* This function will search for a prime number matching the criteria given
* by the Ethash so the execution time is not constant. It takes ~ 0.01 ms.
*
* @param epoch_number The epoch number.
* @return The number items in the light cache.
*/
int ethash_calculate_light_cache_num_items(int epoch_number) NOEXCEPT;
/**
* Calculates the number of items in the full dataset for given epoch.
*
* This function will search for a prime number matching the criteria given
* by the Ethash so the execution time is not constant. It takes ~ 0.05 ms.
*
* @param epoch_number The epoch number.
* @return The number items in the full dataset.
*/
int ethash_calculate_full_dataset_num_items(int epoch_number) NOEXCEPT;
/**
* Calculates the epoch seed hash.
* @param epoch_number The epoch number.
* @return The epoch seed hash.
*/
union ethash_hash256 ethash_calculate_epoch_seed(int epoch_number) NOEXCEPT;
struct ethash_epoch_context* ethash_create_epoch_context(int epoch_number) NOEXCEPT;
/**
* Creates the epoch context with the full dataset initialized.
*
* The memory for the full dataset is only allocated and marked as "not-generated".
* The items of the full dataset are generated on the fly when hit for the first time.
*
* The memory allocated in the context MUST be freed with ethash_destroy_epoch_context_full().
*
* @param epoch_number The epoch number.
* @return Pointer to the context or null in case of memory allocation failure.
*/
struct ethash_epoch_context_full* ethash_create_epoch_context_full(int epoch_number) NOEXCEPT;
void ethash_destroy_epoch_context(struct ethash_epoch_context* context) NOEXCEPT;
void ethash_destroy_epoch_context_full(struct ethash_epoch_context_full* context) NOEXCEPT;
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,160 @@
// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
// Copyright 2018 Pawel Bylica.
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
/// @file
///
/// API design decisions:
///
/// 1. Signed integer type is used whenever the size of the type is not
/// restricted by the Ethash specification.
/// See http://www.aristeia.com/Papers/C++ReportColumns/sep95.pdf.
/// See https://stackoverflow.com/questions/10168079/why-is-size-t-unsigned/.
/// See https://github.com/Microsoft/GSL/issues/171.
#pragma once
#include <ethash/ethash.h>
#include <ethash/hash_types.hpp>
#include <cstdint>
#include <cstring>
#include <memory>
namespace ethash
{
constexpr auto revision = ETHASH_REVISION;
static constexpr int epoch_length = ETHASH_EPOCH_LENGTH;
static constexpr int light_cache_item_size = ETHASH_LIGHT_CACHE_ITEM_SIZE;
static constexpr int full_dataset_item_size = ETHASH_FULL_DATASET_ITEM_SIZE;
static constexpr int num_dataset_accesses = ETHASH_NUM_DATASET_ACCESSES;
using epoch_context = ethash_epoch_context;
using epoch_context_full = ethash_epoch_context_full;
/// Constructs a 256-bit hash from an array of bytes.
///
/// @param bytes A pointer to array of at least 32 bytes.
/// @return The constructed hash.
inline hash256 hash256_from_bytes(const uint8_t bytes[32]) noexcept
{
hash256 h;
std::memcpy(&h, bytes, sizeof(h));
return h;
}
struct result
{
hash256 final_hash;
hash256 mix_hash;
};
struct search_result
{
bool solution_found = false;
uint64_t nonce = 0;
hash256 final_hash = {};
hash256 mix_hash = {};
search_result() noexcept = default;
search_result(result res, uint64_t nonce) noexcept
: solution_found(true), nonce(nonce), final_hash(res.final_hash), mix_hash(res.mix_hash)
{}
};
/// Alias for ethash_calculate_light_cache_num_items().
static constexpr auto calculate_light_cache_num_items = ethash_calculate_light_cache_num_items;
/// Alias for ethash_calculate_full_dataset_num_items().
static constexpr auto calculate_full_dataset_num_items = ethash_calculate_full_dataset_num_items;
/// Alias for ethash_calculate_epoch_seed().
static constexpr auto calculate_epoch_seed = ethash_calculate_epoch_seed;
/// Calculates the epoch number out of the block number.
inline constexpr int get_epoch_number(int block_number) noexcept
{
return block_number / epoch_length;
}
/**
* Coverts the number of items of a light cache to size in bytes.
*
* @param num_items The number of items in the light cache.
* @return The size of the light cache in bytes.
*/
inline constexpr size_t get_light_cache_size(int num_items) noexcept
{
return static_cast<size_t>(num_items) * light_cache_item_size;
}
/**
* Coverts the number of items of a full dataset to size in bytes.
*
* @param num_items The number of items in the full dataset.
* @return The size of the full dataset in bytes.
*/
inline constexpr uint64_t get_full_dataset_size(int num_items) noexcept
{
return static_cast<uint64_t>(num_items) * full_dataset_item_size;
}
/// Owned unique pointer to an epoch context.
using epoch_context_ptr = std::unique_ptr<epoch_context, decltype(&ethash_destroy_epoch_context)>;
using epoch_context_full_ptr =
std::unique_ptr<epoch_context_full, decltype(&ethash_destroy_epoch_context_full)>;
/// Creates Ethash epoch context.
///
/// This is a wrapper for ethash_create_epoch_number C function that returns
/// the context as a smart pointer which handles the destruction of the context.
inline epoch_context_ptr create_epoch_context(int epoch_number) noexcept
{
return {ethash_create_epoch_context(epoch_number), ethash_destroy_epoch_context};
}
inline epoch_context_full_ptr create_epoch_context_full(int epoch_number) noexcept
{
return {ethash_create_epoch_context_full(epoch_number), ethash_destroy_epoch_context_full};
}
result hash(const epoch_context& context, const hash256& header_hash, uint64_t nonce) noexcept;
result hash(const epoch_context_full& context, const hash256& header_hash, uint64_t nonce) noexcept;
bool verify_final_hash(const hash256& header_hash, const hash256& mix_hash, uint64_t nonce,
const hash256& boundary) noexcept;
bool verify(const epoch_context& context, const hash256& header_hash, const hash256& mix_hash,
uint64_t nonce, const hash256& boundary) noexcept;
search_result search_light(const epoch_context& context, const hash256& header_hash,
const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept;
search_result search(const epoch_context_full& context, const hash256& header_hash,
const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept;
/// Tries to find the epoch number matching the given seed hash.
///
/// Mining pool protocols (many variants of stratum and "getwork") send out
/// seed hash instead of epoch number to workers. This function tries to recover
/// the epoch number from this seed hash.
///
/// @param seed Ethash seed hash.
/// @return The epoch number or -1 if not found.
int find_epoch_number(const hash256& seed) noexcept;
/// Get global shared epoch context.
const epoch_context& get_global_epoch_context(int epoch_number);
/// Get global shared epoch context with full dataset initialized.
const epoch_context_full& get_global_epoch_context_full(int epoch_number);
} // namespace ethash

View file

@ -0,0 +1,46 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018 Pawel Bylica.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
union ethash_hash256
{
uint64_t word64s[4];
uint32_t word32s[8];
uint8_t bytes[32];
};
union ethash_hash512
{
uint64_t word64s[8];
uint32_t word32s[16];
uint8_t bytes[64];
};
union ethash_hash1024
{
union ethash_hash512 hash512s[2];
uint64_t word64s[16];
uint32_t word32s[32];
uint8_t bytes[128];
};
union ethash_hash2048
{
union ethash_hash512 hash512s[4];
uint64_t word64s[32];
uint32_t word32s[64];
uint8_t bytes[256];
};
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,15 @@
// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
// Copyright 2018 Pawel Bylica.
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
#pragma once
#include <ethash/hash_types.h>
namespace ethash
{
using hash256 = ethash_hash256;
using hash512 = ethash_hash512;
using hash1024 = ethash_hash1024;
using hash2048 = ethash_hash2048;
} // namespace ethash

View file

@ -0,0 +1,49 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018 Pawel Bylica.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#pragma once
#include <ethash/hash_types.h>
#include <stddef.h>
#ifdef __cplusplus
#define NOEXCEPT noexcept
#else
#define NOEXCEPT
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* The Keccak-f[1600] function.
*
* The implementation of the Keccak-f function with 1600-bit width of the permutation (b).
* The size of the state is also 1600 bit what gives 25 64-bit words.
*
* @param state The state of 25 64-bit words on which the permutation is to be performed.
*/
void ethash_keccakf1600(uint64_t state[25]) NOEXCEPT;
/**
* The Keccak-f[800] function.
*
* The implementation of the Keccak-f function with 800-bit width of the permutation (b).
* The size of the state is also 800 bit what gives 25 32-bit words.
*
* @param state The state of 25 32-bit words on which the permutation is to be performed.
*/
void ethash_keccakf800(uint32_t state[25]) NOEXCEPT;
union ethash_hash256 ethash_keccak256(const uint8_t* data, size_t size) NOEXCEPT;
union ethash_hash256 ethash_keccak256_32(const uint8_t data[32]) NOEXCEPT;
union ethash_hash512 ethash_keccak512(const uint8_t* data, size_t size) NOEXCEPT;
union ethash_hash512 ethash_keccak512_64(const uint8_t data[64]) NOEXCEPT;
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,35 @@
// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
// Copyright 2018 Pawel Bylica.
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
#pragma once
#include <ethash/keccak.h>
#include <ethash/hash_types.hpp>
namespace ethash
{
inline hash256 keccak256(const uint8_t* data, size_t size) noexcept
{
return ethash_keccak256(data, size);
}
inline hash256 keccak256(const hash256& input) noexcept
{
return ethash_keccak256_32(input.bytes);
}
inline hash512 keccak512(const uint8_t* data, size_t size) noexcept
{
return ethash_keccak512(data, size);
}
inline hash512 keccak512(const hash512& input) noexcept
{
return ethash_keccak512_64(input.bytes);
}
static constexpr auto keccak256_32 = ethash_keccak256_32;
static constexpr auto keccak512_64 = ethash_keccak512_64;
} // namespace ethash

View file

@ -0,0 +1,47 @@
// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
// Copyright 2018 Pawel Bylica.
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
/// @file
///
/// ProgPoW API
///
/// This file provides the public API for ProgPoW as the Ethash API extension.
#include <ethash/ethash.hpp>
namespace progpow
{
using namespace ethash; // Include ethash namespace.
/// The ProgPoW algorithm revision implemented as specified in the spec
/// https://github.com/ifdefelse/ProgPOW#change-history.
constexpr auto revision = "0.9.2";
constexpr int period_length = 50;
constexpr uint32_t num_regs = 32;
constexpr size_t num_lanes = 16;
constexpr int num_cache_accesses = 12;
constexpr int num_math_operations = 20;
constexpr size_t l1_cache_size = 16 * 1024;
constexpr size_t l1_cache_num_items = l1_cache_size / sizeof(uint32_t);
result hash(const epoch_context& context, int block_number, const hash256& header_hash,
uint64_t nonce) noexcept;
result hash(const epoch_context_full& context, int block_number, const hash256& header_hash,
uint64_t nonce) noexcept;
bool verify(const epoch_context& context, int block_number, const hash256& header_hash,
const hash256& mix_hash, uint64_t nonce, const hash256& boundary) noexcept;
search_result search_light(const epoch_context& context, int block_number,
const hash256& header_hash, const hash256& boundary, uint64_t start_nonce,
size_t iterations) noexcept;
search_result search(const epoch_context_full& context, int block_number,
const hash256& header_hash, const hash256& boundary, uint64_t start_nonce,
size_t iterations) noexcept;
} // namespace progpow

View file

@ -0,0 +1,18 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2019 Pawel Bylica.
* Licensed under the Apache License, Version 2.0.
*/
#pragma once
/** The ethash library version. */
#define ETHASH_VERSION "0.4.3"
#ifdef __cplusplus
namespace ethash
{
/// The ethash library version.
constexpr auto version = ETHASH_VERSION;
} // namespace ethash
#endif

View file

@ -0,0 +1,123 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018 Pawel Bylica.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#include <ethash/keccak.h>
#include "support/attributes.h"
#include <string.h>
#if _WIN32
/* On Windows assume little endian. */
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
#define __BYTE_ORDER __LITTLE_ENDIAN
#elif __APPLE__
#include <machine/endian.h>
#else
#include <endian.h>
#endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define to_le64(X) X
#else
#define to_le64(X) __builtin_bswap64(X)
#endif
/** Loads 64-bit integer from given memory location as little-endian number. */
static INLINE ALWAYS_INLINE uint64_t load_le(const uint8_t* data)
{
/* memcpy is the best way of expressing the intention. Every compiler will
optimize is to single load instruction if the target architecture
supports unaligned memory access (GCC and clang even in O0).
This is great trick because we are violating C/C++ memory alignment
restrictions with no performance penalty. */
uint64_t word;
memcpy(&word, data, sizeof(word));
return to_le64(word);
}
static INLINE ALWAYS_INLINE void keccak(
uint64_t* out, size_t bits, const uint8_t* data, size_t size)
{
static const size_t word_size = sizeof(uint64_t);
const size_t hash_size = bits / 8;
const size_t block_size = (1600 - bits * 2) / 8;
size_t i;
uint64_t* state_iter;
uint64_t last_word = 0;
uint8_t* last_word_iter = (uint8_t*)&last_word;
uint64_t state[25] = {0};
while (size >= block_size)
{
for (i = 0; i < (block_size / word_size); ++i)
{
state[i] ^= load_le(data);
data += word_size;
}
ethash_keccakf1600(state);
size -= block_size;
}
state_iter = state;
while (size >= word_size)
{
*state_iter ^= load_le(data);
++state_iter;
data += word_size;
size -= word_size;
}
while (size > 0)
{
*last_word_iter = *data;
++last_word_iter;
++data;
--size;
}
*last_word_iter = 0x01;
*state_iter ^= to_le64(last_word);
state[(block_size / word_size) - 1] ^= 0x8000000000000000;
ethash_keccakf1600(state);
for (i = 0; i < (hash_size / word_size); ++i)
out[i] = to_le64(state[i]);
}
union ethash_hash256 ethash_keccak256(const uint8_t* data, size_t size)
{
union ethash_hash256 hash;
keccak(hash.word64s, 256, data, size);
return hash;
}
union ethash_hash256 ethash_keccak256_32(const uint8_t data[32])
{
union ethash_hash256 hash;
keccak(hash.word64s, 256, data, 32);
return hash;
}
union ethash_hash512 ethash_keccak512(const uint8_t* data, size_t size)
{
union ethash_hash512 hash;
keccak(hash.word64s, 512, data, size);
return hash;
}
union ethash_hash512 ethash_keccak512_64(const uint8_t data[64])
{
union ethash_hash512 hash;
keccak(hash.word64s, 512, data, 64);
return hash;
}

View file

@ -0,0 +1,255 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018 Pawel Bylica.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#include <stdint.h>
static uint64_t rol(uint64_t x, unsigned s)
{
return (x << s) | (x >> (64 - s));
}
static const uint64_t round_constants[24] = {
0x0000000000000001,
0x0000000000008082,
0x800000000000808a,
0x8000000080008000,
0x000000000000808b,
0x0000000080000001,
0x8000000080008081,
0x8000000000008009,
0x000000000000008a,
0x0000000000000088,
0x0000000080008009,
0x000000008000000a,
0x000000008000808b,
0x800000000000008b,
0x8000000000008089,
0x8000000000008003,
0x8000000000008002,
0x8000000000000080,
0x000000000000800a,
0x800000008000000a,
0x8000000080008081,
0x8000000000008080,
0x0000000080000001,
0x8000000080008008,
};
void ethash_keccakf1600(uint64_t state[25])
{
/* The implementation based on the "simple" implementation by Ronny Van Keer. */
int round;
uint64_t Aba, Abe, Abi, Abo, Abu;
uint64_t Aga, Age, Agi, Ago, Agu;
uint64_t Aka, Ake, Aki, Ako, Aku;
uint64_t Ama, Ame, Ami, Amo, Amu;
uint64_t Asa, Ase, Asi, Aso, Asu;
uint64_t Eba, Ebe, Ebi, Ebo, Ebu;
uint64_t Ega, Ege, Egi, Ego, Egu;
uint64_t Eka, Eke, Eki, Eko, Eku;
uint64_t Ema, Eme, Emi, Emo, Emu;
uint64_t Esa, Ese, Esi, Eso, Esu;
uint64_t Ba, Be, Bi, Bo, Bu;
uint64_t Da, De, Di, Do, Du;
Aba = state[0];
Abe = state[1];
Abi = state[2];
Abo = state[3];
Abu = state[4];
Aga = state[5];
Age = state[6];
Agi = state[7];
Ago = state[8];
Agu = state[9];
Aka = state[10];
Ake = state[11];
Aki = state[12];
Ako = state[13];
Aku = state[14];
Ama = state[15];
Ame = state[16];
Ami = state[17];
Amo = state[18];
Amu = state[19];
Asa = state[20];
Ase = state[21];
Asi = state[22];
Aso = state[23];
Asu = state[24];
for (round = 0; round < 24; round += 2)
{
/* Round (round + 0): Axx -> Exx */
Ba = Aba ^ Aga ^ Aka ^ Ama ^ Asa;
Be = Abe ^ Age ^ Ake ^ Ame ^ Ase;
Bi = Abi ^ Agi ^ Aki ^ Ami ^ Asi;
Bo = Abo ^ Ago ^ Ako ^ Amo ^ Aso;
Bu = Abu ^ Agu ^ Aku ^ Amu ^ Asu;
Da = Bu ^ rol(Be, 1);
De = Ba ^ rol(Bi, 1);
Di = Be ^ rol(Bo, 1);
Do = Bi ^ rol(Bu, 1);
Du = Bo ^ rol(Ba, 1);
Ba = Aba ^ Da;
Be = rol(Age ^ De, 44);
Bi = rol(Aki ^ Di, 43);
Bo = rol(Amo ^ Do, 21);
Bu = rol(Asu ^ Du, 14);
Eba = Ba ^ (~Be & Bi) ^ round_constants[round];
Ebe = Be ^ (~Bi & Bo);
Ebi = Bi ^ (~Bo & Bu);
Ebo = Bo ^ (~Bu & Ba);
Ebu = Bu ^ (~Ba & Be);
Ba = rol(Abo ^ Do, 28);
Be = rol(Agu ^ Du, 20);
Bi = rol(Aka ^ Da, 3);
Bo = rol(Ame ^ De, 45);
Bu = rol(Asi ^ Di, 61);
Ega = Ba ^ (~Be & Bi);
Ege = Be ^ (~Bi & Bo);
Egi = Bi ^ (~Bo & Bu);
Ego = Bo ^ (~Bu & Ba);
Egu = Bu ^ (~Ba & Be);
Ba = rol(Abe ^ De, 1);
Be = rol(Agi ^ Di, 6);
Bi = rol(Ako ^ Do, 25);
Bo = rol(Amu ^ Du, 8);
Bu = rol(Asa ^ Da, 18);
Eka = Ba ^ (~Be & Bi);
Eke = Be ^ (~Bi & Bo);
Eki = Bi ^ (~Bo & Bu);
Eko = Bo ^ (~Bu & Ba);
Eku = Bu ^ (~Ba & Be);
Ba = rol(Abu ^ Du, 27);
Be = rol(Aga ^ Da, 36);
Bi = rol(Ake ^ De, 10);
Bo = rol(Ami ^ Di, 15);
Bu = rol(Aso ^ Do, 56);
Ema = Ba ^ (~Be & Bi);
Eme = Be ^ (~Bi & Bo);
Emi = Bi ^ (~Bo & Bu);
Emo = Bo ^ (~Bu & Ba);
Emu = Bu ^ (~Ba & Be);
Ba = rol(Abi ^ Di, 62);
Be = rol(Ago ^ Do, 55);
Bi = rol(Aku ^ Du, 39);
Bo = rol(Ama ^ Da, 41);
Bu = rol(Ase ^ De, 2);
Esa = Ba ^ (~Be & Bi);
Ese = Be ^ (~Bi & Bo);
Esi = Bi ^ (~Bo & Bu);
Eso = Bo ^ (~Bu & Ba);
Esu = Bu ^ (~Ba & Be);
/* Round (round + 1): Exx -> Axx */
Ba = Eba ^ Ega ^ Eka ^ Ema ^ Esa;
Be = Ebe ^ Ege ^ Eke ^ Eme ^ Ese;
Bi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi;
Bo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso;
Bu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu;
Da = Bu ^ rol(Be, 1);
De = Ba ^ rol(Bi, 1);
Di = Be ^ rol(Bo, 1);
Do = Bi ^ rol(Bu, 1);
Du = Bo ^ rol(Ba, 1);
Ba = Eba ^ Da;
Be = rol(Ege ^ De, 44);
Bi = rol(Eki ^ Di, 43);
Bo = rol(Emo ^ Do, 21);
Bu = rol(Esu ^ Du, 14);
Aba = Ba ^ (~Be & Bi) ^ round_constants[round + 1];
Abe = Be ^ (~Bi & Bo);
Abi = Bi ^ (~Bo & Bu);
Abo = Bo ^ (~Bu & Ba);
Abu = Bu ^ (~Ba & Be);
Ba = rol(Ebo ^ Do, 28);
Be = rol(Egu ^ Du, 20);
Bi = rol(Eka ^ Da, 3);
Bo = rol(Eme ^ De, 45);
Bu = rol(Esi ^ Di, 61);
Aga = Ba ^ (~Be & Bi);
Age = Be ^ (~Bi & Bo);
Agi = Bi ^ (~Bo & Bu);
Ago = Bo ^ (~Bu & Ba);
Agu = Bu ^ (~Ba & Be);
Ba = rol(Ebe ^ De, 1);
Be = rol(Egi ^ Di, 6);
Bi = rol(Eko ^ Do, 25);
Bo = rol(Emu ^ Du, 8);
Bu = rol(Esa ^ Da, 18);
Aka = Ba ^ (~Be & Bi);
Ake = Be ^ (~Bi & Bo);
Aki = Bi ^ (~Bo & Bu);
Ako = Bo ^ (~Bu & Ba);
Aku = Bu ^ (~Ba & Be);
Ba = rol(Ebu ^ Du, 27);
Be = rol(Ega ^ Da, 36);
Bi = rol(Eke ^ De, 10);
Bo = rol(Emi ^ Di, 15);
Bu = rol(Eso ^ Do, 56);
Ama = Ba ^ (~Be & Bi);
Ame = Be ^ (~Bi & Bo);
Ami = Bi ^ (~Bo & Bu);
Amo = Bo ^ (~Bu & Ba);
Amu = Bu ^ (~Ba & Be);
Ba = rol(Ebi ^ Di, 62);
Be = rol(Ego ^ Do, 55);
Bi = rol(Eku ^ Du, 39);
Bo = rol(Ema ^ Da, 41);
Bu = rol(Ese ^ De, 2);
Asa = Ba ^ (~Be & Bi);
Ase = Be ^ (~Bi & Bo);
Asi = Bi ^ (~Bo & Bu);
Aso = Bo ^ (~Bu & Ba);
Asu = Bu ^ (~Ba & Be);
}
state[0] = Aba;
state[1] = Abe;
state[2] = Abi;
state[3] = Abo;
state[4] = Abu;
state[5] = Aga;
state[6] = Age;
state[7] = Agi;
state[8] = Ago;
state[9] = Agu;
state[10] = Aka;
state[11] = Ake;
state[12] = Aki;
state[13] = Ako;
state[14] = Aku;
state[15] = Ama;
state[16] = Ame;
state[17] = Ami;
state[18] = Amo;
state[19] = Amu;
state[20] = Asa;
state[21] = Ase;
state[22] = Asi;
state[23] = Aso;
state[24] = Asu;
}

View file

@ -0,0 +1,253 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018 Pawel Bylica.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#include <stdint.h>
static uint32_t rol(uint32_t x, unsigned s)
{
return (x << s) | (x >> (32 - s));
}
static const uint32_t round_constants[22] = {
0x00000001,
0x00008082,
0x0000808A,
0x80008000,
0x0000808B,
0x80000001,
0x80008081,
0x00008009,
0x0000008A,
0x00000088,
0x80008009,
0x8000000A,
0x8000808B,
0x0000008B,
0x00008089,
0x00008003,
0x00008002,
0x00000080,
0x0000800A,
0x8000000A,
0x80008081,
0x00008080,
};
void ethash_keccakf800(uint32_t state[25])
{
/* The implementation directly translated from ethash_keccakf1600. */
int round;
uint32_t Aba, Abe, Abi, Abo, Abu;
uint32_t Aga, Age, Agi, Ago, Agu;
uint32_t Aka, Ake, Aki, Ako, Aku;
uint32_t Ama, Ame, Ami, Amo, Amu;
uint32_t Asa, Ase, Asi, Aso, Asu;
uint32_t Eba, Ebe, Ebi, Ebo, Ebu;
uint32_t Ega, Ege, Egi, Ego, Egu;
uint32_t Eka, Eke, Eki, Eko, Eku;
uint32_t Ema, Eme, Emi, Emo, Emu;
uint32_t Esa, Ese, Esi, Eso, Esu;
uint32_t Ba, Be, Bi, Bo, Bu;
uint32_t Da, De, Di, Do, Du;
Aba = state[0];
Abe = state[1];
Abi = state[2];
Abo = state[3];
Abu = state[4];
Aga = state[5];
Age = state[6];
Agi = state[7];
Ago = state[8];
Agu = state[9];
Aka = state[10];
Ake = state[11];
Aki = state[12];
Ako = state[13];
Aku = state[14];
Ama = state[15];
Ame = state[16];
Ami = state[17];
Amo = state[18];
Amu = state[19];
Asa = state[20];
Ase = state[21];
Asi = state[22];
Aso = state[23];
Asu = state[24];
for (round = 0; round < 22; round += 2)
{
/* Round (round + 0): Axx -> Exx */
Ba = Aba ^ Aga ^ Aka ^ Ama ^ Asa;
Be = Abe ^ Age ^ Ake ^ Ame ^ Ase;
Bi = Abi ^ Agi ^ Aki ^ Ami ^ Asi;
Bo = Abo ^ Ago ^ Ako ^ Amo ^ Aso;
Bu = Abu ^ Agu ^ Aku ^ Amu ^ Asu;
Da = Bu ^ rol(Be, 1);
De = Ba ^ rol(Bi, 1);
Di = Be ^ rol(Bo, 1);
Do = Bi ^ rol(Bu, 1);
Du = Bo ^ rol(Ba, 1);
Ba = Aba ^ Da;
Be = rol(Age ^ De, 12);
Bi = rol(Aki ^ Di, 11);
Bo = rol(Amo ^ Do, 21);
Bu = rol(Asu ^ Du, 14);
Eba = Ba ^ (~Be & Bi) ^ round_constants[round];
Ebe = Be ^ (~Bi & Bo);
Ebi = Bi ^ (~Bo & Bu);
Ebo = Bo ^ (~Bu & Ba);
Ebu = Bu ^ (~Ba & Be);
Ba = rol(Abo ^ Do, 28);
Be = rol(Agu ^ Du, 20);
Bi = rol(Aka ^ Da, 3);
Bo = rol(Ame ^ De, 13);
Bu = rol(Asi ^ Di, 29);
Ega = Ba ^ (~Be & Bi);
Ege = Be ^ (~Bi & Bo);
Egi = Bi ^ (~Bo & Bu);
Ego = Bo ^ (~Bu & Ba);
Egu = Bu ^ (~Ba & Be);
Ba = rol(Abe ^ De, 1);
Be = rol(Agi ^ Di, 6);
Bi = rol(Ako ^ Do, 25);
Bo = rol(Amu ^ Du, 8);
Bu = rol(Asa ^ Da, 18);
Eka = Ba ^ (~Be & Bi);
Eke = Be ^ (~Bi & Bo);
Eki = Bi ^ (~Bo & Bu);
Eko = Bo ^ (~Bu & Ba);
Eku = Bu ^ (~Ba & Be);
Ba = rol(Abu ^ Du, 27);
Be = rol(Aga ^ Da, 4);
Bi = rol(Ake ^ De, 10);
Bo = rol(Ami ^ Di, 15);
Bu = rol(Aso ^ Do, 24);
Ema = Ba ^ (~Be & Bi);
Eme = Be ^ (~Bi & Bo);
Emi = Bi ^ (~Bo & Bu);
Emo = Bo ^ (~Bu & Ba);
Emu = Bu ^ (~Ba & Be);
Ba = rol(Abi ^ Di, 30);
Be = rol(Ago ^ Do, 23);
Bi = rol(Aku ^ Du, 7);
Bo = rol(Ama ^ Da, 9);
Bu = rol(Ase ^ De, 2);
Esa = Ba ^ (~Be & Bi);
Ese = Be ^ (~Bi & Bo);
Esi = Bi ^ (~Bo & Bu);
Eso = Bo ^ (~Bu & Ba);
Esu = Bu ^ (~Ba & Be);
/* Round (round + 1): Exx -> Axx */
Ba = Eba ^ Ega ^ Eka ^ Ema ^ Esa;
Be = Ebe ^ Ege ^ Eke ^ Eme ^ Ese;
Bi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi;
Bo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso;
Bu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu;
Da = Bu ^ rol(Be, 1);
De = Ba ^ rol(Bi, 1);
Di = Be ^ rol(Bo, 1);
Do = Bi ^ rol(Bu, 1);
Du = Bo ^ rol(Ba, 1);
Ba = Eba ^ Da;
Be = rol(Ege ^ De, 12);
Bi = rol(Eki ^ Di, 11);
Bo = rol(Emo ^ Do, 21);
Bu = rol(Esu ^ Du, 14);
Aba = Ba ^ (~Be & Bi) ^ round_constants[round + 1];
Abe = Be ^ (~Bi & Bo);
Abi = Bi ^ (~Bo & Bu);
Abo = Bo ^ (~Bu & Ba);
Abu = Bu ^ (~Ba & Be);
Ba = rol(Ebo ^ Do, 28);
Be = rol(Egu ^ Du, 20);
Bi = rol(Eka ^ Da, 3);
Bo = rol(Eme ^ De, 13);
Bu = rol(Esi ^ Di, 29);
Aga = Ba ^ (~Be & Bi);
Age = Be ^ (~Bi & Bo);
Agi = Bi ^ (~Bo & Bu);
Ago = Bo ^ (~Bu & Ba);
Agu = Bu ^ (~Ba & Be);
Ba = rol(Ebe ^ De, 1);
Be = rol(Egi ^ Di, 6);
Bi = rol(Eko ^ Do, 25);
Bo = rol(Emu ^ Du, 8);
Bu = rol(Esa ^ Da, 18);
Aka = Ba ^ (~Be & Bi);
Ake = Be ^ (~Bi & Bo);
Aki = Bi ^ (~Bo & Bu);
Ako = Bo ^ (~Bu & Ba);
Aku = Bu ^ (~Ba & Be);
Ba = rol(Ebu ^ Du, 27);
Be = rol(Ega ^ Da, 4);
Bi = rol(Eke ^ De, 10);
Bo = rol(Emi ^ Di, 15);
Bu = rol(Eso ^ Do, 24);
Ama = Ba ^ (~Be & Bi);
Ame = Be ^ (~Bi & Bo);
Ami = Bi ^ (~Bo & Bu);
Amo = Bo ^ (~Bu & Ba);
Amu = Bu ^ (~Ba & Be);
Ba = rol(Ebi ^ Di, 30);
Be = rol(Ego ^ Do, 23);
Bi = rol(Eku ^ Du, 7);
Bo = rol(Ema ^ Da, 9);
Bu = rol(Ese ^ De, 2);
Asa = Ba ^ (~Be & Bi);
Ase = Be ^ (~Bi & Bo);
Asi = Bi ^ (~Bo & Bu);
Aso = Bo ^ (~Bu & Ba);
Asu = Bu ^ (~Ba & Be);
}
state[0] = Aba;
state[1] = Abe;
state[2] = Abi;
state[3] = Abo;
state[4] = Abu;
state[5] = Aga;
state[6] = Age;
state[7] = Agi;
state[8] = Ago;
state[9] = Agu;
state[10] = Aka;
state[11] = Ake;
state[12] = Aki;
state[13] = Ako;
state[14] = Aku;
state[15] = Ama;
state[16] = Ame;
state[17] = Ami;
state[18] = Amo;
state[19] = Amu;
state[20] = Asa;
state[21] = Ase;
state[22] = Asi;
state[23] = Aso;
state[24] = Asu;
}

View file

@ -0,0 +1,64 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018 Pawel Bylica.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#pragma once
#include "support/attributes.h"
#include <stdint.h>
/**
* KISS PRNG by the spec from 1999.
*
* The implementation of KISS pseudo-random number generator
* by the specification published on 21 Jan 1999 in
* http://www.cse.yorku.ca/~oz/marsaglia-rng.html.
* The KISS is not versioned so here we are using `kiss99` prefix to indicate
* the version from 1999.
*
* The specification uses `unsigned long` type with the intention for 32-bit
* values. Because in GCC/clang for 64-bit architectures `unsigned long` is
* 64-bit size type, here the explicit `uint32_t` type is used.
*
* @defgroup kiss99 KISS99
* @{
*/
/**
* The KISS generator.
*/
class kiss99
{
uint32_t z = 362436069;
uint32_t w = 521288629;
uint32_t jsr = 123456789;
uint32_t jcong = 380116160;
public:
/** Creates KISS generator state with default values provided by the specification. */
kiss99() noexcept = default;
/** Creates KISS generator state with provided init values.*/
kiss99(uint32_t z, uint32_t w, uint32_t jsr, uint32_t jcong) noexcept
: z{z}, w{w}, jsr{jsr}, jcong{jcong}
{}
/** Generates next number from the KISS generator. */
NO_SANITIZE("unsigned-integer-overflow")
uint32_t operator()() noexcept
{
z = 36969 * (z & 0xffff) + (z >> 16);
w = 18000 * (w & 0xffff) + (w >> 16);
jcong = 69069 * jcong + 1234567;
jsr ^= (jsr << 17);
jsr ^= (jsr >> 13);
jsr ^= (jsr << 5);
return (((z << 16) + w) ^ jcong) + jsr;
}
};
/** @} */

View file

@ -0,0 +1,100 @@
// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
// Copyright 2018 Pawel Bylica.
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
#include "ethash-internal.hpp"
#include <memory>
#include <mutex>
#if !defined(__has_cpp_attribute)
#define __has_cpp_attribute(x) 0
#endif
#if __has_cpp_attribute(gnu::noinline)
#define ATTRIBUTE_NOINLINE [[gnu::noinline]]
#elif _MSC_VER
#define ATTRIBUTE_NOINLINE __declspec(noinline)
#else
#define ATTRIBUTE_NOINLINE
#endif
namespace ethash
{
namespace
{
std::mutex shared_context_mutex;
std::shared_ptr<epoch_context> shared_context;
thread_local std::shared_ptr<epoch_context> thread_local_context;
std::mutex shared_context_full_mutex;
std::shared_ptr<epoch_context_full> shared_context_full;
thread_local std::shared_ptr<epoch_context_full> thread_local_context_full;
/// Update thread local epoch context.
///
/// This function is on the slow path. It's separated to allow inlining the fast
/// path.
///
/// @todo: Redesign to guarantee deallocation before new allocation.
ATTRIBUTE_NOINLINE
void update_local_context(int epoch_number)
{
// Release the shared pointer of the obsoleted context.
thread_local_context.reset();
// Local context invalid, check the shared context.
std::lock_guard<std::mutex> lock{shared_context_mutex};
if (!shared_context || shared_context->epoch_number != epoch_number)
{
// Release the shared pointer of the obsoleted context.
shared_context.reset();
// Build new context.
shared_context = create_epoch_context(epoch_number);
}
thread_local_context = shared_context;
}
ATTRIBUTE_NOINLINE
void update_local_context_full(int epoch_number)
{
// Release the shared pointer of the obsoleted context.
thread_local_context_full.reset();
// Local context invalid, check the shared context.
std::lock_guard<std::mutex> lock{shared_context_full_mutex};
if (!shared_context_full || shared_context_full->epoch_number != epoch_number)
{
// Release the shared pointer of the obsoleted context.
shared_context_full.reset();
// Build new context.
shared_context_full = create_epoch_context_full(epoch_number);
}
thread_local_context_full = shared_context_full;
}
} // namespace
const epoch_context& get_global_epoch_context(int epoch_number)
{
// Check if local context matches epoch number.
if (!thread_local_context || thread_local_context->epoch_number != epoch_number)
update_local_context(epoch_number);
return *thread_local_context;
}
const epoch_context_full& get_global_epoch_context_full(int epoch_number)
{
// Check if local context matches epoch number.
if (!thread_local_context_full || thread_local_context_full->epoch_number != epoch_number)
update_local_context_full(epoch_number);
return *thread_local_context_full;
}
} // namespace ethash

View file

@ -0,0 +1,43 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018 Pawel Bylica.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#include "primes.h"
/** Checks if the number is prime. Requires the number to be > 2 and odd. */
static int is_odd_prime(int number)
{
int d;
/* Check factors up to sqrt(number).
To avoid computing sqrt, compare d*d <= number with 64-bit precision. */
for (d = 3; (int64_t)d * (int64_t)d <= (int64_t)number; d += 2)
{
if (number % d == 0)
return 0;
}
return 1;
}
int ethash_find_largest_prime(int upper_bound)
{
int n = upper_bound;
if (n < 2)
return 0;
if (n == 2)
return 2;
/* If even number, skip it. */
if (n % 2 == 0)
--n;
/* Test descending odd numbers. */
while (!is_odd_prime(n))
n -= 2;
return n;
}

View file

@ -0,0 +1,25 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018 Pawel Bylica.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#pragma once
#include <ethash/ethash.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Finds the largest prime number not greater than the provided upper bound.
*
* @param upper_bound The upper bound. SHOULD be greater than 1.
* @return The largest prime number `p` such `p <= upper_bound`.
* In case `upper_bound <= 1`, returns 0.
*/
int ethash_find_largest_prime(int upper_bound) NOEXCEPT;
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,360 @@
// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
// Copyright 2018 Pawel Bylica.
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
#include <ethash/progpow.hpp>
#include "bit_manipulation.h"
#include "endianness.hpp"
#include "ethash-internal.hpp"
#include "kiss99.hpp"
#include <ethash/keccak.hpp>
#include <array>
namespace progpow
{
namespace
{
/// A variant of Keccak hash function for ProgPoW.
///
/// This Keccak hash function uses 800-bit permutation (Keccak-f[800]) with 576 bitrate.
/// It take exactly 576 bits of input (split across 3 arguments) and adds no padding.
///
/// @param header_hash The 256-bit header hash.
/// @param nonce The 64-bit nonce.
/// @param mix_hash Additional 256-bits of data.
/// @return The 256-bit output of the hash function.
hash256 keccak_progpow_256(
const hash256& header_hash, uint64_t nonce, const hash256& mix_hash) noexcept
{
static constexpr size_t num_words =
sizeof(header_hash.word32s) / sizeof(header_hash.word32s[0]);
uint32_t state[25] = {};
size_t i;
for (i = 0; i < num_words; ++i)
state[i] = le::uint32(header_hash.word32s[i]);
state[i++] = static_cast<uint32_t>(nonce);
state[i++] = static_cast<uint32_t>(nonce >> 32);
for (uint32_t mix_word : mix_hash.word32s)
state[i++] = le::uint32(mix_word);
ethash_keccakf800(state);
hash256 output;
for (i = 0; i < num_words; ++i)
output.word32s[i] = le::uint32(state[i]);
return output;
}
/// The same as keccak_progpow_256() but uses null mix
/// and returns top 64 bits of the output being a big-endian prefix of the 256-bit hash.
inline uint64_t keccak_progpow_64(const hash256& header_hash, uint64_t nonce) noexcept
{
const hash256 h = keccak_progpow_256(header_hash, nonce, {});
return be::uint64(h.word64s[0]);
}
/// ProgPoW mix RNG state.
///
/// Encapsulates the state of the random number generator used in computing ProgPoW mix.
/// This includes the state of the KISS99 RNG and the precomputed random permutation of the
/// sequence of mix item indexes.
class mix_rng_state
{
public:
inline explicit mix_rng_state(uint64_t seed) noexcept;
uint32_t next_dst() noexcept { return dst_seq[(dst_counter++) % num_regs]; }
uint32_t next_src() noexcept { return src_seq[(src_counter++) % num_regs]; }
kiss99 rng;
private:
size_t dst_counter = 0;
std::array<uint32_t, num_regs> dst_seq;
size_t src_counter = 0;
std::array<uint32_t, num_regs> src_seq;
};
mix_rng_state::mix_rng_state(uint64_t seed) noexcept
{
const auto seed_lo = static_cast<uint32_t>(seed);
const auto seed_hi = static_cast<uint32_t>(seed >> 32);
const auto z = fnv1a(fnv_offset_basis, seed_lo);
const auto w = fnv1a(z, seed_hi);
const auto jsr = fnv1a(w, seed_lo);
const auto jcong = fnv1a(jsr, seed_hi);
rng = kiss99{z, w, jsr, jcong};
// Create random permutations of mix destinations / sources.
// Uses Fisher-Yates shuffle.
for (uint32_t i = 0; i < num_regs; ++i)
{
dst_seq[i] = i;
src_seq[i] = i;
}
for (uint32_t i = num_regs; i > 1; --i)
{
std::swap(dst_seq[i - 1], dst_seq[rng() % i]);
std::swap(src_seq[i - 1], src_seq[rng() % i]);
}
}
NO_SANITIZE("unsigned-integer-overflow")
inline uint32_t random_math(uint32_t a, uint32_t b, uint32_t selector) noexcept
{
switch (selector % 11)
{
default:
case 2:
return a + b;
case 3:
return a * b;
case 4:
return mul_hi32(a, b);
case 5:
return std::min(a, b);
case 6:
return rotl32(a, b);
case 7:
return rotr32(a, b);
case 8:
return a & b;
case 9:
return a | b;
case 10:
return a ^ b;
case 0:
return clz32(a) + clz32(b);
case 1:
return popcount32(a) + popcount32(b);
}
}
/// Merge data from `b` and `a`.
/// Assuming `a` has high entropy, only do ops that retain entropy even if `b`
/// has low entropy (i.e. do not do `a & b`).
NO_SANITIZE("unsigned-integer-overflow")
inline void random_merge(uint32_t& a, uint32_t b, uint32_t selector) noexcept
{
const auto x = (selector >> 16) % 31 + 1; // Additional non-zero selector from higher bits.
switch (selector % 4)
{
case 0:
a = (a * 33) + b;
break;
case 1:
a = (a ^ b) * 33;
break;
case 2:
a = rotl32(a, x) ^ b;
break;
case 3:
a = rotr32(a, x) ^ b;
break;
}
}
using lookup_fn = hash2048 (*)(const epoch_context&, uint32_t);
using mix_array = std::array<std::array<uint32_t, num_regs>, num_lanes>;
void round(
const epoch_context& context, uint32_t r, mix_array& mix, mix_rng_state state, lookup_fn lookup)
{
const uint32_t num_items = static_cast<uint32_t>(context.full_dataset_num_items / 2);
const uint32_t item_index = mix[r % num_lanes][0] % num_items;
const hash2048 item = lookup(context, item_index);
constexpr size_t num_words_per_lane = sizeof(item) / (sizeof(uint32_t) * num_lanes);
constexpr int max_operations =
num_cache_accesses > num_math_operations ? num_cache_accesses : num_math_operations;
// Process lanes.
for (int i = 0; i < max_operations; ++i)
{
if (i < num_cache_accesses) // Random access to cached memory.
{
const auto src = state.next_src();
const auto dst = state.next_dst();
const auto sel = state.rng();
for (size_t l = 0; l < num_lanes; ++l)
{
const size_t offset = mix[l][src] % l1_cache_num_items;
random_merge(mix[l][dst], le::uint32(context.l1_cache[offset]), sel);
}
}
if (i < num_math_operations) // Random math.
{
// Generate 2 unique source indexes.
const auto src_rnd = state.rng() % (num_regs * (num_regs - 1));
const auto src1 = src_rnd % num_regs; // O <= src1 < num_regs
auto src2 = src_rnd / num_regs; // 0 <= src2 < num_regs - 1
if (src2 >= src1)
++src2;
const auto sel1 = state.rng();
const auto dst = state.next_dst();
const auto sel2 = state.rng();
for (size_t l = 0; l < num_lanes; ++l)
{
const uint32_t data = random_math(mix[l][src1], mix[l][src2], sel1);
random_merge(mix[l][dst], data, sel2);
}
}
}
// DAG access pattern.
uint32_t dsts[num_words_per_lane];
uint32_t sels[num_words_per_lane];
for (size_t i = 0; i < num_words_per_lane; ++i)
{
dsts[i] = i == 0 ? 0 : state.next_dst();
sels[i] = state.rng();
}
// DAG access.
for (size_t l = 0; l < num_lanes; ++l)
{
const auto offset = ((l ^ r) % num_lanes) * num_words_per_lane;
for (size_t i = 0; i < num_words_per_lane; ++i)
{
const auto word = le::uint32(item.word32s[offset + i]);
random_merge(mix[l][dsts[i]], word, sels[i]);
}
}
}
mix_array init_mix(uint64_t seed)
{
const uint32_t z = fnv1a(fnv_offset_basis, static_cast<uint32_t>(seed));
const uint32_t w = fnv1a(z, static_cast<uint32_t>(seed >> 32));
mix_array mix;
for (uint32_t l = 0; l < mix.size(); ++l)
{
const uint32_t jsr = fnv1a(w, l);
const uint32_t jcong = fnv1a(jsr, l);
kiss99 rng{z, w, jsr, jcong};
for (auto& row : mix[l])
row = rng();
}
return mix;
}
hash256 hash_mix(
const epoch_context& context, int block_number, uint64_t seed, lookup_fn lookup) noexcept
{
auto mix = init_mix(seed);
mix_rng_state state{uint64_t(block_number / period_length)};
for (uint32_t i = 0; i < 64; ++i)
round(context, i, mix, state, lookup);
// Reduce mix data to a single per-lane result.
uint32_t lane_hash[num_lanes];
for (size_t l = 0; l < num_lanes; ++l)
{
lane_hash[l] = fnv_offset_basis;
for (uint32_t i = 0; i < num_regs; ++i)
lane_hash[l] = fnv1a(lane_hash[l], mix[l][i]);
}
// Reduce all lanes to a single 256-bit result.
static constexpr size_t num_words = sizeof(hash256) / sizeof(uint32_t);
hash256 mix_hash;
for (uint32_t& w : mix_hash.word32s)
w = fnv_offset_basis;
for (size_t l = 0; l < num_lanes; ++l)
mix_hash.word32s[l % num_words] = fnv1a(mix_hash.word32s[l % num_words], lane_hash[l]);
return le::uint32s(mix_hash);
}
} // namespace
result hash(const epoch_context& context, int block_number, const hash256& header_hash,
uint64_t nonce) noexcept
{
const uint64_t seed = keccak_progpow_64(header_hash, nonce);
const hash256 mix_hash = hash_mix(context, block_number, seed, calculate_dataset_item_2048);
const hash256 final_hash = keccak_progpow_256(header_hash, seed, mix_hash);
return {final_hash, mix_hash};
}
result hash(const epoch_context_full& context, int block_number, const hash256& header_hash,
uint64_t nonce) noexcept
{
static const auto lazy_lookup = [](const epoch_context& context, uint32_t index) noexcept
{
auto* full_dataset_1024 = static_cast<const epoch_context_full&>(context).full_dataset;
auto* full_dataset_2048 = reinterpret_cast<hash2048*>(full_dataset_1024);
hash2048& item = full_dataset_2048[index];
if (item.word64s[0] == 0)
{
// TODO: Copy elision here makes it thread-safe?
item = calculate_dataset_item_2048(context, index);
}
return item;
};
const uint64_t seed = keccak_progpow_64(header_hash, nonce);
const hash256 mix_hash = hash_mix(context, block_number, seed, lazy_lookup);
const hash256 final_hash = keccak_progpow_256(header_hash, seed, mix_hash);
return {final_hash, mix_hash};
}
bool verify(const epoch_context& context, int block_number, const hash256& header_hash,
const hash256& mix_hash, uint64_t nonce, const hash256& boundary) noexcept
{
const uint64_t seed = keccak_progpow_64(header_hash, nonce);
const hash256 final_hash = keccak_progpow_256(header_hash, seed, mix_hash);
if (!is_less_or_equal(final_hash, boundary))
return false;
const hash256 expected_mix_hash =
hash_mix(context, block_number, seed, calculate_dataset_item_2048);
return is_equal(expected_mix_hash, mix_hash);
}
search_result search_light(const epoch_context& context, int block_number,
const hash256& header_hash, const hash256& boundary, uint64_t start_nonce,
size_t iterations) noexcept
{
const uint64_t end_nonce = start_nonce + iterations;
for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce)
{
result r = hash(context, block_number, header_hash, nonce);
if (is_less_or_equal(r.final_hash, boundary))
return {r, nonce};
}
return {};
}
search_result search(const epoch_context_full& context, int block_number,
const hash256& header_hash, const hash256& boundary, uint64_t start_nonce,
size_t iterations) noexcept
{
const uint64_t end_nonce = start_nonce + iterations;
for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce)
{
result r = hash(context, block_number, header_hash, nonce);
if (is_less_or_equal(r.final_hash, boundary))
return {r, nonce};
}
return {};
}
} // namespace progpow

View file

@ -0,0 +1,33 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018 Pawel Bylica.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#pragma once
/** inline */
#if _MSC_VER || __STDC_VERSION__
#define INLINE inline
#else
#define INLINE
#endif
/** [[always_inline]] */
#if _MSC_VER
#define ALWAYS_INLINE __forceinline
#elif defined(__has_attribute) && __STDC_VERSION__
#if __has_attribute(always_inline)
#define ALWAYS_INLINE __attribute__((always_inline))
#endif
#endif
#if !defined(ALWAYS_INLINE)
#define ALWAYS_INLINE
#endif
/** [[no_sanitize()]] */
#if __clang__
#define NO_SANITIZE(sanitizer) \
__attribute__((no_sanitize(sanitizer)))
#else
#define NO_SANITIZE(sanitizer)
#endif

1
contrib/miniupnp Submodule

@ -0,0 +1 @@
Subproject commit bd836936f7ed7e697f36dff709d00a907644172a

View file

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

View file

@ -1,585 +0,0 @@
$Id: Changelog.txt,v 1.193 2014/02/05 17:26:45 nanard Exp $
miniUPnP client Changelog.
2014/02/05:
handle EINPROGRESS after connect()
2014/02/03:
minixml now handle XML comments
VERSION 1.9 : released 2014/01/31
2014/01/31:
added argument remoteHost to UPNP_GetSpecificPortMappingEntry()
increment API_VERSION to 10
2013/12/09:
--help and -h arguments in upnpc.c
2013/10/07:
fixed potential buffer overrun in miniwget.c
Modified UPNP_GetValidIGD() to check for ExternalIpAddress
2013/08/01:
define MAXHOSTNAMELEN if not already done
2013/06/06:
update upnpreplyparse to allow larger values (128 chars instead of 64)
2013/05/14:
Update upnpreplyparse to take into account "empty" elements
validate upnpreplyparse.c code with "make check"
2013/05/03:
Fix Solaris build thanks to Maciej Małecki
2013/04/27:
Fix testminiwget.sh for BSD
2013/03/23:
Fixed Makefile for *BSD
2013/03/11:
Update Makefile to use JNAerator version 0.11
2013/02/11:
Fix testminiwget.sh for use with dash
Use $(DESTDIR) in Makefile
VERSION 1.8 : released 2013/02/06
2012/10/16:
fix testminiwget with no IPv6 support
2012/09/27:
Rename all include guards to not clash with C99
(7.1.3 Reserved identifiers).
2012/08/30:
Added -e option to upnpc program (set description for port mappings)
2012/08/29:
Python 3 support (thanks to Christopher Foo)
2012/08/11:
Fix a memory link in UPNP_GetValidIGD()
Try to handle scope id in link local IPv6 URL under MS Windows
2012/07/20:
Disable HAS_IP_MREQN on DragonFly BSD
2012/06/28:
GetUPNPUrls() now inserts scope into link-local IPv6 addresses
2012/06/23:
More error return checks in upnpc.c
#define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id
parseURL() now parses IPv6 addresses scope
new parameter for miniwget() : IPv6 address scope
increment API_VERSION to 9
2012/06/20:
fixed CMakeLists.txt
2012/05/29
Improvements in testminiwget.sh
VERSION 1.7 : released 2012/05/24
2012/05/01:
Cleanup settings of CFLAGS in Makefile
Fix signed/unsigned integer comparaisons
2012/04/20:
Allow to specify protocol with TCP or UDP for -A option
2012/04/09:
Only try to fetch XML description once in UPNP_GetValidIGD()
Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments.
2012/04/05:
minor improvements to minihttptestserver.c
2012/03/15:
upnperrors.c returns valid error string for unrecognized error codes
2012/03/08:
make minihttptestserver listen on loopback interface instead of 0.0.0.0
2012/01/25:
Maven installation thanks to Alexey Kuznetsov
2012/01/21:
Replace WIN32 macro by _WIN32
2012/01/19:
Fixes in java wrappers thanks to Alexey Kuznetsov :
https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc
Make and install .deb packages (python) thanks to Alexey Kuznetsov :
https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc
2012/01/07:
The multicast interface can now be specified by name with IPv4.
2012/01/02:
Install man page
2011/11/25:
added header to Port Mappings list in upnpc.c
2011/10/09:
Makefile : make clean now removes jnaerator generated files.
MINIUPNPC_VERSION in miniupnpc.h (updated by make)
2011/09/12:
added rootdescURL to UPNPUrls structure.
VERSION 1.6 : released 2011/07/25
2011/07/25:
Update doc for version 1.6 release
2011/06/18:
Fix for windows in miniwget.c
2011/06/04:
display remote host in port mapping listing
2011/06/03:
Fix in make install : there were missing headers
2011/05/26:
Fix the socket leak in miniwget thanks to Richard Marsh.
Permit to add leaseduration in -a command. Display lease duration.
2011/05/15:
Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6
2011/05/09:
add a test in testminiwget.sh.
more error checking in miniwget.c
2011/05/06:
Adding some tool to test and validate miniwget.c
simplified and debugged miniwget.c
2011/04/11:
moving ReceiveData() to a receivedata.c file.
parsing presentation url
adding IGD v2 WANIPv6FirewallControl commands
2011/04/10:
update of miniupnpcmodule.c
comments in miniwget.c, update in testminiwget
Adding errors codes from IGD v2
new functions in upnpc.c for IGD v2
2011/04/09:
Support for litteral ip v6 address in miniwget
2011/04/08:
Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
Updating APIVERSION
Supporting IPV6 in upnpDiscover()
Adding a -6 option to upnpc command line tool
2011/03/18:
miniwget/parseURL() : return an error when url param is null.
fixing GetListOfPortMappings()
2011/03/14:
upnpDiscover() now reporting an error code.
improvements in comments.
2011/03/11:
adding miniupnpcstrings.h.cmake and CMakeLists.txt files.
2011/02/15:
Implementation of GetListOfPortMappings()
2011/02/07:
updates to minixml to support character data starting with spaces
minixml now support CDATA
upnpreplyparse treats <NewPortListing> specificaly
change in simpleUPnPcommand to return the buffer (simplification)
2011/02/06:
Added leaseDuration argument to AddPortMapping()
Starting to implement GetListOfPortMappings()
2011/01/11:
updating wingenminiupnpcstrings.c
2011/01/04:
improving updateminiupnpcstrings.sh
VERSION 1.5 : released 2011/01/01
2010/12/21:
use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo
2010/12/11:
Improvements on getHTTPResponse() code.
2010/12/09:
new code for miniwget that handle Chunked transfer encoding
using getHTTPResponse() in SOAP call code
Adding MANIFEST.in for 'python setup.py bdist_rpm'
2010/11/25:
changes to minissdpc.c to compile under Win32.
see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729
2010/09/17:
Various improvement to Makefile from Michał Górny
2010/08/05:
Adding the script "external-ip.sh" from Reuben Hawkins
2010/06/09:
update to python module to match modification made on 2010/04/05
update to Java test code to match modification made on 2010/04/05
all UPNP_* function now return an error if the SOAP request failed
at HTTP level.
2010/04/17:
Using GetBestRoute() under win32 in order to find the
right interface to use.
2010/04/12:
Retrying with HTTP/1.1 if HTTP/1.0 failed. see
http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703
2010/04/07:
avoid returning duplicates in upnpDiscover()
2010/04/05:
Create a connecthostport.h/.c with connecthostport() function
and use it in miniwget and miniupnpc.
Use getnameinfo() instead of inet_ntop or inet_ntoa
Work to make miniupnpc IPV6 compatible...
Add java test code.
Big changes in order to support device having both WANIPConnection
and WANPPPConnection.
2010/04/04:
Use getaddrinfo() instead of gethostbyname() in miniwget.
2010/01/06:
#define _DARWIN_C_SOURCE for Mac OS X
2009/12/19:
Improve MinGW32 build
2009/12/11:
adding a MSVC9 project to build the static library and executable
2009/12/10:
Fixing some compilation stuff for Windows/MinGW
2009/12/07:
adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS
some fixes for Windows when using virtual ethernet adapters (it is the
case with VMWare installed).
2009/12/04:
some fixes for AmigaOS compilation
Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked
transfer encoding)
2009/12/03:
updating printIDG and testigddescparse.c for debug.
modifications to compile under AmigaOS
adding a testminiwget program
Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked
transfer encoding
2009/11/26:
fixing updateminiupnpcstrings.sh to take into account
which command that does not return an error code.
VERSION 1.4 : released 2009/10/30
2009/10/16:
using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module.
2009/10/10:
Some fixes for compilation under Solaris
compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464
2009/09/21:
fixing the code to ignore EINTR during connect() calls.
2009/08/07:
Set socket timeout for connect()
Some cleanup in miniwget.c
2009/08/04:
remove multiple redirections with -d in upnpc.c
Print textual error code in upnpc.c
Ignore EINTR during the connect() and poll() calls.
2009/07/29:
fix in updateminiupnpcstrings.sh if OS name contains "/"
Sending a correct value for MX: field in SSDP request
2009/07/20:
Change the Makefile to compile under Mac OS X
Fixed a stackoverflow in getDevicesFromMiniSSDPD()
2009/07/09:
Compile under Haiku
generate miniupnpcstrings.h.in from miniupnpcstrings.h
2009/06/04:
patching to compile under CygWin and cross compile for minGW
VERSION 1.3 :
2009/04/17:
updating python module
Use strtoull() when using C99
2009/02/28:
Fixed miniwget.c for compiling under sun
2008/12/18:
cleanup in Makefile (thanks to Paul de Weerd)
minissdpc.c : win32 compatibility
miniupnpc.c : changed xmlns prefix from 'm' to 'u'
Removed NDEBUG (using DEBUG)
2008/10/14:
Added the ExternalHost argument to DeletePortMapping()
2008/10/11:
Added the ExternalHost argument to AddPortMapping()
Put a correct User-Agent: header in HTTP requests.
VERSION 1.2 :
2008/10/07:
Update docs
2008/09/25:
Integrated sameport patch from Dario Meloni : Added a "sameport"
argument to upnpDiscover().
2008/07/18:
small modif to make Clang happy :)
2008/07/17:
#define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV...
2008/07/14:
include declspec.h in installation (to /usr/include/miniupnpc)
VERSION 1.1 :
2008/07/04:
standard options for install/ln instead of gnu-specific stuff.
2008/07/03:
now builds a .dll and .lib with win32. (mingw32)
2008/04/28:
make install now install the binary of the upnpc tool
2008/04/27:
added testupnpigd.py
added error strings for miniupnpc "internal" errors
improved python module error/exception reporting.
2008/04/23:
Completely rewrite igd_desc_parse.c in order to be compatible with
Linksys WAG200G
Added testigddescparse
updated python module
VERSION 1.0 :
2008/02/21:
put some #ifdef DEBUG around DisplayNameValueList()
2008/02/18:
Improved error reporting in upnpcommands.c
UPNP_GetStatusInfo() returns LastConnectionError
2008/02/16:
better error handling in minisoap.c
improving display of "valid IGD found" in upnpc.c
2008/02/03:
Fixing UPNP_GetValidIGD()
improved make install :)
2007/12/22:
Adding upnperrors.c/h to provide a strupnperror() function
used to translate UPnP error codes to string.
2007/12/19:
Fixing getDevicesFromMiniSSDPD()
improved error reporting of UPnP functions
2007/12/18:
It is now possible to specify a different location for MiniSSDPd socket.
working with MiniSSDPd is now more efficient.
python module improved.
2007/12/16:
improving error reporting
2007/12/13:
Try to improve compatibility by using HTTP/1.0 instead of 1.1 and
XML a bit different for SOAP.
2007/11/25:
fixed select() call for linux
2007/11/15:
Added -fPIC to CFLAG for better shared library code.
2007/11/02:
Fixed a potential socket leak in miniwget2()
2007/10/16:
added a parameter to upnpDiscover() in order to allow the use of another
interface than the default multicast interface.
2007/10/12:
Fixed the creation of symbolic link in Makefile
2007/10/08:
Added man page
2007/10/02:
fixed memory bug in GetUPNPUrls()
2007/10/01:
fixes in the Makefile
Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly.
Added SONAME in the shared library to please debian :)
fixed MS Windows compilation (minissdpd is not available under MS Windows).
2007/09/25:
small change to Makefile to be able to install in a different location
(default is /usr)
2007/09/24:
now compiling both shared and static library
2007/09/19:
Cosmetic changes on upnpc.c
2007/09/02:
adapting to new miniSSDPd (release version ?)
2007/08/31:
Usage of miniSSDPd to skip discovery process.
2007/08/27:
fixed python module to allow compilation with Python older than Python 2.4
2007/06/12:
Added a python module.
2007/05/19:
Fixed compilation under MinGW
2007/05/15:
fixed a memory leak in AddPortMapping()
Added testupnpreplyparse executable to check the parsing of
upnp soap messages
minixml now ignore namespace prefixes.
2007/04/26:
upnpc now displays external ip address with -s or -l
2007/04/11:
changed MINIUPNPC_URL_MAXSIZE to 128 to accomodate the "BT Voyager 210"
2007/03/19:
cleanup in miniwget.c
2007/03/01:
Small typo fix...
2007/01/30:
Now parsing the HTTP header from SOAP responses in order to
get content-length value.
2007/01/29:
Fixed the Soap Query to speedup the HTTP request.
added some Win32 DLL stuff...
2007/01/27:
Fixed some WIN32 compatibility issues
2006/12/14:
Added UPNPIGD_IsConnected() function in miniupnp.c/.h
Added UPNP_GetValidIGD() in miniupnp.c/.h
cleaned upnpc.c main(). now using UPNP_GetValidIGD()
2006/12/07:
Version 1.0-RC1 released
2006/12/03:
Minor changes to compile under SunOS/Solaris
2006/11/30:
made a minixml parser validator program
updated minixml to handle attributes correctly
2006/11/22:
Added a -r option to the upnpc sample thanks to Alexander Hubmann.
2006/11/19:
Cleanup code to make it more ANSI C compliant
2006/11/10:
detect and display local lan address.
2006/11/04:
Packets and Bytes Sent/Received are now unsigned int.
2006/11/01:
Bug fix thanks to Giuseppe D'Angelo
2006/10/31:
C++ compatibility for .h files.
Added a way to get ip Address on the LAN used to reach the IGD.
2006/10/25:
Added M-SEARCH to the services in the discovery process.
2006/10/22:
updated the Makefile to use makedepend, added a "make install"
update Makefile
2006/10/20:
fixing the description url parsing thanks to patch sent by
Wayne Dawe.
Fixed/translated some comments.
Implemented a better discover process, first looking
for IGD then for root devices (as some devices only reply to
M-SEARCH for root devices).
2006/09/02:
added freeUPNPDevlist() function.
2006/08/04:
More command line arguments checking
2006/08/01:
Added the .bat file to compile under Win32 with minGW32
2006/07/31:
Fixed the rootdesc parser (igd_desc_parse.c)
2006/07/20:
parseMSEARCHReply() is now returning the ST: line as well
starting changes to detect several UPnP devices on the network
2006/07/19:
using GetCommonLinkProperties to get down/upload bitrate

View file

@ -1,27 +0,0 @@
MiniUPnPc
Copyright (c) 2005-2011, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,5 +0,0 @@
include README
include miniupnpcmodule.c
include setup.py
include *.h
include libminiupnpc.a

View file

@ -1,319 +0,0 @@
# $Id: Makefile,v 1.107 2014/01/31 14:19:12 nanard Exp $
# MiniUPnP Project
# http://miniupnp.free.fr/
# http://miniupnp.tuxfamily.org/
# https://github.com/miniupnp/miniupnp
# (c) 2005-2014 Thomas Bernard
# to install use :
# $ make DESTDIR=/tmp/dummylocation install
# or
# $ INSTALLPREFIX=/usr/local make install
# or
# $ make install (default INSTALLPREFIX is /usr)
OS = $(shell uname -s)
VERSION = $(shell cat VERSION)
ifeq ($(OS), Darwin)
JARSUFFIX=mac
endif
ifeq ($(OS), Linux)
JARSUFFIX=linux
endif
ifneq (,$(findstring NT-5.1,$(OS)))
JARSUFFIX=win32
endif
HAVE_IPV6 ?= yes
export HAVE_IPV6
CC ?= gcc
#AR = gar
#CFLAGS = -O -g -DDEBUG
CFLAGS ?= -O
CFLAGS += -Wall
CFLAGS += -W -Wstrict-prototypes
CFLAGS += -fno-common
CFLAGS += -DMINIUPNPC_SET_SOCKET_TIMEOUT
CFLAGS += -DMINIUPNPC_GET_SRC_ADDR
CFLAGS += -D_BSD_SOURCE -D_POSIX_C_SOURCE=1
CFLAGS += -ansi
# -DNO_GETADDRINFO
INSTALL = install
SH = /bin/sh
JAVA = java
# see http://code.google.com/p/jnaerator/
#JNAERATOR = jnaerator-0.9.7.jar
#JNAERATOR = jnaerator-0.9.8-shaded.jar
#JNAERATORARGS = -library miniupnpc
#JNAERATOR = jnaerator-0.10-shaded.jar
JNAERATOR = jnaerator-0.11-shaded.jar
JNAERATORARGS = -mode StandaloneJar -runtime JNAerator -library miniupnpc
JNAERATORBASEURL = http://jnaerator.googlecode.com/files/
ifeq (SunOS, $(OS))
LDFLAGS=-lsocket -lnsl -lresolv
endif
# APIVERSION is used to build SONAME
APIVERSION = 10
SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \
upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \
minixmlvalid.c testupnpreplyparse.c minissdpc.c \
upnperrors.c testigddescparse.c testminiwget.c \
connecthostport.c portlistingparse.c receivedata.c
LIBOBJS = miniwget.o minixml.o igd_desc_parse.o minisoap.o \
miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \
connecthostport.o portlistingparse.o receivedata.o
ifneq ($(OS), AmigaOS)
CFLAGS := -fPIC $(CFLAGS)
LIBOBJS := $(LIBOBJS) minissdpc.o
endif
OBJS = $(patsubst %.c,%.o,$(SRCS))
# HEADERS to install
HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \
upnpreplyparse.h upnperrors.h miniupnpctypes.h \
portlistingparse.h \
declspec.h
# library names
LIBRARY = libminiupnpc.a
ifeq ($(OS), Darwin)
SHAREDLIBRARY = libminiupnpc.dylib
SONAME = $(basename $(SHAREDLIBRARY)).$(APIVERSION).dylib
CFLAGS := -DMACOSX -D_DARWIN_C_SOURCE $(CFLAGS)
else
ifeq ($(JARSUFFIX), win32)
SHAREDLIBRARY = miniupnpc.dll
else
# Linux/BSD/etc.
SHAREDLIBRARY = libminiupnpc.so
SONAME = $(SHAREDLIBRARY).$(APIVERSION)
endif
endif
EXECUTABLES = upnpc-static
EXECUTABLES_ADDTESTS = testminixml minixmlvalid testupnpreplyparse \
testigddescparse testminiwget
TESTMINIXMLOBJS = minixml.o igd_desc_parse.o testminixml.o
TESTMINIWGETOBJS = miniwget.o testminiwget.o connecthostport.o receivedata.o
TESTUPNPREPLYPARSE = testupnpreplyparse.o minixml.o upnpreplyparse.o
TESTIGDDESCPARSE = testigddescparse.o igd_desc_parse.o minixml.o \
miniupnpc.o miniwget.o upnpcommands.o upnpreplyparse.o \
minisoap.o connecthostport.o receivedata.o \
portlistingparse.o
ifneq ($(OS), AmigaOS)
EXECUTABLES := $(EXECUTABLES) upnpc-shared
TESTMINIWGETOBJS := $(TESTMINIWGETOBJS) minissdpc.o
TESTIGDDESCPARSE := $(TESTIGDDESCPARSE) minissdpc.o
endif
LIBDIR ?= lib
# install directories
INSTALLPREFIX ?= $(PREFIX)/usr
INSTALLDIRINC = $(INSTALLPREFIX)/include/miniupnpc
INSTALLDIRLIB = $(INSTALLPREFIX)/$(LIBDIR)
INSTALLDIRBIN = $(INSTALLPREFIX)/bin
INSTALLDIRMAN = $(INSTALLPREFIX)/share/man
FILESTOINSTALL = $(LIBRARY) $(EXECUTABLES)
ifneq ($(OS), AmigaOS)
FILESTOINSTALL := $(FILESTOINSTALL) $(SHAREDLIBRARY)
endif
.PHONY: install clean depend all check test everything \
installpythonmodule updateversion
# validateminixml validateminiwget
all: $(LIBRARY) $(EXECUTABLES)
test: check
check: validateminixml validateminiwget validateupnpreplyparse
everything: all $(EXECUTABLES_ADDTESTS)
pythonmodule: $(LIBRARY) miniupnpcmodule.c setup.py
python setup.py build
touch $@
installpythonmodule: pythonmodule
python setup.py install
pythonmodule3: $(LIBRARY) miniupnpcmodule.c setup.py
python3 setup.py build
touch $@
installpythonmodule3: pythonmodule3
python3 setup.py install
validateminixml: minixmlvalid
@echo "minixml validation test"
./minixmlvalid
touch $@
validateminiwget: testminiwget minihttptestserver testminiwget.sh
@echo "miniwget validation test"
./testminiwget.sh
touch $@
validateupnpreplyparse: testupnpreplyparse testupnpreplyparse.sh
@echo "upnpreplyparse validation test"
./testupnpreplyparse.sh
touch $@
clean:
$(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h
# clean python stuff
$(RM) pythonmodule pythonmodule3
$(RM) validateminixml validateminiwget validateupnpreplyparse
$(RM) -r build/ dist/
#python setup.py clean
# clean jnaerator stuff
$(RM) _jnaerator.* java/miniupnpc_$(OS).jar
distclean: clean
$(RM) $(JNAERATOR) java/*.jar java/*.class out.errors.txt
updateversion: miniupnpc.h
cp miniupnpc.h miniupnpc.h.bak
sed 's/\(.*MINIUPNPC_API_VERSION\s\+\)[0-9]\+/\1$(APIVERSION)/' < miniupnpc.h.bak > miniupnpc.h
install: updateversion $(FILESTOINSTALL)
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC)
$(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC)
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB)
$(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB)
ifneq ($(OS), AmigaOS)
$(INSTALL) -m 644 $(SHAREDLIBRARY) $(DESTDIR)$(INSTALLDIRLIB)/$(SONAME)
ln -fs $(SONAME) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY)
endif
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN)
ifeq ($(OS), AmigaOS)
$(INSTALL) -m 755 upnpc-static $(DESTDIR)$(INSTALLDIRBIN)/upnpc
else
$(INSTALL) -m 755 upnpc-shared $(DESTDIR)$(INSTALLDIRBIN)/upnpc
endif
$(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip
ifneq ($(OS), AmigaOS)
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRMAN)/man3
$(INSTALL) man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
ifeq ($(OS), Linux)
gzip $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
endif
endif
cleaninstall:
$(RM) -r $(DESTDIR)$(INSTALLDIRINC)
$(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(LIBRARY)
$(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY)
depend:
makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null
$(LIBRARY): $(LIBOBJS)
$(AR) crs $@ $?
$(SHAREDLIBRARY): $(LIBOBJS)
ifeq ($(OS), Darwin)
# $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(SONAME) -o $@ $^
$(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(INSTALLDIRLIB)/$(SONAME) -o $@ $^
else
$(CC) -shared $(LDFLAGS) -Wl,-soname,$(SONAME) -o $@ $^
endif
upnpc-static: upnpc.o $(LIBRARY)
$(CC) $(LDFLAGS) -o $@ $^
upnpc-shared: upnpc.o $(SHAREDLIBRARY)
$(CC) $(LDFLAGS) -o $@ $^
testminixml: $(TESTMINIXMLOBJS)
testminiwget: $(TESTMINIWGETOBJS)
minixmlvalid: minixml.o minixmlvalid.o
testupnpreplyparse: $(TESTUPNPREPLYPARSE)
testigddescparse: $(TESTIGDDESCPARSE)
miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh VERSION
$(SH) updateminiupnpcstrings.sh
# ftp tool supplied with OpenBSD can download files from http.
jnaerator-%.jar:
wget $(JNAERATORBASEURL)/$@ || \
curl -o $@ $(JNAERATORBASEURL)/$@ || \
ftp $(JNAERATORBASEURL)/$@
jar: $(SHAREDLIBRARY) $(JNAERATOR)
$(JAVA) -jar $(JNAERATOR) $(JNAERATORARGS) \
miniupnpc.h declspec.h upnpcommands.h upnpreplyparse.h \
igd_desc_parse.h miniwget.h upnperrors.h $(SHAREDLIBRARY) \
-package fr.free.miniupnp -o . -jar java/miniupnpc_$(JARSUFFIX).jar -v
mvn_install:
mvn install:install-file -Dfile=java/miniupnpc_$(JARSUFFIX).jar \
-DgroupId=com.github \
-DartifactId=miniupnp \
-Dversion=$(VERSION) \
-Dpackaging=jar \
-Dclassifier=$(JARSUFFIX) \
-DgeneratePom=true \
-DcreateChecksum=true
# make .deb packages
deb: /usr/share/pyshared/stdeb all
(python setup.py --command-packages=stdeb.command bdist_deb)
# install .deb packages
ideb:
(sudo dpkg -i deb_dist/*.deb)
/usr/share/pyshared/stdeb: /usr/share/doc/python-all-dev
(sudo apt-get install python-stdeb)
/usr/share/doc/python-all-dev:
(sudo apt-get install python-all-dev)
minihttptestserver: minihttptestserver.o
# DO NOT DELETE THIS LINE -- make depend depends on it.
igd_desc_parse.o: igd_desc_parse.h
miniupnpc.o: miniupnpc.h declspec.h igd_desc_parse.h minissdpc.h miniwget.h
miniupnpc.o: minisoap.h minixml.h upnpcommands.h upnpreplyparse.h
miniupnpc.o: portlistingparse.h miniupnpctypes.h connecthostport.h
miniupnpc.o: receivedata.h
minixml.o: minixml.h
minisoap.o: minisoap.h miniupnpcstrings.h
miniwget.o: miniupnpcstrings.h miniwget.h declspec.h connecthostport.h
miniwget.o: receivedata.h
upnpc.o: miniwget.h declspec.h miniupnpc.h igd_desc_parse.h upnpcommands.h
upnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h upnperrors.h
upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h declspec.h
upnpcommands.o: miniupnpctypes.h miniupnpc.h igd_desc_parse.h
upnpreplyparse.o: upnpreplyparse.h minixml.h
testminixml.o: minixml.h igd_desc_parse.h
minixmlvalid.o: minixml.h
testupnpreplyparse.o: upnpreplyparse.h
minissdpc.o: minissdpc.h miniupnpc.h declspec.h igd_desc_parse.h codelength.h
upnperrors.o: upnperrors.h declspec.h upnpcommands.h upnpreplyparse.h
upnperrors.o: portlistingparse.h miniupnpctypes.h miniupnpc.h
upnperrors.o: igd_desc_parse.h
testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.h declspec.h
testminiwget.o: miniwget.h declspec.h
connecthostport.o: connecthostport.h
receivedata.o: receivedata.h

View file

@ -1,91 +0,0 @@
# $Id: Makefile.mingw,v 1.18 2014/01/17 09:04:01 nanard Exp $
# Miniupnp project.
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
# (c) 2005-2014 Thomas Bernard
# This Makefile is made for MinGW
#
CC = gcc
#CFLAGS = -Wall -g -DDEBUG -D_WIN32_WINNT=0X501
CFLAGS = -Wall -Os -DNDEBUG -D_WIN32_WINNT=0X501
LDLIBS = -lws2_32 -liphlpapi
# -lwsock32
# -liphlpapi is needed for GetBestRoute() and GetIpAddrTable()
PYTHON=\utils\python25\python
OBJS=miniwget.o minixml.o igd_desc_parse.o minisoap.o \
miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \
connecthostport.o portlistingparse.o receivedata.o
OBJSDLL=$(addprefix dll/, $(OBJS))
all: init upnpc-static upnpc-shared testminixml libminiupnpc.a miniupnpc.dll
init:
mkdir dll
echo init > init
clean:
del upnpc testminixml *.o
del dll\*.o
del *.exe
del miniupnpc.dll
del libminiupnpc.a
libminiupnpc.a: $(OBJS)
$(AR) cr $@ $?
pythonmodule: libminiupnpc.a
$(PYTHON) setupmingw32.py build --compiler=mingw32
$(PYTHON) setupmingw32.py install --skip-build
miniupnpc.dll: libminiupnpc.a $(OBJSDLL)
dllwrap -k --driver-name gcc \
--def miniupnpc.def \
--output-def miniupnpc.dll.def \
--implib miniupnpc.lib -o $@ \
$(OBJSDLL) $(LDLIBS)
miniupnpc.lib: miniupnpc.dll
echo $@ generated with $<
dll/upnpc.o: upnpc.o
echo $@ generated with $<
.c.o:
$(CC) $(CFLAGS) -DSTATICLIB -c -o $@ $<
$(CC) $(CFLAGS) -DMINIUPNP_EXPORTS -c -o dll/$@ $<
upnpc.o:
$(CC) $(CFLAGS) -DSTATICLIB -c -o $@ $<
$(CC) $(CFLAGS) -c -o dll/$@ $<
# --enable-stdcall-fixup
upnpc-static: upnpc.o libminiupnpc.a
$(CC) -o $@ $^ $(LDLIBS)
upnpc-shared: dll/upnpc.o miniupnpc.lib
$(CC) -o $@ $^ $(LDLIBS)
wingenminiupnpcstrings: wingenminiupnpcstrings.o
wingenminiupnpcstrings.o: wingenminiupnpcstrings.c
miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings
wingenminiupnpcstrings $< $@
minixml.o: minixml.c minixml.h miniupnpcstrings.h
upnpc.o: upnpc.c miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h upnpreplyparse.h upnpcommands.h upnperrors.h
miniwget.o: miniwget.c miniwget.h miniupnpcstrings.h connecthostport.h
minisoap.o: minisoap.c minisoap.h miniupnpcstrings.h
miniupnpc.o: miniupnpc.c miniupnpc.h minisoap.h miniwget.h minixml.h
igd_desc_parse.o: igd_desc_parse.c igd_desc_parse.h
testminixml: minixml.o igd_desc_parse.o testminixml.c
upnpreplyparse.o: upnpreplyparse.c upnpreplyparse.h minixml.h
upnpcommands.o: upnpcommands.c upnpcommands.h upnpreplyparse.h miniupnpc.h portlistingparse.h

View file

@ -1,66 +0,0 @@
Project: miniupnp
Project web page: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
github: https://github.com/miniupnp/miniupnp
freecode: http://freecode.com/projects/miniupnp
Author: Thomas Bernard
Copyright (c) 2005-2012 Thomas Bernard
This software is subject to the conditions detailed in the
LICENSE file provided within this distribution.
For the comfort of Win32 users, bsdqueue.h is included in the distribution.
Its licence is included in the header of the file.
bsdqueue.h is a copy of the sys/queue.h of an OpenBSD system.
* miniUPnP Client - miniUPnPc *
To compile, simply run 'gmake' (could be 'make' on your system).
Under win32, to compile with MinGW, type "mingw32make.bat".
MS Visual C solution and project files are supplied in the msvc/ subdirectory.
The compilation is known to work under linux, FreeBSD,
OpenBSD, MacOS X, AmigaOS and cygwin.
The official AmigaOS4.1 SDK was used for AmigaOS4 and GeekGadgets for AmigaOS3.
upx (http://upx.sourceforge.net) is used to compress the win32 .exe files.
To install the library and headers on the system use :
> su
> make install
> exit
alternatively, to install into a specific location, use :
> INSTALLPREFIX=/usr/local make install
upnpc.c is a sample client using the libminiupnpc.
To use the libminiupnpc in your application, link it with
libminiupnpc.a (or .so) and use the following functions found in miniupnpc.h,
upnpcommands.h and miniwget.h :
- upnpDiscover()
- miniwget()
- parserootdesc()
- GetUPNPUrls()
- UPNP_* (calling UPNP methods)
Note : use #include <miniupnpc/miniupnpc.h> etc... for the includes
and -lminiupnpc for the link
Discovery process is speeded up when MiniSSDPd is running on the machine.
* Python module *
you can build a python module with 'make pythonmodule'
and install it with 'make installpythonmodule'.
setup.py (and setupmingw32.py) are included in the distribution.
Feel free to contact me if you have any problem :
e-mail : miniupnp@free.fr
If you are using libminiupnpc in your application, please
send me an email !
For any question, you can use the web forum :
http://miniupnp.tuxfamily.org/forum/

View file

@ -1 +0,0 @@
1.9

View file

@ -1,127 +0,0 @@
$Id: apiversions.txt,v 1.3 2014/01/31 13:14:32 nanard Exp $
Differences in API between miniUPnPc versions
====================== miniUPnPc version 1.9 ======================
API version 10
upnpcommands.h:
added argument remoteHost to UPNP_GetSpecificPortMappingEntry()
miniupnpc.h:
updated macros :
#define MINIUPNPC_VERSION "1.9"
#define MINIUPNPC_API_VERSION 10
====================== miniUPnPc version 1.8 ======================
API version 9
miniupnpc.h:
updated macros :
#define MINIUPNPC_VERSION "1.8"
#define MINIUPNPC_API_VERSION 9
added "unsigned int scope_id;" to struct UPNPDev
added scope_id argument to GetUPNPUrls()
====================== miniUPnPc version 1.7 ======================
API version 8
miniupnpc.h :
add new macros :
#define MINIUPNPC_VERSION "1.7"
#define MINIUPNPC_API_VERSION 8
add rootdescURL to struct UPNPUrls
====================== miniUPnPc version 1.6 ======================
API version 8
Adding support for IPv6.
igd_desc_parse.h :
struct IGDdatas_service :
add char presentationurl[MINIUPNPC_URL_MAXSIZE];
struct IGDdatas :
add struct IGDdatas_service IPv6FC;
miniupnpc.h :
new macros :
#define UPNPDISCOVER_SUCCESS (0)
#define UPNPDISCOVER_UNKNOWN_ERROR (-1)
#define UPNPDISCOVER_SOCKET_ERROR (-101)
#define UPNPDISCOVER_MEMORY_ERROR (-102)
simpleUPnPcommand() prototype changed (but is normaly not used by API users)
add arguments ipv6 and error to upnpDiscover() :
struct UPNPDev *
upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
int ipv6,
int * error);
add controlURL_6FC member to struct UPNPUrls :
struct UPNPUrls {
char * controlURL;
char * ipcondescURL;
char * controlURL_CIF;
char * controlURL_6FC;
};
upnpcommands.h :
add leaseDuration argument to UPNP_AddPortMapping()
add desc, enabled and leaseDuration arguments to UPNP_GetSpecificPortMappingEntry()
add UPNP_GetListOfPortMappings() function (IGDv2)
add IGDv2 IPv6 related functions :
UPNP_GetFirewallStatus()
UPNP_GetOutboundPinholeTimeout()
UPNP_AddPinhole()
UPNP_UpdatePinhole()
UPNP_DeletePinhole()
UPNP_CheckPinholeWorking()
UPNP_GetPinholePackets()
====================== miniUPnPc version 1.5 ======================
API version 5
new function :
int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
new macro in upnpcommands.h :
#define UPNPCOMMAND_HTTP_ERROR
====================== miniUPnPc version 1.4 ======================
Same API as version 1.3
====================== miniUPnPc version 1.3 ======================
API version 4
Use UNSIGNED_INTEGER type for
UPNP_GetTotalBytesSent(), UPNP_GetTotalBytesReceived(),
UPNP_GetTotalPacketsSent(), UPNP_GetTotalPacketsReceived()
Add remoteHost argument to UPNP_AddPortMapping() and UPNP_DeletePortMapping()
====================== miniUPnPc version 1.2 ======================
API version 3
added sameport argument to upnpDiscover()
struct UPNPDev *
upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int sameport);
====================== miniUPnPc Version 1.1 ======================
Same API as 1.0
====================== miniUPnPc Version 1.0 ======================
API version 2
struct UPNPDev {
struct UPNPDev * pNext;
char * descURL;
char * st;
char buffer[2];
};
struct UPNPDev * upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock);

View file

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

View file

@ -1,31 +0,0 @@
/* $Id: codelength.h,v 1.4 2012/09/27 15:40:29 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas BERNARD
* copyright (c) 2005-2011 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#ifndef CODELENGTH_H_INCLUDED
#define CODELENGTH_H_INCLUDED
/* Encode length by using 7bit per Byte :
* Most significant bit of each byte specifies that the
* following byte is part of the code */
#define DECODELENGTH(n, p) n = 0; \
do { n = (n << 7) | (*p & 0x7f); } \
while((*(p++)&0x80) && (n<(1<<25)));
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
n = 0; \
do { \
if((p) >= (p_limit)) break; \
n = (n << 7) | (*(p) & 0x7f); \
} while((*((p)++)&0x80) && (n<(1<<25)));
#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
if(n>=16384) *(p++) = (n >> 14) | 0x80; \
if(n>=128) *(p++) = (n >> 7) | 0x80; \
*(p++) = n & 0x7f;
#endif

View file

@ -1,261 +0,0 @@
/* $Id: connecthostport.c,v 1.13 2014/03/31 12:36:36 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2010-2014 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
/* use getaddrinfo() or gethostbyname()
* uncomment the following line in order to use gethostbyname() */
#ifdef NO_GETADDRINFO
#define USE_GETHOSTBYNAME
#endif
#include <string.h>
#include <stdio.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
#define MAXHOSTNAMELEN 64
#define snprintf _snprintf
#define herror
#define socklen_t int
#else /* #ifdef _WIN32 */
#include <unistd.h>
#include <sys/param.h>
#include <sys/select.h>
#include <errno.h>
#define closesocket close
#include <netdb.h>
#include <netinet/in.h>
/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
* during the connect() call */
#define MINIUPNPC_IGNORE_EINTR
#ifndef USE_GETHOSTBYNAME
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#endif /* #ifndef USE_GETHOSTBYNAME */
#endif /* #else _WIN32 */
/* definition of PRINT_SOCKET_ERROR */
#ifdef _WIN32
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
#else
#define PRINT_SOCKET_ERROR(x) perror(x)
#endif
#if defined(__amigaos__) || defined(__amigaos4__)
#define herror(A) printf("%s\n", A)
#endif
#include "connecthostport.h"
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
/* connecthostport()
* return a socket connected (TCP) to the host and port
* or -1 in case of error */
int connecthostport(const char * host, unsigned short port,
unsigned int scope_id)
{
int s, n;
#ifdef USE_GETHOSTBYNAME
struct sockaddr_in dest;
struct hostent *hp;
#else /* #ifdef USE_GETHOSTBYNAME */
char tmp_host[MAXHOSTNAMELEN+1];
char port_str[8];
struct addrinfo *ai, *p;
struct addrinfo hints;
#endif /* #ifdef USE_GETHOSTBYNAME */
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
struct timeval timeout;
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
#ifdef USE_GETHOSTBYNAME
hp = gethostbyname(host);
if(hp == NULL)
{
herror(host);
return -1;
}
memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr));
memset(dest.sin_zero, 0, sizeof(dest.sin_zero));
s = socket(PF_INET, SOCK_STREAM, 0);
if(s < 0)
{
PRINT_SOCKET_ERROR("socket");
return -1;
}
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
/* setting a 3 seconds timeout for the connect() call */
timeout.tv_sec = 3;
timeout.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
timeout.tv_sec = 3;
timeout.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
dest.sin_family = AF_INET;
dest.sin_port = htons(port);
n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
#ifdef MINIUPNPC_IGNORE_EINTR
/* EINTR The system call was interrupted by a signal that was caught
* EINPROGRESS The socket is nonblocking and the connection cannot
* be completed immediately. */
while(n < 0 && (errno == EINTR || errno = EINPROGRESS))
{
socklen_t len;
fd_set wset;
int err;
FD_ZERO(&wset);
FD_SET(s, &wset);
if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
continue;
/*len = 0;*/
/*n = getpeername(s, NULL, &len);*/
len = sizeof(err);
if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
PRINT_SOCKET_ERROR("getsockopt");
closesocket(s);
return -1;
}
if(err != 0) {
errno = err;
n = -1;
}
}
#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
if(n<0)
{
PRINT_SOCKET_ERROR("connect");
closesocket(s);
return -1;
}
#else /* #ifdef USE_GETHOSTBYNAME */
/* use getaddrinfo() instead of gethostbyname() */
memset(&hints, 0, sizeof(hints));
/* hints.ai_flags = AI_ADDRCONFIG; */
#ifdef AI_NUMERICSERV
hints.ai_flags = AI_NUMERICSERV;
#endif
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */
/* hints.ai_protocol = IPPROTO_TCP; */
snprintf(port_str, sizeof(port_str), "%hu", port);
if(host[0] == '[')
{
/* literal ip v6 address */
int i, j;
for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++)
{
tmp_host[i] = host[j];
if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */
j+=2; /* skip "25" */
}
tmp_host[i] = '\0';
}
else
{
strncpy(tmp_host, host, MAXHOSTNAMELEN);
}
tmp_host[MAXHOSTNAMELEN] = '\0';
n = getaddrinfo(tmp_host, port_str, &hints, &ai);
if(n != 0)
{
#ifdef _WIN32
fprintf(stderr, "getaddrinfo() error : %d\n", n);
#else
fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n));
#endif
return -1;
}
s = -1;
for(p = ai; p; p = p->ai_next)
{
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if(s < 0)
continue;
if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) {
struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr;
addr6->sin6_scope_id = scope_id;
}
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
/* setting a 3 seconds timeout for the connect() call */
timeout.tv_sec = 3;
timeout.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
timeout.tv_sec = 3;
timeout.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
n = connect(s, p->ai_addr, p->ai_addrlen);
#ifdef MINIUPNPC_IGNORE_EINTR
/* EINTR The system call was interrupted by a signal that was caught
* EINPROGRESS The socket is nonblocking and the connection cannot
* be completed immediately. */
while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
{
socklen_t len;
fd_set wset;
int err;
FD_ZERO(&wset);
FD_SET(s, &wset);
if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
continue;
/*len = 0;*/
/*n = getpeername(s, NULL, &len);*/
len = sizeof(err);
if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
PRINT_SOCKET_ERROR("getsockopt");
closesocket(s);
freeaddrinfo(ai);
return -1;
}
if(err != 0) {
errno = err;
n = -1;
}
}
#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */
if(n < 0)
{
closesocket(s);
continue;
}
else
{
break;
}
}
freeaddrinfo(ai);
if(s < 0)
{
PRINT_SOCKET_ERROR("socket");
return -1;
}
if(n < 0)
{
PRINT_SOCKET_ERROR("connect");
return -1;
}
#endif /* #ifdef USE_GETHOSTBYNAME */
return s;
}

View file

@ -1,18 +0,0 @@
/* $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

View file

@ -1,21 +0,0 @@
#ifndef DECLSPEC_H_INCLUDED
#define DECLSPEC_H_INCLUDED
#if defined(_WIN32) && !defined(STATICLIB)
/* for windows dll */
#ifdef MINIUPNP_EXPORTS
#define LIBSPEC __declspec(dllexport)
#else
#define LIBSPEC __declspec(dllimport)
#endif
#else
#if defined(__GNUC__) && __GNUC__ >= 4
/* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */
#define LIBSPEC __attribute__ ((visibility ("default")))
#else
#define LIBSPEC
#endif
#endif
#endif

View file

@ -1,4 +0,0 @@
#!/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'

View file

@ -1,125 +0,0 @@
/* $Id: igd_desc_parse.c,v 1.14 2011/04/11 09:19:24 nanard Exp $ */
/* Project : miniupnp
* http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2005-2010 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
#include "igd_desc_parse.h"
#include <stdio.h>
#include <string.h>
/* Start element handler :
* update nesting level counter and copy element name */
void IGDstartelt(void * d, const char * name, int l)
{
struct IGDdatas * datas = (struct IGDdatas *)d;
memcpy( datas->cureltname, name, l);
datas->cureltname[l] = '\0';
datas->level++;
if( (l==7) && !memcmp(name, "service", l) ) {
datas->tmp.controlurl[0] = '\0';
datas->tmp.eventsuburl[0] = '\0';
datas->tmp.scpdurl[0] = '\0';
datas->tmp.servicetype[0] = '\0';
}
}
/* End element handler :
* update nesting level counter and update parser state if
* service element is parsed */
void IGDendelt(void * d, const char * name, int l)
{
struct IGDdatas * datas = (struct IGDdatas *)d;
datas->level--;
/*printf("endelt %2d %.*s\n", datas->level, l, name);*/
if( (l==7) && !memcmp(name, "service", l) )
{
/*
if( datas->state < 1
&& !strcmp(datas->servicetype,
// "urn:schemas-upnp-org:service:WANIPConnection:1") )
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"))
datas->state ++;
*/
if(0==strcmp(datas->tmp.servicetype,
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) {
memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service));
} else if(0==strcmp(datas->tmp.servicetype,
"urn:schemas-upnp-org:service:WANIPv6FirewallControl:1")) {
memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service));
} else if(0==strcmp(datas->tmp.servicetype,
"urn:schemas-upnp-org:service:WANIPConnection:1")
|| 0==strcmp(datas->tmp.servicetype,
"urn:schemas-upnp-org:service:WANPPPConnection:1") ) {
if(datas->first.servicetype[0] == '\0') {
memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service));
} else {
memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service));
}
}
}
}
/* Data handler :
* copy data depending on the current element name and state */
void IGDdata(void * d, const char * data, int l)
{
struct IGDdatas * datas = (struct IGDdatas *)d;
char * dstmember = 0;
/*printf("%2d %s : %.*s\n",
datas->level, datas->cureltname, l, data); */
if( !strcmp(datas->cureltname, "URLBase") )
dstmember = datas->urlbase;
else if( !strcmp(datas->cureltname, "presentationURL") )
dstmember = datas->presentationurl;
else if( !strcmp(datas->cureltname, "serviceType") )
dstmember = datas->tmp.servicetype;
else if( !strcmp(datas->cureltname, "controlURL") )
dstmember = datas->tmp.controlurl;
else if( !strcmp(datas->cureltname, "eventSubURL") )
dstmember = datas->tmp.eventsuburl;
else if( !strcmp(datas->cureltname, "SCPDURL") )
dstmember = datas->tmp.scpdurl;
/* else if( !strcmp(datas->cureltname, "deviceType") )
dstmember = datas->devicetype_tmp;*/
if(dstmember)
{
if(l>=MINIUPNPC_URL_MAXSIZE)
l = MINIUPNPC_URL_MAXSIZE-1;
memcpy(dstmember, data, l);
dstmember[l] = '\0';
}
}
void printIGD(struct IGDdatas * d)
{
printf("urlbase = '%s'\n", d->urlbase);
printf("WAN Device (Common interface config) :\n");
/*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/
printf(" serviceType = '%s'\n", d->CIF.servicetype);
printf(" controlURL = '%s'\n", d->CIF.controlurl);
printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl);
printf(" SCPDURL = '%s'\n", d->CIF.scpdurl);
printf("primary WAN Connection Device (IP or PPP Connection):\n");
/*printf(" deviceType = '%s'\n", d->first.devicetype);*/
printf(" servicetype = '%s'\n", d->first.servicetype);
printf(" controlURL = '%s'\n", d->first.controlurl);
printf(" eventSubURL = '%s'\n", d->first.eventsuburl);
printf(" SCPDURL = '%s'\n", d->first.scpdurl);
printf("secondary WAN Connection Device (IP or PPP Connection):\n");
/*printf(" deviceType = '%s'\n", d->second.devicetype);*/
printf(" servicetype = '%s'\n", d->second.servicetype);
printf(" controlURL = '%s'\n", d->second.controlurl);
printf(" eventSubURL = '%s'\n", d->second.eventsuburl);
printf(" SCPDURL = '%s'\n", d->second.scpdurl);
printf("WAN IPv6 Firewall Control :\n");
/*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/
printf(" servicetype = '%s'\n", d->IPv6FC.servicetype);
printf(" controlURL = '%s'\n", d->IPv6FC.controlurl);
printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl);
printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl);
}

View file

@ -1,48 +0,0 @@
/* $Id: igd_desc_parse.h,v 1.11 2012/10/16 16:49:02 nanard Exp $ */
/* Project : miniupnp
* http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2005-2010 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
#ifndef IGD_DESC_PARSE_H_INCLUDED
#define IGD_DESC_PARSE_H_INCLUDED
/* Structure to store the result of the parsing of UPnP
* descriptions of Internet Gateway Devices */
#define MINIUPNPC_URL_MAXSIZE (128)
struct IGDdatas_service {
char controlurl[MINIUPNPC_URL_MAXSIZE];
char eventsuburl[MINIUPNPC_URL_MAXSIZE];
char scpdurl[MINIUPNPC_URL_MAXSIZE];
char servicetype[MINIUPNPC_URL_MAXSIZE];
/*char devicetype[MINIUPNPC_URL_MAXSIZE];*/
};
struct IGDdatas {
char cureltname[MINIUPNPC_URL_MAXSIZE];
char urlbase[MINIUPNPC_URL_MAXSIZE];
char presentationurl[MINIUPNPC_URL_MAXSIZE];
int level;
/*int state;*/
/* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */
struct IGDdatas_service CIF;
/* "urn:schemas-upnp-org:service:WANIPConnection:1"
* "urn:schemas-upnp-org:service:WANPPPConnection:1" */
struct IGDdatas_service first;
/* if both WANIPConnection and WANPPPConnection are present */
struct IGDdatas_service second;
/* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */
struct IGDdatas_service IPv6FC;
/* tmp */
struct IGDdatas_service tmp;
};
void IGDstartelt(void *, const char *, int);
void IGDendelt(void *, const char *, int);
void IGDdata(void *, const char *, int);
void printIGD(struct IGDdatas *);
#endif

View file

@ -1,97 +0,0 @@
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import fr.free.miniupnp.*;
/**
*
* @author syuu
*/
public class JavaBridgeTest {
public static void main(String[] args) {
int UPNP_DELAY = 2000;
MiniupnpcLibrary miniupnpc = MiniupnpcLibrary.INSTANCE;
UPNPDev devlist = null;
UPNPUrls urls = new UPNPUrls();
IGDdatas data = new IGDdatas();
ByteBuffer lanaddr = ByteBuffer.allocate(16);
ByteBuffer intClient = ByteBuffer.allocate(16);
ByteBuffer intPort = ByteBuffer.allocate(6);
ByteBuffer desc = ByteBuffer.allocate(80);
ByteBuffer enabled = ByteBuffer.allocate(4);
ByteBuffer leaseDuration = ByteBuffer.allocate(16);
int ret;
int i;
if(args.length < 2) {
System.err.println("Usage : java [...] JavaBridgeTest port protocol");
System.out.println(" port is numeric, protocol is TCP or UDP");
return;
}
devlist = miniupnpc.upnpDiscover(UPNP_DELAY, (String) null, (String) null, 0, 0, IntBuffer.allocate(1));
if (devlist != null) {
System.out.println("List of UPNP devices found on the network :");
for (UPNPDev device = devlist; device != null; device = device.pNext) {
System.out.println("desc: " + device.descURL.getString(0) + " st: " + device.st.getString(0));
}
if ((i = miniupnpc.UPNP_GetValidIGD(devlist, urls, data, lanaddr, 16)) != 0) {
switch (i) {
case 1:
System.out.println("Found valid IGD : " + urls.controlURL.getString(0));
break;
case 2:
System.out.println("Found a (not connected?) IGD : " + urls.controlURL.getString(0));
System.out.println("Trying to continue anyway");
break;
case 3:
System.out.println("UPnP device found. Is it an IGD ? : " + urls.controlURL.getString(0));
System.out.println("Trying to continue anyway");
break;
default:
System.out.println("Found device (igd ?) : " + urls.controlURL.getString(0));
System.out.println("Trying to continue anyway");
}
System.out.println("Local LAN ip address : " + new String(lanaddr.array()));
ByteBuffer externalAddress = ByteBuffer.allocate(16);
miniupnpc.UPNP_GetExternalIPAddress(urls.controlURL.getString(0),
new String(data.first.servicetype), externalAddress);
System.out.println("ExternalIPAddress = " + new String(externalAddress.array()));
ret = miniupnpc.UPNP_AddPortMapping(
urls.controlURL.getString(0), // controlURL
new String(data.first.servicetype), // servicetype
args[0], // external Port
args[0], // internal Port
new String(lanaddr.array()), // internal client
"added via miniupnpc/JAVA !", // description
args[1], // protocol UDP or TCP
null, // remote host (useless)
"0"); // leaseDuration
if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS)
System.out.println("AddPortMapping() failed with code " + ret);
ret = miniupnpc.UPNP_GetSpecificPortMappingEntry(
urls.controlURL.getString(0), new String(data.first.servicetype),
args[0], args[1], null, intClient, intPort,
desc, enabled, leaseDuration);
if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS)
System.out.println("GetSpecificPortMappingEntry() failed with code " + ret);
System.out.println("InternalIP:Port = " +
new String(intClient.array()) + ":" + new String(intPort.array()) +
" (" + new String(desc.array()) + ")");
ret = miniupnpc.UPNP_DeletePortMapping(
urls.controlURL.getString(0),
new String(data.first.servicetype),
args[0], args[1], null);
if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS)
System.out.println("DelPortMapping() failed with code " + ret);
miniupnpc.FreeUPNPUrls(urls);
} else {
System.out.println("No valid UPNP Internet Gateway Device found.");
}
miniupnpc.freeUPNPDevlist(devlist);
} else {
System.out.println("No IGD UPnP Device found on the network !\n");
}
}
}

View file

@ -1,8 +0,0 @@
@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

View file

@ -1,8 +0,0 @@
#!/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

View file

@ -1,52 +0,0 @@
.TH MINIUPNPC 3
.SH NAME
miniupnpc \- UPnP client library
.SH SYNOPSIS
.SH DESCRIPTION
The miniupnpc library implement the UPnP protocol defined
to dialog with Internet Gateway Devices. It also has
the ability to use data gathered by minissdpd(1) about
UPnP devices up on the network in order to skip the
long UPnP device discovery process.
.PP
At first, upnpDiscover(3) has to be used to discover UPnP IGD present
on the network. Then UPNP_GetValidIGD(3) to select the right one.
Alternatively, UPNP_GetIGDFromUrl(3) could be used to bypass discovery
process if the root description url of the device to use is known.
Then all the UPNP_* functions can be used, such as
UPNP_GetConnectionTypeInfo(3), UPNP_AddPortMapping(3), etc...
.SH "HEADER FILES"
.IP miniupnpc.h
That's the main header file for the miniupnpc library API.
It contains all the functions and structures related to device discovery.
.IP upnpcommands.h
This header file contain the UPnP IGD methods that are accessible
through the miniupnpc API. The name of the C functions are matching
the UPnP methods names. ie: GetGenericPortMappingEntry is
UPNP_GetGenericPortMappingEntry.
.SH "API FUNCTIONS"
.IP "struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error);"
execute the discovery process.
delay (in millisecond) is the maximum time for waiting any device response.
If available, device list will be obtained from MiniSSDPd.
Default path for minissdpd socket will be used if minissdpdsock argument is NULL.
If multicastif is not NULL, it will be used instead of the default multicast interface for sending SSDP discover packets.
If sameport is not null, SSDP packets will be sent from the source port 1900 (same as destination port) otherwise system assign a source port.
If ipv6 is not 0, IPv6 is used instead of IPv4 for the discovery process.
.IP "void freeUPNPDevlist(struct UPNPDev * devlist);"
free the list returned by upnpDiscover().
.IP "int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen);"
browse the list of device returned by upnpDiscover(), find
a live UPnP internet gateway device and fill structures passed as arguments
with data used for UPNP methods invokation.
.IP "int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen);"
permit to bypass the upnpDiscover() call if the xml root description
URL of the UPnP IGD is known.
Fill structures passed as arguments
with data used for UPNP methods invokation.
.IP "void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *);"
.IP "void FreeUPNPUrls(struct UPNPUrls *);"
.SH "SEE ALSO"
minissdpd(1)
.SH BUGS

View file

@ -1,8 +0,0 @@
@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

View file

@ -1,486 +0,0 @@
/* $Id: minihttptestserver.c,v 1.13 2012/05/29 13:03:07 nanard Exp $ */
/* Project : miniUPnP
* Author : Thomas Bernard
* Copyright (c) 2011-2012 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#define CRAP_LENGTH (2048)
volatile sig_atomic_t quit = 0;
volatile sig_atomic_t child_to_wait_for = 0;
/**
* signal handler for SIGCHLD (child status has changed)
*/
void handle_signal_chld(int sig)
{
printf("handle_signal_chld(%d)\n", sig);
++child_to_wait_for;
}
/**
* signal handler for SIGINT (CRTL C)
*/
#if 0
void handle_signal_int(int sig)
{
printf("handle_signal_int(%d)\n", sig);
quit = 1;
}
#endif
/**
* build a text/plain content of the specified length
*/
void build_content(char * p, int n)
{
char line_buffer[80];
int k;
int i = 0;
while(n > 0) {
k = snprintf(line_buffer, sizeof(line_buffer),
"%04d_ABCDEFGHIJKL_This_line_is_64_bytes_long_ABCDEFGHIJKL_%04d\r\n",
i, i);
if(k != 64) {
fprintf(stderr, "snprintf() returned %d in build_content()\n", k);
}
++i;
if(n >= 64) {
memcpy(p, line_buffer, 64);
p += 64;
n -= 64;
} else {
memcpy(p, line_buffer, n);
p += n;
n = 0;
}
}
}
/**
* build crappy content
*/
void build_crap(char * p, int n)
{
static const char crap[] = "_CRAP_\r\n";
int i;
while(n > 0) {
i = sizeof(crap) - 1;
if(i > n)
i = n;
memcpy(p, crap, i);
p += i;
n -= i;
}
}
/**
* build chunked response.
* return a malloc'ed buffer
*/
char * build_chunked_response(int content_length, int * response_len) {
char * response_buffer;
char * content_buffer;
int buffer_length;
int i, n;
/* allocate to have some margin */
buffer_length = 256 + content_length + (content_length >> 4);
response_buffer = malloc(buffer_length);
*response_len = snprintf(response_buffer, buffer_length,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n");
/* build the content */
content_buffer = malloc(content_length);
build_content(content_buffer, content_length);
/* chunk it */
i = 0;
while(i < content_length) {
n = (rand() % 199) + 1;
if(i + n > content_length) {
n = content_length - i;
}
/* TODO : check buffer size ! */
*response_len += snprintf(response_buffer + *response_len,
buffer_length - *response_len,
"%x\r\n", n);
memcpy(response_buffer + *response_len, content_buffer + i, n);
*response_len += n;
i += n;
response_buffer[(*response_len)++] = '\r';
response_buffer[(*response_len)++] = '\n';
}
/* the last chunk : "0\r\n" a empty body and then
* the final "\r\n" */
memcpy(response_buffer + *response_len, "0\r\n\r\n", 5);
*response_len += 5;
free(content_buffer);
printf("resp_length=%d buffer_length=%d content_length=%d\n",
*response_len, buffer_length, content_length);
return response_buffer;
}
enum modes { MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL };
const struct {
const enum modes mode;
const char * text;
} modes_array[] = {
{MODE_CHUNKED, "chunked"},
{MODE_ADDCRAP, "addcrap"},
{MODE_NORMAL, "normal"},
{MODE_INVALID, NULL}
};
/**
* write the response with random behaviour !
*/
void send_response(int c, const char * buffer, int len)
{
int n;
while(len > 0) {
n = (rand() % 99) + 1;
if(n > len)
n = len;
n = write(c, buffer, n);
if(n < 0) {
if(errno != EINTR) {
perror("write");
return;
}
/* if errno == EINTR, try again */
} else {
len -= n;
buffer += n;
}
usleep(10000); /* 10ms */
}
}
/**
* handle the HTTP connection
*/
void handle_http_connection(int c)
{
char request_buffer[2048];
int request_len = 0;
int headers_found = 0;
int n, i;
char request_method[16];
char request_uri[256];
char http_version[16];
char * p;
char * response_buffer;
int response_len;
enum modes mode;
int content_length = 16*1024;
/* read the request */
while(request_len < (int)sizeof(request_buffer) && !headers_found) {
n = read(c,
request_buffer + request_len,
sizeof(request_buffer) - request_len);
if(n < 0) {
perror("read");
return;
} else if(n==0) {
/* remote host closed the connection */
break;
} else {
request_len += n;
for(i = 0; i < request_len - 3; i++) {
if(0 == memcmp(request_buffer + i, "\r\n\r\n", 4)) {
/* found the end of headers */
headers_found = 1;
break;
}
}
}
}
if(!headers_found) {
/* error */
return;
}
printf("headers :\n%.*s", request_len, request_buffer);
/* the request have been received, now parse the request line */
p = request_buffer;
for(i = 0; i < (int)sizeof(request_method) - 1; i++) {
if(*p == ' ' || *p == '\r')
break;
request_method[i] = *p;
++p;
}
request_method[i] = '\0';
while(*p == ' ')
p++;
for(i = 0; i < (int)sizeof(request_uri) - 1; i++) {
if(*p == ' ' || *p == '\r')
break;
request_uri[i] = *p;
++p;
}
request_uri[i] = '\0';
while(*p == ' ')
p++;
for(i = 0; i < (int)sizeof(http_version) - 1; i++) {
if(*p == ' ' || *p == '\r')
break;
http_version[i] = *p;
++p;
}
http_version[i] = '\0';
printf("Method = %s, URI = %s, %s\n",
request_method, request_uri, http_version);
/* check if the request method is allowed */
if(0 != strcmp(request_method, "GET")) {
const char response405[] = "HTTP/1.1 405 Method Not Allowed\r\n"
"Allow: GET\r\n\r\n";
const char * pc;
/* 405 Method Not Allowed */
/* The response MUST include an Allow header containing a list
* of valid methods for the requested resource. */
n = sizeof(response405) - 1;
pc = response405;
while(n > 0) {
i = write(c, pc, n);
if(i<0) {
if(errno != EINTR) {
perror("write");
return;
}
} else {
n -= i;
pc += i;
}
}
return;
}
mode = MODE_INVALID;
/* use the request URI to know what to do */
for(i = 0; modes_array[i].mode != MODE_INVALID; i++) {
if(strstr(request_uri, modes_array[i].text)) {
mode = modes_array[i].mode; /* found */
break;
}
}
switch(mode) {
case MODE_CHUNKED:
response_buffer = build_chunked_response(content_length, &response_len);
break;
case MODE_ADDCRAP:
response_len = content_length+256;
response_buffer = malloc(response_len);
n = snprintf(response_buffer, response_len,
"HTTP/1.1 200 OK\r\n"
"Server: minihttptestserver\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %d\r\n"
"\r\n", content_length);
response_len = content_length+n+CRAP_LENGTH;
response_buffer = realloc(response_buffer, response_len);
build_content(response_buffer + n, content_length);
build_crap(response_buffer + n + content_length, CRAP_LENGTH);
break;
default:
response_len = content_length+256;
response_buffer = malloc(response_len);
n = snprintf(response_buffer, response_len,
"HTTP/1.1 200 OK\r\n"
"Server: minihttptestserver\r\n"
"Content-Type: text/plain\r\n"
"\r\n");
response_len = content_length+n;
response_buffer = realloc(response_buffer, response_len);
build_content(response_buffer + n, response_len - n);
}
if(response_buffer) {
send_response(c, response_buffer, response_len);
free(response_buffer);
} else {
/* Error 500 */
}
}
/**
*/
int main(int argc, char * * argv) {
int ipv6 = 0;
int s, c, i;
unsigned short port = 0;
struct sockaddr_storage server_addr;
socklen_t server_addrlen;
struct sockaddr_storage client_addr;
socklen_t client_addrlen;
pid_t pid;
int child = 0;
int status;
const char * expected_file_name = NULL;
for(i = 1; i < argc; i++) {
if(argv[i][0] == '-') {
switch(argv[i][1]) {
case '6':
ipv6 = 1;
break;
case 'e':
/* write expected file ! */
expected_file_name = argv[++i];
break;
case 'p':
/* port */
if(++i < argc) {
port = (unsigned short)atoi(argv[i]);
}
break;
default:
fprintf(stderr, "unknown command line switch '%s'\n", argv[i]);
}
} else {
fprintf(stderr, "unkown command line argument '%s'\n", argv[i]);
}
}
srand(time(NULL));
signal(SIGCHLD, handle_signal_chld);
#if 0
signal(SIGINT, handle_signal_int);
#endif
s = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
if(s < 0) {
perror("socket");
return 1;
}
memset(&server_addr, 0, sizeof(struct sockaddr_storage));
memset(&client_addr, 0, sizeof(struct sockaddr_storage));
if(ipv6) {
struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr;
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(port);
addr->sin6_addr = in6addr_loopback;
} else {
struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr;
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}
if(bind(s, (struct sockaddr *)&server_addr,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) < 0) {
perror("bind");
return 1;
}
if(listen(s, 5) < 0) {
perror("listen");
}
if(port == 0) {
server_addrlen = sizeof(struct sockaddr_storage);
if(getsockname(s, (struct sockaddr *)&server_addr, &server_addrlen) < 0) {
perror("getsockname");
return 1;
}
if(ipv6) {
struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr;
port = ntohs(addr->sin6_port);
} else {
struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr;
port = ntohs(addr->sin_port);
}
printf("Listening on port %hu\n", port);
fflush(stdout);
}
/* write expected file */
if(expected_file_name) {
FILE * f;
f = fopen(expected_file_name, "wb");
if(f) {
char * buffer;
buffer = malloc(16*1024);
build_content(buffer, 16*1024);
i = fwrite(buffer, 1, 16*1024, f);
if(i != 16*1024) {
fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024);
}
free(buffer);
fclose(f);
} else {
fprintf(stderr, "error opening file %s for writing\n", expected_file_name);
}
}
/* fork() loop */
while(!child && !quit) {
while(child_to_wait_for > 0) {
pid = wait(&status);
if(pid < 0) {
perror("wait");
} else {
printf("child(%d) terminated with status %d\n", pid, status);
}
--child_to_wait_for;
}
/* TODO : add a select() call in order to handle the case
* when a signal is caught */
client_addrlen = sizeof(struct sockaddr_storage);
c = accept(s, (struct sockaddr *)&client_addr,
&client_addrlen);
if(c < 0) {
perror("accept");
return 1;
}
printf("accept...\n");
pid = fork();
if(pid < 0) {
perror("fork");
return 1;
} else if(pid == 0) {
/* child */
child = 1;
close(s);
s = -1;
handle_http_connection(c);
}
close(c);
}
if(s >= 0) {
close(s);
s = -1;
}
if(!child) {
while(child_to_wait_for > 0) {
pid = wait(&status);
if(pid < 0) {
perror("wait");
} else {
printf("child(%d) terminated with status %d\n", pid, status);
}
--child_to_wait_for;
}
printf("Bye...\n");
}
return 0;
}

View file

@ -1,121 +0,0 @@
/* $Id: minisoap.c,v 1.22 2012/01/21 13:30:31 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
*
* Minimal SOAP implementation for UPnP protocol.
*/
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#include <winsock2.h>
#define snprintf _snprintf
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#endif
#include "minisoap.h"
#include "miniupnpcstrings.h"
/* only for malloc */
#include <stdlib.h>
#ifdef _WIN32
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
#else
#define PRINT_SOCKET_ERROR(x) perror(x)
#endif
/* httpWrite sends the headers and the body to the socket
* and returns the number of bytes sent */
static int
httpWrite(int fd, const char * body, int bodysize,
const char * headers, int headerssize)
{
int n = 0;
/*n = write(fd, headers, headerssize);*/
/*if(bodysize>0)
n += write(fd, body, bodysize);*/
/* Note : my old linksys router only took into account
* soap request that are sent into only one packet */
char * p;
/* TODO: AVOID MALLOC */
p = malloc(headerssize+bodysize);
if(!p)
return 0;
memcpy(p, headers, headerssize);
memcpy(p+headerssize, body, bodysize);
/*n = write(fd, p, headerssize+bodysize);*/
n = send(fd, p, headerssize+bodysize, 0);
if(n<0) {
PRINT_SOCKET_ERROR("send");
}
/* disable send on the socket */
/* draytek routers dont seems to like that... */
#if 0
#ifdef _WIN32
if(shutdown(fd, SD_SEND)<0) {
#else
if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/
#endif
PRINT_SOCKET_ERROR("shutdown");
}
#endif
free(p);
return n;
}
/* self explanatory */
int soapPostSubmit(int fd,
const char * url,
const char * host,
unsigned short port,
const char * action,
const char * body,
const char * httpversion)
{
int bodysize;
char headerbuf[512];
int headerssize;
char portstr[8];
bodysize = (int)strlen(body);
/* We are not using keep-alive HTTP connections.
* HTTP/1.1 needs the header Connection: close to do that.
* This is the default with HTTP/1.0
* Using HTTP/1.1 means we need to support chunked transfer-encoding :
* When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked
* transfer encoding. */
/* Connection: Close is normally there only in HTTP/1.1 but who knows */
portstr[0] = '\0';
if(port != 80)
snprintf(portstr, sizeof(portstr), ":%hu", port);
headerssize = snprintf(headerbuf, sizeof(headerbuf),
"POST %s HTTP/%s\r\n"
"Host: %s%s\r\n"
"User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
"Content-Length: %d\r\n"
"Content-Type: text/xml\r\n"
"SOAPAction: \"%s\"\r\n"
"Connection: Close\r\n"
"Cache-Control: no-cache\r\n" /* ??? */
"Pragma: no-cache\r\n"
"\r\n",
url, httpversion, host, portstr, bodysize, action);
#ifdef DEBUG
/*printf("SOAP request : headersize=%d bodysize=%d\n",
headerssize, bodysize);
*/
printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n",
url, httpversion, host, portstr);
printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize);
printf("Headers :\n%s", headerbuf);
printf("Body :\n%s\n", body);
#endif
return httpWrite(fd, body, bodysize, headerbuf, headerssize);
}

View file

@ -1,15 +0,0 @@
/* $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

View file

@ -1,133 +0,0 @@
/* $Id: minissdpc.c,v 1.16 2012/03/05 19:42:46 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2012 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
/*#include <syslog.h>*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
#include <winsock.h>
#include <stdint.h>
#endif
#if defined(__amigaos__) || defined(__amigaos4__)
#include <sys/socket.h>
#endif
#if defined(__amigaos__)
#define uint16_t unsigned short
#endif
/* Hack */
#define UNIX_PATH_LEN 108
struct sockaddr_un {
uint16_t sun_family;
char sun_path[UNIX_PATH_LEN];
};
#else
#include <sys/socket.h>
#include <sys/un.h>
#endif
#include "minissdpc.h"
#include "miniupnpc.h"
#include "codelength.h"
struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
{
struct UPNPDev * tmp;
struct UPNPDev * devlist = NULL;
unsigned char buffer[2048];
ssize_t n;
unsigned char * p;
unsigned char * url;
unsigned int i;
unsigned int urlsize, stsize, usnsize, l;
int s;
struct sockaddr_un addr;
s = socket(AF_UNIX, SOCK_STREAM, 0);
if(s < 0)
{
/*syslog(LOG_ERR, "socket(unix): %m");*/
perror("socket(unix)");
return NULL;
}
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path));
/* TODO : check if we need to handle the EINTR */
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0)
{
/*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/
close(s);
return NULL;
}
stsize = strlen(devtype);
buffer[0] = 1; /* request type 1 : request devices/services by type */
p = buffer + 1;
l = stsize; CODELENGTH(l, p);
if(p + stsize > buffer + sizeof(buffer))
{
/* devtype is too long ! */
close(s);
return NULL;
}
memcpy(p, devtype, stsize);
p += stsize;
if(write(s, buffer, p - buffer) < 0)
{
/*syslog(LOG_ERR, "write(): %m");*/
perror("minissdpc.c: write()");
close(s);
return NULL;
}
n = read(s, buffer, sizeof(buffer));
if(n<=0)
{
perror("minissdpc.c: read()");
close(s);
return NULL;
}
p = buffer + 1;
for(i = 0; i < buffer[0]; i++)
{
if(p+2>=buffer+sizeof(buffer))
break;
DECODELENGTH(urlsize, p);
if(p+urlsize+2>=buffer+sizeof(buffer))
break;
url = p;
p += urlsize;
DECODELENGTH(stsize, p);
if(p+stsize+2>=buffer+sizeof(buffer))
break;
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
tmp->pNext = devlist;
tmp->descURL = tmp->buffer;
tmp->st = tmp->buffer + 1 + urlsize;
memcpy(tmp->buffer, url, urlsize);
tmp->buffer[urlsize] = '\0';
memcpy(tmp->buffer + urlsize + 1, p, stsize);
p += stsize;
tmp->buffer[urlsize+1+stsize] = '\0';
devlist = tmp;
/* added for compatibility with recent versions of MiniSSDPd
* >= 2007/12/19 */
DECODELENGTH(usnsize, p);
p += usnsize;
if(p>buffer + sizeof(buffer))
break;
}
close(s);
return devlist;
}

View file

@ -1,15 +0,0 @@
/* $Id: minissdpc.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author: Thomas Bernard
* Copyright (c) 2005-2007 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINISSDPC_H_INCLUDED
#define MINISSDPC_H_INCLUDED
struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,43 +0,0 @@
LIBRARY
; miniupnpc library
miniupnpc
EXPORTS
; miniupnpc
upnpDiscover
freeUPNPDevlist
parserootdesc
UPNP_GetValidIGD
UPNP_GetIGDFromUrl
GetUPNPUrls
FreeUPNPUrls
; miniwget
miniwget
miniwget_getaddr
; upnpcommands
UPNP_GetTotalBytesSent
UPNP_GetTotalBytesReceived
UPNP_GetTotalPacketsSent
UPNP_GetTotalPacketsReceived
UPNP_GetStatusInfo
UPNP_GetConnectionTypeInfo
UPNP_GetExternalIPAddress
UPNP_GetLinkLayerMaxBitRates
UPNP_AddPortMapping
UPNP_DeletePortMapping
UPNP_GetPortMappingNumberOfEntries
UPNP_GetSpecificPortMappingEntry
UPNP_GetGenericPortMappingEntry
UPNP_GetListOfPortMappings
UPNP_AddPinhole
UPNP_CheckPinholeWorking
UPNP_UpdatePinhole
UPNP_GetPinholePackets
UPNP_DeletePinhole
UPNP_GetFirewallStatus
UPNP_GetOutboundPinholeTimeout
; upnperrors
strupnperror
; portlistingparse
ParsePortListing
FreePortListing

View file

@ -1,130 +0,0 @@
/* $Id: miniupnpc.h,v 1.35 2014/01/31 13:26:34 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/
* Author: Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINIUPNPC_H_INCLUDED
#define MINIUPNPC_H_INCLUDED
#include "declspec.h"
#include "igd_desc_parse.h"
/* error codes : */
#define UPNPDISCOVER_SUCCESS (0)
#define UPNPDISCOVER_UNKNOWN_ERROR (-1)
#define UPNPDISCOVER_SOCKET_ERROR (-101)
#define UPNPDISCOVER_MEMORY_ERROR (-102)
/* versions : */
#define MINIUPNPC_VERSION "1.9.20140401"
#define MINIUPNPC_API_VERSION 10
#ifdef __cplusplus
extern "C" {
#endif
/* Structures definitions : */
struct UPNParg { const char * elt; const char * val; };
char *
simpleUPnPcommand(int, const char *, const char *,
const char *, struct UPNParg *,
int *);
struct UPNPDev {
struct UPNPDev * pNext;
char * descURL;
char * st;
unsigned int scope_id;
char buffer[2];
};
/* upnpDiscover()
* discover UPnP devices on the network.
* The discovered devices are returned as a chained list.
* It is up to the caller to free the list with freeUPNPDevlist().
* delay (in millisecond) is the maximum time for waiting any device
* response.
* If available, device list will be obtained from MiniSSDPd.
* Default path for minissdpd socket will be used if minissdpdsock argument
* is NULL.
* If multicastif is not NULL, it will be used instead of the default
* multicast interface for sending SSDP discover packets.
* If sameport is not null, SSDP packets will be sent from the source port
* 1900 (same as destination port) otherwise system assign a source port. */
LIBSPEC struct UPNPDev *
upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int sameport,
int ipv6,
int * error);
/* freeUPNPDevlist()
* free list returned by upnpDiscover() */
LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
/* parserootdesc() :
* parse root XML description of a UPnP device and fill the IGDdatas
* structure. */
LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *);
/* structure used to get fast access to urls
* controlURL: controlURL of the WANIPConnection
* ipcondescURL: url of the description of the WANIPConnection
* controlURL_CIF: controlURL of the WANCommonInterfaceConfig
* controlURL_6FC: controlURL of the WANIPv6FirewallControl
*/
struct UPNPUrls {
char * controlURL;
char * ipcondescURL;
char * controlURL_CIF;
char * controlURL_6FC;
char * rootdescURL;
};
/* UPNP_GetValidIGD() :
* return values :
* 0 = NO IGD found
* 1 = A valid connected IGD has been found
* 2 = A valid IGD has been found but it reported as
* not connected
* 3 = an UPnP device has been found but was not recognized as an IGD
*
* In any non zero return case, the urls and data structures
* passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to
* free allocated memory.
*/
LIBSPEC int
UPNP_GetValidIGD(struct UPNPDev * devlist,
struct UPNPUrls * urls,
struct IGDdatas * data,
char * lanaddr, int lanaddrlen);
/* UPNP_GetIGDFromUrl()
* Used when skipping the discovery process.
* return value :
* 0 - Not ok
* 1 - OK */
LIBSPEC int
UPNP_GetIGDFromUrl(const char * rootdescurl,
struct UPNPUrls * urls,
struct IGDdatas * data,
char * lanaddr, int lanaddrlen);
LIBSPEC void
GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *,
const char *, unsigned int);
LIBSPEC void
FreeUPNPUrls(struct UPNPUrls *);
/* return 0 or 1 */
LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,545 +0,0 @@
/* $Id: miniupnpcmodule.c,v 1.22 2014/01/31 13:18:25 nanard Exp $*/
/* Project : miniupnp
* Author : Thomas BERNARD
* website : http://miniupnp.tuxfamily.org/
* copyright (c) 2007-2014 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENCE file. */
#include <Python.h>
#define STATICLIB
#include "structmember.h"
#include "miniupnpc.h"
#include "upnpcommands.h"
#include "upnperrors.h"
/* for compatibility with Python < 2.4 */
#ifndef Py_RETURN_NONE
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
#endif
#ifndef Py_RETURN_TRUE
#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
#endif
#ifndef Py_RETURN_FALSE
#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
#endif
/* for compatibility with Python < 3.0 */
#ifndef PyVarObject_HEAD_INIT
#define PyVarObject_HEAD_INIT(type, size) \
PyObject_HEAD_INIT(type) size,
#endif
#ifndef Py_TYPE
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
#endif
typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
struct UPNPDev * devlist;
struct UPNPUrls urls;
struct IGDdatas data;
unsigned int discoverdelay; /* value passed to upnpDiscover() */
char lanaddr[40]; /* our ip address on the LAN */
char * multicastif;
char * minissdpdsocket;
} UPnPObject;
static PyMemberDef UPnP_members[] = {
{"lanaddr", T_STRING_INPLACE, offsetof(UPnPObject, lanaddr),
READONLY, "ip address on the LAN"
},
{"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay),
0/*READWRITE*/, "value in ms used to wait for SSDP responses"
},
/* T_STRING is allways readonly :( */
{"multicastif", T_STRING, offsetof(UPnPObject, multicastif),
0, "IP of the network interface to be used for multicast operations"
},
{"minissdpdsocket", T_STRING, offsetof(UPnPObject, multicastif),
0, "path of the MiniSSDPd unix socket"
},
{NULL}
};
static void
UPnPObject_dealloc(UPnPObject *self)
{
freeUPNPDevlist(self->devlist);
FreeUPNPUrls(&self->urls);
Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject *
UPnP_discover(UPnPObject *self)
{
struct UPNPDev * dev;
int i;
PyObject *res = NULL;
if(self->devlist)
{
freeUPNPDevlist(self->devlist);
self->devlist = 0;
}
Py_BEGIN_ALLOW_THREADS
self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
0/* multicast if*/,
0/*minissdpd socket*/,
0/*sameport flag*/,
0/*ip v6*/,
0/*error */);
Py_END_ALLOW_THREADS
/* Py_RETURN_NONE ??? */
for(dev = self->devlist, i = 0; dev; dev = dev->pNext)
i++;
res = Py_BuildValue("i", i);
return res;
}
static PyObject *
UPnP_selectigd(UPnPObject *self)
{
int r;
Py_BEGIN_ALLOW_THREADS
r = UPNP_GetValidIGD(self->devlist, &self->urls, &self->data,
self->lanaddr, sizeof(self->lanaddr));
Py_END_ALLOW_THREADS
if(r)
{
return Py_BuildValue("s", self->urls.controlURL);
}
else
{
/* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, "No UPnP device discovered");
return NULL;
}
}
static PyObject *
UPnP_totalbytesent(UPnPObject *self)
{
UNSIGNED_INTEGER i;
Py_BEGIN_ALLOW_THREADS
i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
self->data.CIF.servicetype);
Py_END_ALLOW_THREADS
return Py_BuildValue("I", i);
}
static PyObject *
UPnP_totalbytereceived(UPnPObject *self)
{
UNSIGNED_INTEGER i;
Py_BEGIN_ALLOW_THREADS
i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
self->data.CIF.servicetype);
Py_END_ALLOW_THREADS
return Py_BuildValue("I", i);
}
static PyObject *
UPnP_totalpacketsent(UPnPObject *self)
{
UNSIGNED_INTEGER i;
Py_BEGIN_ALLOW_THREADS
i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
self->data.CIF.servicetype);
Py_END_ALLOW_THREADS
return Py_BuildValue("I", i);
}
static PyObject *
UPnP_totalpacketreceived(UPnPObject *self)
{
UNSIGNED_INTEGER i;
Py_BEGIN_ALLOW_THREADS
i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
self->data.CIF.servicetype);
Py_END_ALLOW_THREADS
return Py_BuildValue("I", i);
}
static PyObject *
UPnP_statusinfo(UPnPObject *self)
{
char status[64];
char lastconnerror[64];
unsigned int uptime = 0;
int r;
status[0] = '\0';
lastconnerror[0] = '\0';
Py_BEGIN_ALLOW_THREADS
r = UPNP_GetStatusInfo(self->urls.controlURL, self->data.first.servicetype,
status, &uptime, lastconnerror);
Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS) {
return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);
} else {
/* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, strupnperror(r));
return NULL;
}
}
static PyObject *
UPnP_connectiontype(UPnPObject *self)
{
char connectionType[64];
int r;
connectionType[0] = '\0';
Py_BEGIN_ALLOW_THREADS
r = UPNP_GetConnectionTypeInfo(self->urls.controlURL,
self->data.first.servicetype,
connectionType);
Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS) {
return Py_BuildValue("s", connectionType);
} else {
/* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, strupnperror(r));
return NULL;
}
}
static PyObject *
UPnP_externalipaddress(UPnPObject *self)
{
char externalIPAddress[40];
int r;
externalIPAddress[0] = '\0';
Py_BEGIN_ALLOW_THREADS
r = UPNP_GetExternalIPAddress(self->urls.controlURL,
self->data.first.servicetype,
externalIPAddress);
Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS) {
return Py_BuildValue("s", externalIPAddress);
} else {
/* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, strupnperror(r));
return NULL;
}
}
/* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc,
* remoteHost)
* protocol is 'UDP' or 'TCP' */
static PyObject *
UPnP_addportmapping(UPnPObject *self, PyObject *args)
{
char extPort[6];
unsigned short ePort;
char inPort[6];
unsigned short iPort;
const char * proto;
const char * host;
const char * desc;
const char * remoteHost;
const char * leaseDuration = "0";
int r;
if (!PyArg_ParseTuple(args, "HssHss", &ePort, &proto,
&host, &iPort, &desc, &remoteHost))
return NULL;
Py_BEGIN_ALLOW_THREADS
sprintf(extPort, "%hu", ePort);
sprintf(inPort, "%hu", iPort);
r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype,
extPort, inPort, host, desc, proto,
remoteHost, leaseDuration);
Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS)
{
Py_RETURN_TRUE;
}
else
{
// TODO: RAISE an Exception. See upnpcommands.h for errors codes.
// upnperrors.c
//Py_RETURN_FALSE;
/* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, strupnperror(r));
return NULL;
}
}
/* DeletePortMapping(extPort, proto, removeHost='')
* proto = 'UDP', 'TCP' */
static PyObject *
UPnP_deleteportmapping(UPnPObject *self, PyObject *args)
{
char extPort[6];
unsigned short ePort;
const char * proto;
const char * remoteHost = "";
int r;
if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
return NULL;
Py_BEGIN_ALLOW_THREADS
sprintf(extPort, "%hu", ePort);
r = UPNP_DeletePortMapping(self->urls.controlURL, self->data.first.servicetype,
extPort, proto, remoteHost);
Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS) {
Py_RETURN_TRUE;
} else {
/* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, strupnperror(r));
return NULL;
}
}
static PyObject *
UPnP_getportmappingnumberofentries(UPnPObject *self)
{
unsigned int n = 0;
int r;
Py_BEGIN_ALLOW_THREADS
r = UPNP_GetPortMappingNumberOfEntries(self->urls.controlURL,
self->data.first.servicetype,
&n);
Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS) {
return Py_BuildValue("I", n);
} else {
/* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, strupnperror(r));
return NULL;
}
}
/* GetSpecificPortMapping(ePort, proto, remoteHost='')
* proto = 'UDP' or 'TCP' */
static PyObject *
UPnP_getspecificportmapping(UPnPObject *self, PyObject *args)
{
char extPort[6];
unsigned short ePort;
const char * proto;
const char * remoteHost = "";
char intClient[40];
char intPort[6];
unsigned short iPort;
char desc[80];
char enabled[4];
char leaseDuration[16];
if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost))
return NULL;
extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0';
desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0';
Py_BEGIN_ALLOW_THREADS
sprintf(extPort, "%hu", ePort);
UPNP_GetSpecificPortMappingEntry(self->urls.controlURL,
self->data.first.servicetype,
extPort, proto, remoteHost,
intClient, intPort,
desc, enabled, leaseDuration);
Py_END_ALLOW_THREADS
if(intClient[0])
{
iPort = (unsigned short)atoi(intPort);
return Py_BuildValue("(s,H,s,O,i)",
intClient, iPort, desc,
PyBool_FromLong(atoi(enabled)),
atoi(leaseDuration));
}
else
{
Py_RETURN_NONE;
}
}
/* GetGenericPortMapping(index) */
static PyObject *
UPnP_getgenericportmapping(UPnPObject *self, PyObject *args)
{
int i, r;
char index[8];
char intClient[40];
char intPort[6];
unsigned short iPort;
char extPort[6];
unsigned short ePort;
char protocol[4];
char desc[80];
char enabled[6];
char rHost[64];
char duration[16]; /* lease duration */
unsigned int dur;
if(!PyArg_ParseTuple(args, "i", &i))
return NULL;
Py_BEGIN_ALLOW_THREADS
snprintf(index, sizeof(index), "%d", i);
rHost[0] = '\0'; enabled[0] = '\0';
duration[0] = '\0'; desc[0] = '\0';
extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0';
r = UPNP_GetGenericPortMappingEntry(self->urls.controlURL,
self->data.first.servicetype,
index,
extPort, intClient, intPort,
protocol, desc, enabled, rHost,
duration);
Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS)
{
ePort = (unsigned short)atoi(extPort);
iPort = (unsigned short)atoi(intPort);
dur = (unsigned int)strtoul(duration, 0, 0);
return Py_BuildValue("(H,s,(s,H),s,s,s,I)",
ePort, protocol, intClient, iPort,
desc, enabled, rHost, dur);
}
else
{
Py_RETURN_NONE;
}
}
/* miniupnpc.UPnP object Method Table */
static PyMethodDef UPnP_methods[] = {
{"discover", (PyCFunction)UPnP_discover, METH_NOARGS,
"discover UPnP IGD devices on the network"
},
{"selectigd", (PyCFunction)UPnP_selectigd, METH_NOARGS,
"select a valid UPnP IGD among discovered devices"
},
{"totalbytesent", (PyCFunction)UPnP_totalbytesent, METH_NOARGS,
"return the total number of bytes sent by UPnP IGD"
},
{"totalbytereceived", (PyCFunction)UPnP_totalbytereceived, METH_NOARGS,
"return the total number of bytes received by UPnP IGD"
},
{"totalpacketsent", (PyCFunction)UPnP_totalpacketsent, METH_NOARGS,
"return the total number of packets sent by UPnP IGD"
},
{"totalpacketreceived", (PyCFunction)UPnP_totalpacketreceived, METH_NOARGS,
"return the total number of packets received by UPnP IGD"
},
{"statusinfo", (PyCFunction)UPnP_statusinfo, METH_NOARGS,
"return status and uptime"
},
{"connectiontype", (PyCFunction)UPnP_connectiontype, METH_NOARGS,
"return IGD WAN connection type"
},
{"externalipaddress", (PyCFunction)UPnP_externalipaddress, METH_NOARGS,
"return external IP address"
},
{"addportmapping", (PyCFunction)UPnP_addportmapping, METH_VARARGS,
"add a port mapping"
},
{"deleteportmapping", (PyCFunction)UPnP_deleteportmapping, METH_VARARGS,
"delete a port mapping"
},
{"getportmappingnumberofentries", (PyCFunction)UPnP_getportmappingnumberofentries, METH_NOARGS,
"-- non standard --"
},
{"getspecificportmapping", (PyCFunction)UPnP_getspecificportmapping, METH_VARARGS,
"get details about a specific port mapping entry"
},
{"getgenericportmapping", (PyCFunction)UPnP_getgenericportmapping, METH_VARARGS,
"get all details about the port mapping at index"
},
{NULL} /* Sentinel */
};
static PyTypeObject UPnPType = {
PyVarObject_HEAD_INIT(NULL,
0) /*ob_size*/
"miniupnpc.UPnP", /*tp_name*/
sizeof(UPnPObject), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)UPnPObject_dealloc,/*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
"UPnP objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
UPnP_methods, /* tp_methods */
UPnP_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0,/*(initproc)UPnP_init,*/ /* tp_init */
0, /* tp_alloc */
#ifndef _WIN32
PyType_GenericNew,/*UPnP_new,*/ /* tp_new */
#else
0,
#endif
};
/* module methods */
static PyMethodDef miniupnpc_methods[] = {
{NULL} /* Sentinel */
};
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"miniupnpc", /* m_name */
"miniupnpc module.", /* m_doc */
-1, /* m_size */
miniupnpc_methods, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
#endif
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
#if PY_MAJOR_VERSION >= 3
PyInit_miniupnpc(void)
#else
initminiupnpc(void)
#endif
{
PyObject* m;
#ifdef _WIN32
UPnPType.tp_new = PyType_GenericNew;
#endif
if (PyType_Ready(&UPnPType) < 0)
return;
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&moduledef);
#else
m = Py_InitModule3("miniupnpc", miniupnpc_methods,
"miniupnpc module.");
#endif
Py_INCREF(&UPnPType);
PyModule_AddObject(m, "UPnP", (PyObject *)&UPnPType);
#if PY_MAJOR_VERSION >= 3
return m;
#endif
}

View file

@ -1,7 +0,0 @@
#ifndef MINIUPNPCSTRINGS_H_INCLUDED
#define MINIUPNPCSTRINGS_H_INCLUDED
#define OS_STRING "${CMAKE_SYSTEM_NAME}"
#define MINIUPNPC_VERSION_STRING "${MINIUPNPC_VERSION}"
#endif

View file

@ -1,15 +0,0 @@
/* $Id: miniupnpcstrings.h.in,v 1.5 2012/10/16 16:48:26 nanard Exp $ */
/* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author: Thomas Bernard
* Copyright (c) 2005-2011 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINIUPNPCSTRINGS_H_INCLUDED
#define MINIUPNPCSTRINGS_H_INCLUDED
#define OS_STRING "OS/version"
#define MINIUPNPC_VERSION_STRING "version"
#endif

View file

@ -1,19 +0,0 @@
/* $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

View file

@ -1,575 +0,0 @@
/* $Id: miniwget.c,v 1.61 2014/02/05 17:27:48 nanard Exp $ */
/* Project : miniupnp
* Website : http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
#define MAXHOSTNAMELEN 64
#define MIN(x,y) (((x)<(y))?(x):(y))
#define snprintf _snprintf
#define socklen_t int
#ifndef strncasecmp
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#define strncasecmp _memicmp
#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
#define strncasecmp memicmp
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
#endif /* #ifndef strncasecmp */
#else /* #ifdef _WIN32 */
#include <unistd.h>
#include <sys/param.h>
#if defined(__amigaos__) && !defined(__amigaos4__)
#define socklen_t int
#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
#include <sys/select.h>
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netdb.h>
#define closesocket close
#endif /* #else _WIN32 */
#if defined(__sun) || defined(sun)
#define MIN(x,y) (((x)<(y))?(x):(y))
#endif
#include "miniupnpcstrings.h"
#include "miniwget.h"
#include "connecthostport.h"
#include "receivedata.h"
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
/*
* Read a HTTP response from a socket.
* Process Content-Length and Transfer-encoding headers.
* return a pointer to the content buffer, which length is saved
* to the length parameter.
*/
void *
getHTTPResponse(int s, int * size)
{
char buf[2048];
int n;
int endofheaders = 0;
int chunked = 0;
int content_length = -1;
unsigned int chunksize = 0;
unsigned int bytestocopy = 0;
/* buffers : */
char * header_buf;
unsigned int header_buf_len = 2048;
unsigned int header_buf_used = 0;
char * content_buf;
unsigned int content_buf_len = 2048;
unsigned int content_buf_used = 0;
char chunksize_buf[32];
unsigned int chunksize_buf_index;
header_buf = malloc(header_buf_len);
content_buf = malloc(content_buf_len);
chunksize_buf[0] = '\0';
chunksize_buf_index = 0;
while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0)
{
if(endofheaders == 0)
{
int i;
int linestart=0;
int colon=0;
int valuestart=0;
if(header_buf_used + n > header_buf_len) {
header_buf = realloc(header_buf, header_buf_used + n);
header_buf_len = header_buf_used + n;
}
memcpy(header_buf + header_buf_used, buf, n);
header_buf_used += n;
/* search for CR LF CR LF (end of headers)
* recognize also LF LF */
i = 0;
while(i < ((int)header_buf_used-1) && (endofheaders == 0)) {
if(header_buf[i] == '\r') {
i++;
if(header_buf[i] == '\n') {
i++;
if(i < (int)header_buf_used && header_buf[i] == '\r') {
i++;
if(i < (int)header_buf_used && header_buf[i] == '\n') {
endofheaders = i+1;
}
}
}
} else if(header_buf[i] == '\n') {
i++;
if(header_buf[i] == '\n') {
endofheaders = i+1;
}
}
i++;
}
if(endofheaders == 0)
continue;
/* parse header lines */
for(i = 0; i < endofheaders - 1; i++) {
if(colon <= linestart && header_buf[i]==':')
{
colon = i;
while(i < (endofheaders-1)
&& (header_buf[i+1] == ' ' || header_buf[i+1] == '\t'))
i++;
valuestart = i + 1;
}
/* detecting end of line */
else if(header_buf[i]=='\r' || header_buf[i]=='\n')
{
if(colon > linestart && valuestart > colon)
{
#ifdef DEBUG
printf("header='%.*s', value='%.*s'\n",
colon-linestart, header_buf+linestart,
i-valuestart, header_buf+valuestart);
#endif
if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart))
{
content_length = atoi(header_buf+valuestart);
#ifdef DEBUG
printf("Content-Length: %d\n", content_length);
#endif
}
else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart)
&& 0==strncasecmp(header_buf+valuestart, "chunked", 7))
{
#ifdef DEBUG
printf("chunked transfer-encoding!\n");
#endif
chunked = 1;
}
}
while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n'))
i++;
linestart = i;
colon = linestart;
valuestart = 0;
}
}
/* copy the remaining of the received data back to buf */
n = header_buf_used - endofheaders;
memcpy(buf, header_buf + endofheaders, n);
/* if(headers) */
}
if(endofheaders)
{
/* content */
if(chunked)
{
int i = 0;
while(i < n)
{
if(chunksize == 0)
{
/* reading chunk size */
if(chunksize_buf_index == 0) {
/* skipping any leading CR LF */
if(i<n && buf[i] == '\r') i++;
if(i<n && buf[i] == '\n') i++;
}
while(i<n && isxdigit(buf[i])
&& chunksize_buf_index < (sizeof(chunksize_buf)-1))
{
chunksize_buf[chunksize_buf_index++] = buf[i];
chunksize_buf[chunksize_buf_index] = '\0';
i++;
}
while(i<n && buf[i] != '\r' && buf[i] != '\n')
i++; /* discarding chunk-extension */
if(i<n && buf[i] == '\r') i++;
if(i<n && buf[i] == '\n') {
unsigned int j;
for(j = 0; j < chunksize_buf_index; j++) {
if(chunksize_buf[j] >= '0'
&& chunksize_buf[j] <= '9')
chunksize = (chunksize << 4) + (chunksize_buf[j] - '0');
else
chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10);
}
chunksize_buf[0] = '\0';
chunksize_buf_index = 0;
i++;
} else {
/* not finished to get chunksize */
continue;
}
#ifdef DEBUG
printf("chunksize = %u (%x)\n", chunksize, chunksize);
#endif
if(chunksize == 0)
{
#ifdef DEBUG
printf("end of HTTP content - %d %d\n", i, n);
/*printf("'%.*s'\n", n-i, buf+i);*/
#endif
goto end_of_stream;
}
}
bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i);
if((content_buf_used + bytestocopy) > content_buf_len)
{
if(content_length >= (int)(content_buf_used + bytestocopy)) {
content_buf_len = content_length;
} else {
content_buf_len = content_buf_used + bytestocopy;
}
content_buf = (char *)realloc((void *)content_buf,
content_buf_len);
}
memcpy(content_buf + content_buf_used, buf + i, bytestocopy);
content_buf_used += bytestocopy;
i += bytestocopy;
chunksize -= bytestocopy;
}
}
else
{
/* not chunked */
if(content_length > 0
&& (int)(content_buf_used + n) > content_length) {
/* skipping additional bytes */
n = content_length - content_buf_used;
}
if(content_buf_used + n > content_buf_len)
{
if(content_length >= (int)(content_buf_used + n)) {
content_buf_len = content_length;
} else {
content_buf_len = content_buf_used + n;
}
content_buf = (char *)realloc((void *)content_buf,
content_buf_len);
}
memcpy(content_buf + content_buf_used, buf, n);
content_buf_used += n;
}
}
/* use the Content-Length header value if available */
if(content_length > 0 && (int)content_buf_used >= content_length)
{
#ifdef DEBUG
printf("End of HTTP content\n");
#endif
break;
}
}
end_of_stream:
free(header_buf); header_buf = NULL;
*size = content_buf_used;
if(content_buf_used == 0)
{
free(content_buf);
content_buf = NULL;
}
return content_buf;
}
/* miniwget3() :
* do all the work.
* Return NULL if something failed. */
static void *
miniwget3(const char * host,
unsigned short port, const char * path,
int * size, char * addr_str, int addr_str_len,
const char * httpversion, unsigned int scope_id)
{
char buf[2048];
int s;
int n;
int len;
int sent;
void * content;
*size = 0;
s = connecthostport(host, port, scope_id);
if(s < 0)
return NULL;
/* get address for caller ! */
if(addr_str)
{
struct sockaddr_storage saddr;
socklen_t saddrlen;
saddrlen = sizeof(saddr);
if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0)
{
perror("getsockname");
}
else
{
#if defined(__amigaos__) && !defined(__amigaos4__)
/* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD);
* But his function make a string with the port : nn.nn.nn.nn:port */
/* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr),
NULL, addr_str, (DWORD *)&addr_str_len))
{
printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError());
}*/
/* the following code is only compatible with ip v4 addresses */
strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len);
#else
#if 0
if(saddr.sa_family == AF_INET6) {
inet_ntop(AF_INET6,
&(((struct sockaddr_in6 *)&saddr)->sin6_addr),
addr_str, addr_str_len);
} else {
inet_ntop(AF_INET,
&(((struct sockaddr_in *)&saddr)->sin_addr),
addr_str, addr_str_len);
}
#endif
/* getnameinfo return ip v6 address with the scope identifier
* such as : 2a01:e35:8b2b:7330::%4281128194 */
n = getnameinfo((const struct sockaddr *)&saddr, saddrlen,
addr_str, addr_str_len,
NULL, 0,
NI_NUMERICHOST | NI_NUMERICSERV);
if(n != 0) {
#ifdef _WIN32
fprintf(stderr, "getnameinfo() failed : %d\n", n);
#else
fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n));
#endif
}
#endif
}
#ifdef DEBUG
printf("address miniwget : %s\n", addr_str);
#endif
}
len = snprintf(buf, sizeof(buf),
"GET %s HTTP/%s\r\n"
"Host: %s:%d\r\n"
"Connection: Close\r\n"
"User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
"\r\n",
path, httpversion, host, port);
sent = 0;
/* sending the HTTP request */
while(sent < len)
{
n = send(s, buf+sent, len-sent, 0);
if(n < 0)
{
perror("send");
closesocket(s);
return NULL;
}
else
{
sent += n;
}
}
content = getHTTPResponse(s, size);
closesocket(s);
return content;
}
/* miniwget2() :
* Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */
static void *
miniwget2(const char * host,
unsigned short port, const char * path,
int * size, char * addr_str, int addr_str_len,
unsigned int scope_id)
{
char * respbuffer;
#if 1
respbuffer = miniwget3(host, port, path, size,
addr_str, addr_str_len, "1.1", scope_id);
#else
respbuffer = miniwget3(host, port, path, size,
addr_str, addr_str_len, "1.0", scope_id);
if (*size == 0)
{
#ifdef DEBUG
printf("Retrying with HTTP/1.1\n");
#endif
free(respbuffer);
respbuffer = miniwget3(host, port, path, size,
addr_str, addr_str_len, "1.1", scope_id);
}
#endif
return respbuffer;
}
/* parseURL()
* arguments :
* url : source string not modified
* hostname : hostname destination string (size of MAXHOSTNAMELEN+1)
* port : port (destination)
* path : pointer to the path part of the URL
*
* Return values :
* 0 - Failure
* 1 - Success */
int
parseURL(const char * url,
char * hostname, unsigned short * port,
char * * path, unsigned int * scope_id)
{
char * p1, *p2, *p3;
if(!url)
return 0;
p1 = strstr(url, "://");
if(!p1)
return 0;
p1 += 3;
if( (url[0]!='h') || (url[1]!='t')
||(url[2]!='t') || (url[3]!='p'))
return 0;
memset(hostname, 0, MAXHOSTNAMELEN + 1);
if(*p1 == '[')
{
/* IP v6 : http://[2a00:1450:8002::6a]/path/abc */
char * scope;
scope = strchr(p1, '%');
p2 = strchr(p1, ']');
if(p2 && scope && scope < p2 && scope_id) {
/* parse scope */
#ifdef IF_NAMESIZE
char tmp[IF_NAMESIZE];
int l;
scope++;
/* "%25" is just '%' in URL encoding */
if(scope[0] == '2' && scope[1] == '5')
scope += 2; /* skip "25" */
l = p2 - scope;
if(l >= IF_NAMESIZE)
l = IF_NAMESIZE - 1;
memcpy(tmp, scope, l);
tmp[l] = '\0';
*scope_id = if_nametoindex(tmp);
if(*scope_id == 0) {
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
}
#else
/* under windows, scope is numerical */
char tmp[8];
int l;
scope++;
/* "%25" is just '%' in URL encoding */
if(scope[0] == '2' && scope[1] == '5')
scope += 2; /* skip "25" */
l = p2 - scope;
if(l >= sizeof(tmp))
l = sizeof(tmp) - 1;
memcpy(tmp, scope, l);
tmp[l] = '\0';
*scope_id = (unsigned int)strtoul(tmp, NULL, 10);
#endif
}
p3 = strchr(p1, '/');
if(p2 && p3)
{
p2++;
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
if(*p2 == ':')
{
*port = 0;
p2++;
while( (*p2 >= '0') && (*p2 <= '9'))
{
*port *= 10;
*port += (unsigned short)(*p2 - '0');
p2++;
}
}
else
{
*port = 80;
}
*path = p3;
return 1;
}
}
p2 = strchr(p1, ':');
p3 = strchr(p1, '/');
if(!p3)
return 0;
if(!p2 || (p2>p3))
{
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1)));
*port = 80;
}
else
{
strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
*port = 0;
p2++;
while( (*p2 >= '0') && (*p2 <= '9'))
{
*port *= 10;
*port += (unsigned short)(*p2 - '0');
p2++;
}
}
*path = p3;
return 1;
}
void *
miniwget(const char * url, int * size, unsigned int scope_id)
{
unsigned short port;
char * path;
/* protocol://host:port/chemin */
char hostname[MAXHOSTNAMELEN+1];
*size = 0;
if(!parseURL(url, hostname, &port, &path, &scope_id))
return NULL;
#ifdef DEBUG
printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
hostname, port, path, scope_id);
#endif
return miniwget2(hostname, port, path, size, 0, 0, scope_id);
}
void *
miniwget_getaddr(const char * url, int * size,
char * addr, int addrlen, unsigned int scope_id)
{
unsigned short port;
char * path;
/* protocol://host:port/path */
char hostname[MAXHOSTNAMELEN+1];
*size = 0;
if(addr)
addr[0] = '\0';
if(!parseURL(url, hostname, &port, &path, &scope_id))
return NULL;
#ifdef DEBUG
printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
hostname, port, path, scope_id);
#endif
return miniwget2(hostname, port, path, size, addr, addrlen, scope_id);
}

View file

@ -1,30 +0,0 @@
/* $Id: miniwget.h,v 1.8 2012/09/27 15:42:10 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
#ifndef MINIWGET_H_INCLUDED
#define MINIWGET_H_INCLUDED
#include "declspec.h"
#ifdef __cplusplus
extern "C" {
#endif
LIBSPEC void * getHTTPResponse(int s, int * size);
LIBSPEC void * miniwget(const char *, int *, unsigned int);
LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int);
int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,229 +0,0 @@
/* $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);
}

View file

@ -1,37 +0,0 @@
/* $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

View file

@ -1,158 +0,0 @@
/* $Id: minixmlvalid.c,v 1.6 2012/05/01 16:24:07 nanard Exp $ */
/* MiniUPnP Project
* http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
* minixmlvalid.c :
* validation program for the minixml parser
*
* (c) 2006-2011 Thomas Bernard */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "minixml.h"
/* xml event structure */
struct event {
enum { ELTSTART, ELTEND, ATT, CHARDATA } type;
const char * data;
int len;
};
struct eventlist {
int n;
struct event * events;
};
/* compare 2 xml event lists
* return 0 if the two lists are equals */
int evtlistcmp(struct eventlist * a, struct eventlist * b)
{
int i;
struct event * ae, * be;
if(a->n != b->n)
{
printf("event number not matching : %d != %d\n", a->n, b->n);
/*return 1;*/
}
for(i=0; i<a->n; i++)
{
ae = a->events + i;
be = b->events + i;
if( (ae->type != be->type)
||(ae->len != be->len)
||memcmp(ae->data, be->data, ae->len))
{
printf("Found a difference : %d '%.*s' != %d '%.*s'\n",
ae->type, ae->len, ae->data,
be->type, be->len, be->data);
return 1;
}
}
return 0;
}
/* Test data */
static const char xmldata[] =
"<xmlroot>\n"
" <elt1 att1=\"attvalue1\" att2=\"attvalue2\">"
"character data"
"</elt1> \n \t"
"<elt1b/>"
"<elt1>\n<![CDATA[ <html>stuff !\n ]]> \n</elt1>\n"
"<elt2a> \t<elt2b>chardata1</elt2b><elt2b> chardata2 </elt2b></elt2a>"
"</xmlroot>";
static const struct event evtref[] =
{
{ELTSTART, "xmlroot", 7},
{ELTSTART, "elt1", 4},
/* attributes */
{CHARDATA, "character data", 14},
{ELTEND, "elt1", 4},
{ELTSTART, "elt1b", 5},
{ELTSTART, "elt1", 4},
{CHARDATA, " <html>stuff !\n ", 16},
{ELTEND, "elt1", 4},
{ELTSTART, "elt2a", 5},
{ELTSTART, "elt2b", 5},
{CHARDATA, "chardata1", 9},
{ELTEND, "elt2b", 5},
{ELTSTART, "elt2b", 5},
{CHARDATA, " chardata2 ", 11},
{ELTEND, "elt2b", 5},
{ELTEND, "elt2a", 5},
{ELTEND, "xmlroot", 7}
};
void startelt(void * data, const char * p, int l)
{
struct eventlist * evtlist = data;
struct event * evt;
evt = evtlist->events + evtlist->n;
/*printf("startelt : %.*s\n", l, p);*/
evt->type = ELTSTART;
evt->data = p;
evt->len = l;
evtlist->n++;
}
void endelt(void * data, const char * p, int l)
{
struct eventlist * evtlist = data;
struct event * evt;
evt = evtlist->events + evtlist->n;
/*printf("endelt : %.*s\n", l, p);*/
evt->type = ELTEND;
evt->data = p;
evt->len = l;
evtlist->n++;
}
void chardata(void * data, const char * p, int l)
{
struct eventlist * evtlist = data;
struct event * evt;
evt = evtlist->events + evtlist->n;
/*printf("chardata : '%.*s'\n", l, p);*/
evt->type = CHARDATA;
evt->data = p;
evt->len = l;
evtlist->n++;
}
int testxmlparser(const char * xml, int size)
{
int r;
struct eventlist evtlist;
struct eventlist evtlistref;
struct xmlparser parser;
evtlist.n = 0;
evtlist.events = malloc(sizeof(struct event)*100);
memset(&parser, 0, sizeof(parser));
parser.xmlstart = xml;
parser.xmlsize = size;
parser.data = &evtlist;
parser.starteltfunc = startelt;
parser.endeltfunc = endelt;
parser.datafunc = chardata;
parsexml(&parser);
printf("%d events\n", evtlist.n);
/* compare */
evtlistref.n = sizeof(evtref)/sizeof(struct event);
evtlistref.events = (struct event *)evtref;
r = evtlistcmp(&evtlistref, &evtlist);
free(evtlist.events);
return r;
}
int main(int argc, char * * argv)
{
int r;
(void)argc; (void)argv;
r = testxmlparser(xmldata, sizeof(xmldata)-1);
if(r)
printf("minixml validation test failed\n");
return r;
}

View file

@ -1,29 +0,0 @@

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

View file

@ -1,271 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="miniupnpc"
ProjectGUID="{D28CE435-CB33-4BAE-8A52-C6EF915956F5}"
RootNamespace="miniupnpc"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;WIN32;STATICLIB;DEBUG"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;WIN32;STATICLIB"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Fichiers sources"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\connecthostport.c"
>
</File>
<File
RelativePath="..\igd_desc_parse.c"
>
</File>
<File
RelativePath="..\minisoap.c"
>
</File>
<File
RelativePath="..\miniupnpc.c"
>
</File>
<File
RelativePath="..\miniwget.c"
>
</File>
<File
RelativePath="..\minixml.c"
>
</File>
<File
RelativePath="..\portlistingparse.c"
>
</File>
<File
RelativePath="..\receivedata.c"
>
</File>
<File
RelativePath="..\upnpcommands.c"
>
</File>
<File
RelativePath="..\upnperrors.c"
>
</File>
<File
RelativePath="..\upnpreplyparse.c"
>
</File>
</Filter>
<Filter
Name="Fichiers d&apos;en-tête"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\bsdqueue.h"
>
</File>
<File
RelativePath="..\connecthostport.h"
>
</File>
<File
RelativePath="..\declspec.h"
>
</File>
<File
RelativePath="..\igd_desc_parse.h"
>
</File>
<File
RelativePath="..\minisoap.h"
>
</File>
<File
RelativePath="..\miniupnpc.h"
>
</File>
<File
RelativePath="..\miniupnpcstrings.h"
>
</File>
<File
RelativePath="..\miniupnpctypes.h"
>
</File>
<File
RelativePath="..\miniwget.h"
>
</File>
<File
RelativePath="..\minixml.h"
>
</File>
<File
RelativePath="..\portlistingparse.h"
>
</File>
<File
RelativePath="..\receivedata.h"
>
</File>
<File
RelativePath="..\upnpcommands.h"
>
</File>
<File
RelativePath="..\upnperrors.h"
>
</File>
<File
RelativePath="..\upnpreplyparse.h"
>
</File>
</Filter>
<Filter
Name="Fichiers de ressources"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -1,195 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="upnpc-static"
ProjectGUID="{469E1CF6-08A2-4B7B-A2AA-5BDB089857C1}"
RootNamespace="upnpcstatic"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;STATICLIB;DEBUG;_CRT_SECURE_NO_WARNINGS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib IPHlpApi.Lib Debug\miniupnpc.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;STATICLIB"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib IPHlpApi.Lib Release\miniupnpc.lib"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Fichiers sources"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\upnpc.c"
>
</File>
</Filter>
<Filter
Name="Fichiers d&apos;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>

View file

@ -1,159 +0,0 @@
/* $Id: portlistingparse.c,v 1.6 2012/05/29 10:26:51 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#include <string.h>
#include <stdlib.h>
#include "portlistingparse.h"
#include "minixml.h"
/* list of the elements */
static const struct {
const portMappingElt code;
const char * const str;
} elements[] = {
{ PortMappingEntry, "PortMappingEntry"},
{ NewRemoteHost, "NewRemoteHost"},
{ NewExternalPort, "NewExternalPort"},
{ NewProtocol, "NewProtocol"},
{ NewInternalPort, "NewInternalPort"},
{ NewInternalClient, "NewInternalClient"},
{ NewEnabled, "NewEnabled"},
{ NewDescription, "NewDescription"},
{ NewLeaseTime, "NewLeaseTime"},
{ PortMappingEltNone, NULL}
};
/* Helper function */
static UNSIGNED_INTEGER
atoui(const char * p, int l)
{
UNSIGNED_INTEGER r = 0;
while(l > 0 && *p)
{
if(*p >= '0' && *p <= '9')
r = r*10 + (*p - '0');
else
break;
p++;
l--;
}
return r;
}
/* Start element handler */
static void
startelt(void * d, const char * name, int l)
{
int i;
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
pdata->curelt = PortMappingEltNone;
for(i = 0; elements[i].str; i++)
{
if(memcmp(name, elements[i].str, l) == 0)
{
pdata->curelt = elements[i].code;
break;
}
}
if(pdata->curelt == PortMappingEntry)
{
struct PortMapping * pm;
pm = calloc(1, sizeof(struct PortMapping));
LIST_INSERT_HEAD( &(pdata->head), pm, entries);
}
}
/* End element handler */
static void
endelt(void * d, const char * name, int l)
{
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
(void)name;
(void)l;
pdata->curelt = PortMappingEltNone;
}
/* Data handler */
static void
data(void * d, const char * data, int l)
{
struct PortMapping * pm;
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
pm = pdata->head.lh_first;
if(!pm)
return;
if(l > 63)
l = 63;
switch(pdata->curelt)
{
case NewRemoteHost:
memcpy(pm->remoteHost, data, l);
pm->remoteHost[l] = '\0';
break;
case NewExternalPort:
pm->externalPort = (unsigned short)atoui(data, l);
break;
case NewProtocol:
if(l > 3)
l = 3;
memcpy(pm->protocol, data, l);
pm->protocol[l] = '\0';
break;
case NewInternalPort:
pm->internalPort = (unsigned short)atoui(data, l);
break;
case NewInternalClient:
memcpy(pm->internalClient, data, l);
pm->internalClient[l] = '\0';
break;
case NewEnabled:
pm->enabled = (unsigned char)atoui(data, l);
break;
case NewDescription:
memcpy(pm->description, data, l);
pm->description[l] = '\0';
break;
case NewLeaseTime:
pm->leaseTime = atoui(data, l);
break;
default:
break;
}
}
/* Parse the PortMappingList XML document for IGD version 2
*/
void
ParsePortListing(const char * buffer, int bufsize,
struct PortMappingParserData * pdata)
{
struct xmlparser parser;
memset(pdata, 0, sizeof(struct PortMappingParserData));
LIST_INIT(&(pdata->head));
/* init xmlparser */
parser.xmlstart = buffer;
parser.xmlsize = bufsize;
parser.data = pdata;
parser.starteltfunc = startelt;
parser.endeltfunc = endelt;
parser.datafunc = data;
parser.attfunc = 0;
parsexml(&parser);
}
void
FreePortListing(struct PortMappingParserData * pdata)
{
struct PortMapping * pm;
while((pm = pdata->head.lh_first) != NULL)
{
LIST_REMOVE(pm, entries);
free(pm);
}
}

View file

@ -1,71 +0,0 @@
/* $Id: portlistingparse.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011-2012 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef PORTLISTINGPARSE_H_INCLUDED
#define PORTLISTINGPARSE_H_INCLUDED
#include "declspec.h"
/* for the definition of UNSIGNED_INTEGER */
#include "miniupnpctypes.h"
#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__)
#include "bsdqueue.h"
#else
#include <sys/queue.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* sample of PortMappingEntry :
<p:PortMappingEntry>
<p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
<p:NewExternalPort>2345</p:NewExternalPort>
<p:NewProtocol>TCP</p:NewProtocol>
<p:NewInternalPort>2345</p:NewInternalPort>
<p:NewInternalClient>192.168.1.137</p:NewInternalClient>
<p:NewEnabled>1</p:NewEnabled>
<p:NewDescription>dooom</p:NewDescription>
<p:NewLeaseTime>345</p:NewLeaseTime>
</p:PortMappingEntry>
*/
typedef enum { PortMappingEltNone,
PortMappingEntry, NewRemoteHost,
NewExternalPort, NewProtocol,
NewInternalPort, NewInternalClient,
NewEnabled, NewDescription,
NewLeaseTime } portMappingElt;
struct PortMapping {
LIST_ENTRY(PortMapping) entries;
UNSIGNED_INTEGER leaseTime;
unsigned short externalPort;
unsigned short internalPort;
char remoteHost[64];
char internalClient[64];
char description[64];
char protocol[4];
unsigned char enabled;
};
struct PortMappingParserData {
LIST_HEAD(portmappinglisthead, PortMapping) head;
portMappingElt curelt;
};
LIBSPEC void
ParsePortListing(const char * buffer, int bufsize,
struct PortMappingParserData * pdata);
LIBSPEC void
FreePortListing(struct PortMappingParserData * pdata);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,52 +0,0 @@
#! /usr/bin/python
# MiniUPnP project
# Author : Thomas Bernard
# This Sample code is public domain.
# website : http://miniupnp.tuxfamily.org/
# import the python miniupnpc module
import miniupnpc
import sys
# create the object
u = miniupnpc.UPnP()
print 'inital(default) values :'
print ' discoverdelay', u.discoverdelay
print ' lanaddr', u.lanaddr
print ' multicastif', u.multicastif
print ' minissdpdsocket', u.minissdpdsocket
u.discoverdelay = 200;
#u.minissdpdsocket = '../minissdpd/minissdpd.sock'
# discovery process, it usualy takes several seconds (2 seconds or more)
print 'Discovering... delay=%ums' % u.discoverdelay
print u.discover(), 'device(s) detected'
# select an igd
try:
u.selectigd()
except Exception, e:
print 'Exception :', e
sys.exit(1)
# display information about the IGD and the internet connection
print 'local ip address :', u.lanaddr
print 'external ip address :', u.externalipaddress()
print u.statusinfo(), u.connectiontype()
#print u.addportmapping(64000, 'TCP',
# '192.168.1.166', 63000, 'port mapping test', '')
#print u.deleteportmapping(64000, 'TCP')
port = 0
proto = 'UDP'
# list the redirections :
i = 0
while True:
p = u.getgenericportmapping(i)
if p==None:
break
print i, p
(port, proto, (ihost,iport), desc, c, d, e) = p
#print port, desc
i = i + 1
print u.getspecificportmapping(port, proto)

View file

@ -1,109 +0,0 @@
/* $Id: receivedata.c,v 1.5 2013/10/07 09:48:36 nanard Exp $ */
/* Project : miniupnp
* Website : http://miniupnp.free.fr/
* Author : Thomas Bernard
* Copyright (c) 2011-2012 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
#include <stdio.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <unistd.h>
#if defined(__amigaos__) && !defined(__amigaos4__)
#define socklen_t int
#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */
#include <sys/select.h>
#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */
#include <sys/socket.h>
#include <netinet/in.h>
#if !defined(__amigaos__) && !defined(__amigaos4__)
#include <poll.h>
#endif
#include <errno.h>
#define MINIUPNPC_IGNORE_EINTR
#endif
#ifdef _WIN32
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
#else
#define PRINT_SOCKET_ERROR(x) perror(x)
#endif
#include "receivedata.h"
int
receivedata(int socket,
char * data, int length,
int timeout, unsigned int * scope_id)
{
#if MINIUPNPC_GET_SRC_ADDR
#ifdef DEBUG
/* to shut up valgrind about uninit value */
struct sockaddr_storage src_addr = {0};
#else
struct sockaddr_storage src_addr;
#endif
socklen_t src_addr_len = sizeof(src_addr);
#endif
int n;
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
/* using poll */
struct pollfd fds[1]; /* for the poll */
#ifdef MINIUPNPC_IGNORE_EINTR
do {
#endif
fds[0].fd = socket;
fds[0].events = POLLIN;
n = poll(fds, 1, timeout);
#ifdef MINIUPNPC_IGNORE_EINTR
} while(n < 0 && errno == EINTR);
#endif
if(n < 0) {
PRINT_SOCKET_ERROR("poll");
return -1;
} else if(n == 0) {
/* timeout */
return 0;
}
#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
/* using select under _WIN32 and amigaos */
fd_set socketSet;
TIMEVAL timeval;
FD_ZERO(&socketSet);
FD_SET(socket, &socketSet);
timeval.tv_sec = timeout / 1000;
timeval.tv_usec = (timeout % 1000) * 1000;
n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval);
if(n < 0) {
PRINT_SOCKET_ERROR("select");
return -1;
} else if(n == 0) {
return 0;
}
#endif
#if MINIUPNPC_GET_SRC_ADDR
n = recvfrom(socket, data, length, 0,
(struct sockaddr *)&src_addr, &src_addr_len);
#else
n = recv(socket, data, length, 0);
#endif
if(n<0) {
PRINT_SOCKET_ERROR("recv");
}
#if MINIUPNPC_GET_SRC_ADDR
if (src_addr.ss_family == AF_INET6) {
const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr;
#ifdef DEBUG
printf("scope_id=%u\n", src_addr6->sin6_scope_id);
#endif
if(scope_id)
*scope_id = src_addr6->sin6_scope_id;
}
#endif
return n;
}

View file

@ -1,19 +0,0 @@
/* $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

View file

@ -1,18 +0,0 @@
#! /usr/bin/python
# $Id: setup.py,v 1.9 2012/05/23 08:50:10 nanard Exp $
# the MiniUPnP Project (c) 2007-2012 Thomas Bernard
# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
#
# python script to build the miniupnpc module under unix
#
# replace libminiupnpc.a by libminiupnpc.so for shared library usage
from distutils.core import setup, Extension
from distutils import sysconfig
sysconfig.get_config_vars()["OPT"] = ''
sysconfig.get_config_vars()["CFLAGS"] = ''
setup(name="miniupnpc", version="1.7",
ext_modules=[
Extension(name="miniupnpc", sources=["miniupnpcmodule.c"],
extra_objects=["libminiupnpc.a"])
])

View file

@ -1,18 +0,0 @@
#! /usr/bin/python
# $Id: setupmingw32.py,v 1.8 2012/05/23 08:50:10 nanard Exp $
# the MiniUPnP Project (c) 2007-2012 Thomas Bernard
# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
#
# python script to build the miniupnpc module under windows (using mingw32)
#
from distutils.core import setup, Extension
from distutils import sysconfig
sysconfig.get_config_vars()["OPT"] = ''
sysconfig.get_config_vars()["CFLAGS"] = ''
setup(name="miniupnpc", version="1.7",
ext_modules=[
Extension(name="miniupnpc", sources=["miniupnpcmodule.c"],
libraries=["ws2_32", "iphlpapi"],
extra_objects=["libminiupnpc.a"])
])

Some files were not shown because too many files have changed in this diff Show more