diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 00000000..22f692da --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,31 @@ +# image +image: Visual Studio 2017 + +# build platform +platform: x64 + +# clone directory +clone_folder: c:\xmr-stak-cpu + +install: + - mkdir c:\xmr-stak-dep + - curl -fsS http://slproweb.com/download/Win64OpenSSL-1_0_2L.exe -o Win64OpenSSL.exe + - Win64OpenSSL.exe /silent /verysilent /sp- /suppressmsgboxes + - curl -fsS https://www.open-mpi.org/software/hwloc/v1.11/downloads/hwloc-win64-build-1.11.7.zip -o hwloc-win64-build.zip + - 7z x hwloc-win64-build.zip -o"c:\xmr-stak-dep" -y > nul + - curl -fsS http://mirror.reismil.ch/gnu/libmicrohttpd/libmicrohttpd-latest-w32-bin.zip -o libmicrohttpd-w32-bin.zip + - 7z x libmicrohttpd-w32-bin.zip -o"c:\xmr-stak-dep" -y > nul + +build_script: + - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsMSBuildCmd.bat" + - cd c:\xmr-stak-cpu + - set CMAKE_PREFIX_PATH=C:\xmr-stak-dep\hwloc-win64-build-1.11.7;C:\xmr-stak-dep\libmicrohttpd-0.9.55-w32-bin\x86_64\VS2017\Release-static; + - cmake -G "Visual Studio 15 2017 Win64" -T v141,host=x64 . + - msbuild xmr-stak-cpu.sln /p:Configuration=Release + +test_script: + - cd c:\xmr-stak-cpu\bin\Release + - copy c:\xmr-stak-dep\hwloc-win64-build-1.11.7\bin\libhwloc-5.dll . + - copy c:\xmr-stak-dep\libmicrohttpd-0.9.55-w32-bin\x86_64\VS2017\Release-dll\libmicrohttpd-dll.dll . + - dir +# - xmr-stak-cpu.exe -c ..\..\..\config.txt diff --git a/.gitignore b/.gitignore index 60a43dbd..86a97f89 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ bin/ obj/ +build/ xmr-stak-cpu.layout xmr-stak-cpu.depend config-debug.txt diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..37b77490 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,75 @@ +dist: trusty + +osx_image: xcode8.3 + +sudo: false + +language: cpp + +addons: + apt: + packages: &default_packages + - cmake + - libmicrohttpd-dev + - libssl-dev + - libhwloc-dev + +matrix: + include: + - os: linux + compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - *default_packages + - gcc-5 + - g++-5 + env: + - CMAKE_CXX_COMPILER=g++-5 + - CMAKE_C_COMPILER=gcc-5 + + - os: linux + compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - *default_packages + - gcc-6 + - g++-6 + env: + - CMAKE_CXX_COMPILER=g++-6 + - CMAKE_C_COMPILER=gcc-6 + + - os: linux + compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - *default_packages + - gcc-7 + - g++-7 + env: + - CMAKE_CXX_COMPILER=g++-7 + - CMAKE_C_COMPILER=gcc-7 + + - os: osx + compiler: gcc + +before_install: + - if [ $TRAVIS_OS_NAME = osx ]; then brew tap homebrew/science; fi + +script: + - if [ $TRAVIS_OS_NAME = osx ]; then + brew install hwloc; + cmake -DMICROHTTPD_ENABLE=OFF -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl .; + else + cmake -D CMAKE_C_COMPILER=${CMAKE_C_COMPILER} -D CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} .; + fi; + - make VERBOSE=1 + - ./bin/xmr-stak-cpu -c ./config.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 68d24326..0a056bea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,9 +22,9 @@ list(APPEND CMAKE_PREFIX_PATH "$ENV{CMAKE_PREFIX_PATH}") # https://github.com/fireice-uk/xmr-stak-nvidia/pull/10#issuecomment-290821792 # If you remove this guard to compile with older gcc versions the miner will produce # a high rate of wrong shares. -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1) - message(FATAL_ERROR "GCC version must be at least 5.1!") + message(FATAL_ERROR "g++ version must be at least 5.1!") endif() endif() @@ -48,36 +48,98 @@ set(LIBS ${LIBS} ${CMAKE_THREAD_LIBS_INIT}) # Find microhttpd ################################################################################ -option(MICROHTTPD_REQUIRED "Enable or disable the requirement of microhttp (http deamon)" ON) -find_library(MHTD NAMES microhttpd) -if("${MHTD}" STREQUAL "MHTD-NOTFOUND") - if(MICROHTTPD_REQUIRED) - message(FATAL_ERROR "microhttpd NOT found: use `-DMICROHTTPD_REQUIRED=OFF` to build without http deamon support") +option(MICROHTTPD_ENABLE "Enable or disable the requirement of microhttp (http deamon)" ON) +if(MICROHTTPD_ENABLE) + find_path(MTHD_INCLUDE_DIR + NAMES + microhttpd.h + PATHS + /opt/local + /usr/local + /usr + ENV "PROGRAMFILES(X86)" + ENV "HWLOC_ROOT" + PATH_SUFFIXES + include) + + find_library(MHTD + NAMES + microhttpd + libmicrohttpd.lib + PATHS + ENV "MICROHTTPD_ROOT" + PATH_SUFFIXES + lib) + if("${MHTD}" STREQUAL "MHTD-NOTFOUND") + message(FATAL_ERROR "microhttpd NOT found: use `-DMICROHTTPD_ENABLE=OFF` to build without http deamon support") else() - message(STATUS "microhttpd NOT found: disable http server") - add_definitions("-DCONF_NO_HTTPD") + set(LIBS ${LIBS} ${MHTD}) + include_directories(AFTER ${MTHD_INCLUDE_DIR}) endif() else() - set(LIBS ${LIBS} ${MHTD}) + add_definitions("-DCONF_NO_HTTPD") endif() ############################################################################### # Find OpenSSL ############################################################################### -option(OpenSSL_REQUIRED "Enable or disable the requirement of OpenSSL" ON) -find_package(OpenSSL) -if(OPENSSL_FOUND) - include_directories(${OPENSSL_INCLUDE_DIR}) - set(LIBS ${LIBS} ${OPENSSL_LIBRARIES}) +option(OpenSSL_ENABLE "Enable or disable the requirement of OpenSSL" ON) +if(OpenSSL_ENABLE) + find_package(OpenSSL) + if(OPENSSL_FOUND) + include_directories(${OPENSSL_INCLUDE_DIR}) + set(LIBS ${LIBS} ${OPENSSL_LIBRARIES}) + else() + message(FATAL_ERROR "OpenSSL NOT found: use `-DOpenSSL_ENABLE=OFF` to build without SSL support") + endif() else() - if(OpenSSL_REQUIRED) - message(FATAL_ERROR "OpenSSL NOT found: use `-DOpenSSL_REQUIRED=OFF` to build without SSL support") + add_definitions("-DCONF_NO_TLS") +endif() + +################################################################################ +# Find hwloc +################################################################################ + +option(HWLOC_ENABLE "Enable or disable the requirement of hwloc" ON) +if(HWLOC_ENABLE) + find_path(HWLOC_INCLUDE_DIR + NAMES + hwloc.h + PATHS + /opt/local + /usr/local + /usr + ENV "PROGRAMFILES(X86)" + ENV "HWLOC_ROOT" + PATH_SUFFIXES + include) + + find_library(HWLOC + NAMES + libhwloc.lib + hwloc + PATHS + ENV "HWLOC_ROOT" + PATH_SUFFIXES + lib) + + if("${HWLOC}" STREQUAL "MHTD-NOTFOUND" OR ${HWLOC_INCLUDE_DIR} STREQUAL "HWLOC_INCLUDE_DIR-NOTFOUND") + message(FATAL_ERROR "hwloc NOT found: use `-DHWLOC_ENABLE=OFF` to build without hwloc support") else() - if(NOT OPENSSL_FOUND) - add_definitions("-DCONF_NO_TLS") - endif() + set(LIBS ${LIBS} ${HWLOC}) + include_directories(AFTER ${HWLOC_INCLUDE_DIR}) endif() +else() + add_definitions("-DCONF_NO_HWLOC") +endif() + +################################################################################ +# Windows Sockets +################################################################################ + +if(WIN32) + set(LIBS ${LIBS} wsock32 ws2_32) endif() ################################################################################ @@ -85,8 +147,10 @@ endif() ################################################################################ # activate sse2 and aes-ni -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2 -maes") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2 -maes") +if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2 -maes") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2 -maes") +endif() # activate static libgcc and libstdc++ linking if(CMAKE_LINK_STATIC) @@ -104,6 +168,7 @@ add_library(xmr-stak-c ${SRCFILES_C} ) set_property(TARGET xmr-stak-c PROPERTY C_STANDARD 99) +target_link_libraries(xmr-stak-c ${LIBS}) add_executable(xmr-stak-cpu ${SRCFILES_CPP} diff --git a/FREEBSDCOMPILE.md b/FREEBSDCOMPILE.md new file mode 100644 index 00000000..230ce73a --- /dev/null +++ b/FREEBSDCOMPILE.md @@ -0,0 +1,20 @@ +# Compile **xmr-stak** for FreeBSD + +## Install Dependencies + +*Note: This guide is tested for FreeBSD 11.0-RELEASE* + +From the root shell, run the following commands: + + pkg install git libmicrohttpd hwloc cmake + +Type 'y' and hit enter to proceed with installing the packages. + + git clone https://github.com/fireice-uk/xmr-stak-cpu.git + cd xmr-stak-cpu + cmake . + make + +Now you have the binary located at "bin/xmr-stak-cpu". Either move this file to your desired location or run "make install" to install it to your path. + +You can edit the prebuilt [config.txt](config.txt) file found in the root of the repository or you can make your own. This file is required to run xmr-stak-cpu. diff --git a/LINUXCOMPILE.md b/LINUXCOMPILE.md new file mode 100644 index 00000000..4cc19eaf --- /dev/null +++ b/LINUXCOMPILE.md @@ -0,0 +1,50 @@ +# Compile **xmr-stak** for Linux + +### GNU Compiler +``` + # Ubuntu / Debian + sudo apt install libmicrohttpd-dev libssl-dev cmake build-essential libhwloc-dev + cmake . + make install + + # Arch + sudo pacman -S base-devel hwloc openssl cmake libmicrohttpd + cmake . + make install + + # Fedora + sudo dnf install gcc gcc-c++ hwloc-devel libmicrohttpd-devel openssl-devel cmake + cmake . + make install + + # CentOS + sudo yum install centos-release-scl cmake3 hwloc-devel libmicrohttpd-devel openssl-devel + sudo yum install devtoolset-4-gcc* + sudo scl enable devtoolset-4 bash + cmake3 . + make install + + # Ubuntu 14.04 + sudo add-apt-repository ppa:ubuntu-toolchain-r/test + sudo apt update + sudo apt install gcc-5 g++-5 make + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 1 --slave /usr/bin/g++ g++ /usr/bin/g++-5 + curl -L http://www.cmake.org/files/v3.4/cmake-3.4.1.tar.gz | tar -xvzf - -C /tmp/ + cd /tmp/cmake-3.4.1/ && ./configure && make && sudo make install && cd - + sudo update-alternatives --install /usr/bin/cmake cmake /usr/local/bin/cmake 1 --force + sudo apt install libmicrohttpd-dev libssl-dev libhwloc-dev + cmake . + make install +``` + +- g++ version 5.1 or higher is required for full C++11 support. CMake release compile scripts, as well as CodeBlocks build environment for debug builds is included. + +### To do a static build for a system without gcc 5.1+ +``` + cmake -DCMAKE_LINK_STATIC=ON . + make install +``` +Note - cmake caches variables, so if you want to do a dynamic build later you need to specify '-DCMAKE_LINK_STATIC=OFF' + + + diff --git a/README.md b/README.md index 3cd3996d..07a01fbb 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,15 @@ XMR-Stak is a universal Stratum pool miner. This is the CPU-mining version; ther ## HTML reports +## HTML and JSON API report configuraton + +To configure the reports shown above you need to edit the httpd_port variable. Then enable wifi on your phone and navigate to [miner ip address]:[httpd_port] in your phone browser. If you want to use the data in scripts, you can get the JSON version of the data at url [miner ip address]:[httpd_port]/api.json + ## Usage on Windows 1) Edit the config.txt file to enter your pool login and password. 2) Double click the exe file. -XMR-Stak should compile on any C++11 compliant compiler. Windows compiler is assumed to be MSVC 2015 CE. MSVC build environment is not vendored. +XMR-Stak should compile on any C++11 compliant compiler. ``` -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 @@ -17,51 +21,35 @@ Hash: SHA256 sha1sum d34a0ba0dd7b3b1f900a7e02772e197e974b4a73 libeay32.dll 2ee9966a0fc163da58408d91be36b84fa287c10b ssleay32.dll -a03f81d7445005e0d51e3825e67cac8413df1068 xmr-stak-cpu.exe -98bb62cd1f3c7a11a18d6c2b1f1bd6bf4b5b41a3 xmr-stak-cpu-notls.exe - +e4d8a974e58985214de163df0c1ed0f54250d7ee xmr-stak-cpu.exe +ae0153ff98df82022b2c392d6a17c5f3614f6a50 xmr-stak-cpu-notls.exe sha3sum 05003137a87313c81d6c348c9b96411c95d48dc22c35f36c39129747 libeay32.dll 133c065d9ef2c93396382e2ba5d8c3ca8c6a57c6beb0159cb9a4b6c5 ssleay32.dll -9666ae2cfa337599282615275ea05f4e6240fd571c86530583ac89aa xmr-stak-cpu.exe -46f633b125907feed2f16fc97dcc8402a67218809fef226a77c0aa70 xmr-stak-cpu-notls.exe +7bfc30b06524dc9139a3157e2661d2a6f5720738dde8e490f05cc8e2 xmr-stak-cpu.exe +005fb81fc3711a97b2ce65bad0ca97318d878dc793a8cba99c7d1f6f xmr-stak-cpu-notls.exe date -Sat 29 Apr 16:59:00 BST 2017 +Wed 19 Jul 21:18:58 BST 2017 -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 -iQEcBAEBCAAGBQJZBLhQAAoJEPsk95p+1Bw0bWYH/0jtGhKqahRGaxAnLLmA9rsK -HUsvIDkAFEshdcUK2yB32JXu4vltG2sbIb/AaY3qifFawhfMPQXGPhJ1YfWlJrI6 -icqcPlvHRo88nSfpCfRA3EOjmrNSM4uXb4/FM9ongTgqBKPkSAoQjJfnhXQfOFKb -ULyN0xRRMuqPxnAggzqn5mwcJ1qPFnuUDjcBssnHw21P/p72qrMK/pMp1LeGMpGZ -+kzr7rS2wko7isJuMouddCK3rypxeIry2XfLehRqguhfXLw9Xi+HNmBCY+76bYWi -xXl2Nm/u3cPP/eQVrZz5H8eACwIv+LL1EV+9uLanWUa+IO5hHr3KElvKNKD6vN0= -=vGQV +iQEcBAEBCAAGBQJZb77XAAoJEPsk95p+1Bw0GU4H/26sBwJzYSeWoLwo0LdmOPk3 +19n+svFYnz6NlxAjs+fvuTK992ilLMy2pa4PHKhot2oyZIgt2rRaFsvRADcHVraG +nsIh4Oq31T9epZI0WxIH5FJlDx30fdGkpMTu9xt6ta2JXsmkDiCoZxmETuljB7Rw +xvnKeHiuTccp73C6Nd7dkuiemsOw0FZA7XXS/Kmwqm7n8BtCztY70R6SVN7QFbCz +C49s0A9cT4UbAUPuu8KvxFozmJHA/wDBYHgkq95Y6n/q116+Sc9BpdF8j+qK4YzZ +uM+B10XY0g7Qv376UoJRYKokpVaBxF08nD+JXLdL+zfQvnEfKgrhTnjaTkWFfEY= +=jpgE -----END PGP SIGNATURE----- ``` +## Compile guides -## Compile on Linux (Debian-based distros) - -### GNU Compiler -``` - sudo apt-get install libmicrohttpd-dev libssl-dev cmake build-essential - cmake . - make install -``` - -- GCC version 5.1 or higher is required for full C++11 support. CMake release compile scripts, as well as CodeBlocks build environment for debug builds is included. - -### To do a static build for a system without gcc 5.1+ -``` - cmake -DCMAKE_LINK_STATIC=ON . - make install -``` -Note - cmake caches variables, so if you want to do a dynamic build later you need to specify '-DCMAKE_BUILD_TYPE=RELEASE' - +- [Free BSD](FREEBSDCOMPILE.md) +- [Linux](LINUXCOMPILE.md) +- [Windows](WINCOMPILE.md) -You can find a complete compile guide under [Advanced Compile Options](#advanced-compile-options). #### CPU mining performance @@ -73,7 +61,7 @@ Performance is nearly identical to the closed source paid miners. Here are some * **Dual E5640** - 365 H/s (same as above) ## Default dev donation -By default the miner will donate 1% of the hashpower (1 minute in 100 minutes) to my pool. If you want to change that, edit **donate-level.h** before you build the binaries. +By default the miner will donate 2% of the hashpower (2 minute in 100 minutes) to my pool. If you want to change that, edit **donate-level.h** before you build the binaries. If you want to donate directly to support further development, here is my wallet @@ -115,7 +103,7 @@ If that happens, disable all auto-staring applications and run the miner after a **msvcp140.dll and vcruntime140.dll not available errors** -Download and install this [runtime package](https://www.microsoft.com/en-us/download/details.aspx?id=48145) from Microsoft. *Warning: Do NOT use "missing dll" sites - dll's are exe files with another name, and it is a fairly safe bet that any dll on a shady site like that will be trojaned. Please download offical runtimes from Microsoft above.* +Download and install this [runtime package](https://go.microsoft.com/fwlink/?LinkId=746572) from Microsoft. *Warning: Do NOT use "missing dll" sites - dll's are exe files with another name, and it is a fairly safe bet that any dll on a shady site like that will be trojaned. Please download offical runtimes from Microsoft above.* **Error: MEMORY ALLOC FAILED: mmap failed** @@ -168,12 +156,15 @@ and install. -`CMAKE_BUILD_TYPE` set the build type - valid options: `Release` or `Debug` - you should always keep `Release` for your productive miners -- `MICROHTTPD_REQUIRED` allow to disable/enable the dependency *microhttpd* +- `MICROHTTPD_ENABLE` allow to disable/enable the dependency *microhttpd* + - by default enabled + - there is no *http* interface available if option is disabled: `cmake . -DMICROHTTPD_ENABLE=OFF` +- `OpenSSL_ENABLE` allow to disable/enable the dependency *OpenSSL* - by default enabled - - there is no *http* interface available if option is disabled: `cmake . -DMICROHTTPD_REQUIRED=OFF` -- `OpenSSL_REQUIRED`allow to disable/enable the dependency *OpenSSL* + - it is not possible to connect to a *https* secured pool if option is disabled: `cmake . -DOpenSSL_ENABLE=OFF` +- `HWLOC_ENABLE` allow to disable/enable the dependency *hwloc* - by default enabled - - it is not possible to connect to a *https* secured pool if optin is disabled: `cmake . -DOpenSSL_REQUIRED=OFF` + - the config suggestion is not optimal if option is disabled: `cmake . -DHWLOC_ENABLE=OFF` ## PGP Key ``` diff --git a/WINCOMPILE.md b/WINCOMPILE.md new file mode 100644 index 00000000..603ce5ce --- /dev/null +++ b/WINCOMPILE.md @@ -0,0 +1,155 @@ +# Compile **xmr-stak** for Windows + +## Install Dependencies + +### Preparation + +- open a command line `cmd` +- run `mkdir C:\xmr-stak-dep` + +### Visual Studio 2017 Community + +- download VS2017 Community and install from [https://www.visualstudio.com/downloads/](https://www.visualstudio.com/downloads/) +- during the install chose the components + - `Desktop development with C++` (left side) + - `Toolset for Visual Studio C++ 2015.3 v140...` (right side) + +### CMake for Win64 + +- download and install the latest version from [https://cmake.org/download/](https://cmake.org/download/) +- tested version: [cmake 3.9](https://cmake.org/files/v3.9/cmake-3.9.0-rc3-win64-x64.msi) +- during the install choose the option `Add CMake to the system PATH for all users` + +### OpenSSL for Win64 + +- download and install the precompiled binary form [https://slproweb.com/products/Win32OpenSSL.html](https://slproweb.com/products/Win32OpenSSL.html) +- tested version: [OpenSSL 1.0.2L](https://slproweb.com/download/Win64OpenSSL-1_0_2L.exe) + +### Hwloc for Win64 + +- download the precompiled binary from [https://www.open-mpi.org/software/hwloc/v1.11/](https://www.open-mpi.org/software/hwloc/v1.11/) +- tested version: [hwloc-win64-build-1.11.7](https://www.open-mpi.org/software/hwloc/v1.11/downloads/hwloc-win64-build-1.11.7.zip) +- unzip hwloc to `C:\xmr-stak-dep` + +### Microhttpd for Win32 + +- download the precompiled binary from [http://ftpmirror.gnu.org/libmicrohttpd/](http://ftpmirror.gnu.org/libmicrohttpd/) +- tested version: [libmicrohttpd-0.9.55-w32-bin](http://mirror.reismil.ch/gnu/libmicrohttpd/libmicrohttpd-0.9.55-w32-bin.zip) +- unzip microhttpd to ``C:\xmr-stak-dep` + +### Validate the Dependency Folder + +- open a command line `cmd` +- run + ``` + cd c:\xmr-stak-dep + tree . + ``` +- the result should have the same structure + ``` + C:\XMR-STAK-DEP + ├───hwloc-win64-build-1.11.7 + │ ├───bin + │ ├───include + │ │ └───hwloc + │ │ └───autogen + │ ├───lib + │ │ └───pkgconfig + │ └───share + │ ├───doc + │ │ └───hwloc + │ ├───hwloc + │ └───man + │ ├───man1 + │ ├───man3 + │ └───man7 + └───libmicrohttpd-0.9.55-w32-bin + ├───x86 + │ ├───MinGW + │ │ ├───shared + │ │ │ └───mingw32 + │ │ │ ├───bin + │ │ │ ├───include + │ │ │ └───lib + │ │ │ └───pkgconfig + │ │ ├───shared-xp + │ │ │ └───mingw32 + │ │ │ ├───bin + │ │ │ ├───include + │ │ │ └───lib + │ │ │ └───pkgconfig + │ │ ├───static + │ │ │ └───mingw32 + │ │ │ ├───include + │ │ │ └───lib + │ │ │ └───pkgconfig + │ │ └───static-xp + │ │ └───mingw32 + │ │ ├───include + │ │ └───lib + │ │ └───pkgconfig + │ ├───VS2013 + │ │ ├───Release-dll + │ │ ├───Release-dll-xp + │ │ ├───Release-static + │ │ └───Release-static-xp + │ ├───VS2015 + │ │ ├───Debug-dll + │ │ ├───Debug-dll-xp + │ │ ├───Debug-static + │ │ ├───Debug-static-xp + │ │ ├───Release-dll + │ │ ├───Release-dll-xp + │ │ ├───Release-static + │ │ └───Release-static-xp + │ └───VS2017 + │ ├───Debug-dll + │ ├───Debug-static + │ ├───Release-dll + │ └───Release-static + └───x86_64 + ├───MinGW + │ ├───shared + │ │ └───mingw64 + │ │ ├───bin + │ │ ├───include + │ │ └───lib + │ │ └───pkgconfig + │ └───static + │ └───mingw64 + │ ├───include + │ └───lib + │ └───pkgconfig + ├───VS2013 + │ ├───Release-dll + │ └───Release-static + ├───VS2015 + │ ├───Debug-dll + │ ├───Debug-static + │ ├───Release-dll + │ └───Release-static + └───VS2017 + ├───Debug-dll + ├───Debug-static + ├───Release-dll + └───Release-static + ``` + +## Compile + +- download and unzip `xmr-stak-cpu` +- open a command line `cmd` +- `cd` to your unzipped source code directory +- execute the following commands (NOTE: path to VS2017 can be different) + ``` + "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsMSBuildCmd.bat" + set CMAKE_PREFIX_PATH=C:\xmr-stak-dep\hwloc-win64-build-1.11.7;C:\xmr-stak-dep\libmicrohttpd-0.9.55-w32-bin\x86_64\VS2017\Release-static + mkdir build + cd build + cmake -G "Visual Studio 15 2017 Win64" -T v141,host=x64 .. + msbuild xmr-stak-cpu.sln /p:Configuration=Release + cd bin\Release + copy C:\xmr-stak-dep\hwloc-win64-build-1.11.7\bin\libhwloc-5.dll . + copy ..\..\..\config.txt . + ``` +- customize your `config.txt` file by adding the pool, username and password diff --git a/autoAdjust.hpp b/autoAdjust.hpp index c9ee9e6c..93a88e88 100644 --- a/autoAdjust.hpp +++ b/autoAdjust.hpp @@ -38,10 +38,10 @@ class autoAdjust printer::inst()->print_msg(L0, "Autoconf failed: L3 size sanity check failed - %u KB.", L3KB_size); printer::inst()->print_msg(L0, "Autoconf failed: Printing config for a single thread. Please try to add new ones until the hashrate slows down."); - printer::inst()->print_str("\n**************** Copy&Paste ****************\n\n"); + printer::inst()->print_str("\n**************** Copy&Paste BEGIN ****************\n\n"); printer::inst()->print_str("\"cpu_threads_conf\" :\n[\n"); printer::inst()->print_str(" { \"low_power_mode\" : false, \"no_prefetch\" : true, \"affine_to_cpu\" : false },\n"); - printer::inst()->print_str("],\n\n**************** Copy&Paste ****************\n"); + printer::inst()->print_str("],\n\n**************** Copy&Paste END ****************\n"); return; } @@ -52,7 +52,7 @@ class autoAdjust printer::inst()->print_msg(L0, "Autoconf core count detected as %u on %s.", corecnt, linux_layout ? "Linux" : "Windows"); - printer::inst()->print_str("\n**************** Copy&Paste ****************\n\n"); + printer::inst()->print_str("\n**************** Copy&Paste BEGIN ****************\n\n"); printer::inst()->print_str("\"cpu_threads_conf\" :\n[\n"); uint32_t aff_id = 0; @@ -86,7 +86,7 @@ class autoAdjust L3KB_size -= 2048; } - printer::inst()->print_str("],\n\n**************** Copy&Paste ****************\n"); + printer::inst()->print_str("],\n\n**************** Copy&Paste END ****************\n"); } private: diff --git a/autoAdjustHwloc.hpp b/autoAdjustHwloc.hpp new file mode 100644 index 00000000..92a668a5 --- /dev/null +++ b/autoAdjustHwloc.hpp @@ -0,0 +1,195 @@ +#pragma once + +#include "console.h" +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif // _WIN32 + +class autoAdjust +{ +public: + + autoAdjust() + { + } + + void printConfig() + { + printer::inst()->print_str("The configuration for 'cpu_threads_conf' in your config file is 'null'.\n"); + printer::inst()->print_str("The miner evaluates your system and prints a suggestion for the section `cpu_threads_conf` to the terminal.\n"); + printer::inst()->print_str("The values are not optimal, please try to tweak the values based on notes in config.txt.\n"); + printer::inst()->print_str("Please copy & paste the block within the asterisks to your config.\n\n"); + + hwloc_topology_t topology; + hwloc_topology_init(&topology); + hwloc_topology_load(topology); + + try + { + std::vector tlcs; + tlcs.reserve(16); + results.reserve(16); + + findChildrenCaches(hwloc_get_root_obj(topology), + [&tlcs](hwloc_obj_t found) { tlcs.emplace_back(found); } ); + + if(tlcs.size() == 0) + throw(std::runtime_error("The CPU doesn't seem to have a cache.")); + + for(hwloc_obj_t obj : tlcs) + proccessTopLevelCache(obj); + + printer::inst()->print_str("\n**************** Copy&Paste BEGIN ****************\n\n"); + printer::inst()->print_str("\"cpu_threads_conf\" :\n[\n"); + + for(uint32_t id : results) + { + char str[128]; + snprintf(str, sizeof(str), " { \"low_power_mode\" : %s, \"no_prefetch\" : true, \"affine_to_cpu\" : %u },\n", + (id & 0x8000000) != 0 ? "true" : "false", id & 0x7FFFFFF); + printer::inst()->print_str(str); + } + + printer::inst()->print_str("],\n\n**************** Copy&Paste END ****************\n"); + } + catch(const std::runtime_error& err) + { + printer::inst()->print_msg(L0, "Autoconf FAILED: %s", err.what()); + printer::inst()->print_str("\nPrinting config for a single thread. Please try to add new ones until the hashrate slows down.\n"); + printer::inst()->print_str("\n**************** FAILURE Copy&Paste BEGIN ****************\n\n"); + printer::inst()->print_str("\"cpu_threads_conf\" :\n[\n"); + printer::inst()->print_str(" { \"low_power_mode\" : false, \"no_prefetch\" : true, \"affine_to_cpu\" : false },\n"); + printer::inst()->print_str("],\n\n**************** FAILURE Copy&Paste END ****************\n"); + } + + /* Destroy topology object. */ + hwloc_topology_destroy(topology); + } + +private: + static constexpr size_t hashSize = 2 * 1024 * 1024; + std::vector results; + + template + inline void findChildrenByType(hwloc_obj_t obj, hwloc_obj_type_t type, func lambda) + { + for(size_t i=0; i < obj->arity; i++) + { + if(obj->children[i]->type == type) + lambda(obj->children[i]); + else + findChildrenByType(obj->children[i], type, lambda); + } + } + + inline bool isCacheObject(hwloc_obj_t obj) + { +#if HWLOC_API_VERSION >= 0x20000 + return hwloc_obj_type_is_cache(obj->type); +#else + return obj->type == HWLOC_OBJ_CACHE; +#endif // HWLOC_API_VERSION + } + + template + inline void findChildrenCaches(hwloc_obj_t obj, func lambda) + { + for(size_t i=0; i < obj->arity; i++) + { + if(isCacheObject(obj->children[i])) + lambda(obj->children[i]); + else + findChildrenCaches(obj->children[i], lambda); + } + } + + inline bool isCacheExclusive(hwloc_obj_t obj) + { + const char* value = hwloc_obj_get_info_by_name(obj, "Inclusive"); + return value == nullptr || value[0] != '1'; + } + + // Top level cache isn't shared with other cores on the same package + // This will usually be 1 x L3, but can be 2 x L2 per package + void proccessTopLevelCache(hwloc_obj_t obj) + { + if(obj->attr == nullptr) + throw(std::runtime_error("Cache object hasn't got attributes.")); + + size_t PUs = 0; + findChildrenByType(obj, HWLOC_OBJ_PU, [&PUs](hwloc_obj_t found) { PUs++; } ); + + //Strange case, but we will handle it silently, surely there must be one PU somewhere? + if(PUs == 0) + return; + + if(obj->attr->cache.size == 0) + { + //We will always have one child if PUs > 0 + if(!isCacheObject(obj->children[0])) + throw(std::runtime_error("The CPU doesn't seem to have a cache.")); + + //Try our luck with lower level caches + for(size_t i=0; i < obj->arity; i++) + proccessTopLevelCache(obj->children[i]); + return; + } + + size_t cacheSize = obj->attr->cache.size; + if(isCacheExclusive(obj)) + { + for(size_t i=0; i < obj->arity; i++) + { + hwloc_obj_t l2obj = obj->children[i]; + //If L2 is exclusive and greater or equal to 2MB add room for one more hash + if(isCacheObject(l2obj) && l2obj->attr != nullptr && l2obj->attr->cache.size >= hashSize) + cacheSize += hashSize; + } + } + + std::vector cores; + cores.reserve(16); + findChildrenByType(obj, HWLOC_OBJ_CORE, [&cores](hwloc_obj_t found) { cores.emplace_back(found); } ); + + size_t cacheHashes = (cacheSize + hashSize/2) / hashSize; + + //Firstly allocate PU 0 of every CORE, then PU 1 etc. + size_t pu_id = 0; + while(cacheHashes > 0 && PUs > 0) + { + bool allocated_pu = false; + for(hwloc_obj_t core : cores) + { + if(core->arity <= pu_id || core->children[pu_id]->type != HWLOC_OBJ_PU) + continue; + + size_t os_id = core->children[pu_id]->os_index; + + if(cacheHashes > PUs) + { + cacheHashes -= 2; + os_id |= 0x8000000; //double hash marker bit + } + else + cacheHashes--; + PUs--; + + allocated_pu = true; + results.emplace_back(os_id); + + if(cacheHashes == 0) + break; + } + + if(!allocated_pu) + throw(std::runtime_error("Failed to allocate a PU.")); + + pu_id++; + } + } +}; diff --git a/cli-miner.cpp b/cli-miner.cpp index 38fb7201..45d2c163 100644 --- a/cli-miner.cpp +++ b/cli-miner.cpp @@ -26,7 +26,12 @@ #include "jconf.h" #include "console.h" #include "donate-level.h" -#include "autoAdjust.hpp" +#ifndef CONF_NO_HWLOC +# include "autoAdjustHwloc.hpp" +#else +# include "autoAdjust.hpp" +#endif +#include "version.h" #ifndef CONF_NO_HTTPD # include "httpd.h" @@ -36,6 +41,8 @@ #include #include +#include + #ifndef CONF_NO_TLS #include #include @@ -69,6 +76,8 @@ int main(int argc, char *argv[]) OpenSSL_add_all_digests(); #endif + srand(time(0)); + const char* sFilename = "config.txt"; bool benchmark_mode = false; @@ -133,7 +142,7 @@ int main(int argc, char *argv[]) #endif printer::inst()->print_str("-------------------------------------------------------------------\n"); - printer::inst()->print_str("XMR-Stak-CPU mining software, CPU Version.\n"); + printer::inst()->print_str( XMR_STAK_NAME" " XMR_STAK_VERSION " mining software, CPU Version.\n"); printer::inst()->print_str("Based on CPU mining code by wolf9466 (heavily optimized by fireice_uk).\n"); printer::inst()->print_str("Brought to you by fireice_uk and psychocrypt under GPLv3.\n\n"); char buffer[64]; @@ -148,7 +157,10 @@ int main(int argc, char *argv[]) if(strlen(jconf::inst()->GetOutputFile()) != 0) printer::inst()->open_logfile(jconf::inst()->GetOutputFile()); - executor::inst()->ex_start(); + executor::inst()->ex_start(jconf::inst()->DaemonMode()); + + using namespace std::chrono; + uint64_t lastTime = time_point_cast(high_resolution_clock::now()).time_since_epoch().count(); int key; while(true) @@ -169,6 +181,13 @@ int main(int argc, char *argv[]) default: break; } + + uint64_t currentTime = time_point_cast(high_resolution_clock::now()).time_since_epoch().count(); + + /* Hard guard to make sure we never get called more than twice per second */ + if( currentTime - lastTime < 500) + std::this_thread::sleep_for(std::chrono::milliseconds(500 - (currentTime - lastTime))); + lastTime = currentTime; } return 0; diff --git a/config.txt b/config.txt index 0dcb9e92..22a857ea 100644 --- a/config.txt +++ b/config.txt @@ -76,6 +76,16 @@ null, */ "nicehash_nonce" : false, +/* + * Manual hardware AES override + * + * Some VMs don't report AES capability correctly. You can set this value to true to enforce hardware AES or + * to false to force disable AES or null to let the miner decide if AES is used. + * + * WARNING: setting this to true on a CPU that doesn't support hardware AES will crash the miner. + */ +"aes_override" : null, + /* * TLS Settings * If you need real security, make sure tls_secure_algo is enabled (otherwise MITM attack can downgrade encryption @@ -93,8 +103,10 @@ null, * pool_address - Pool address should be in the form "pool.supportxmr.com:3333". Only stratum pools are supported. * wallet_address - Your wallet, or pool login. * pool_password - Can be empty in most cases or "x". + * + * We feature pools up to 1MH/s. For a more complete list see M5M400's pool list at www.moneropools.com */ -"pool_address" : "pool.supportxmr.com:3333", +"pool_address" : "pool.usxmrpool.com:3333", "wallet_address" : "", "pool_password" : "", @@ -139,6 +151,14 @@ null, */ "h_print_time" : 60, +/* + * Daemon mode + * + * If you are running the process in the background and you don't need the keyboard reports, set this to true. + * This should solve the hashrate problems on some emulated terminals. + */ +"daemon_mode" : false, + /* * Output file * diff --git a/crypto/c_keccak.c b/crypto/c_keccak.c index e11ca474..eadb85b7 100644 --- a/crypto/c_keccak.c +++ b/crypto/c_keccak.c @@ -24,18 +24,6 @@ const uint64_t keccakf_rndc[24] = 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 }; -const int keccakf_rotc[24] = -{ - 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, - 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 -}; - -const int keccakf_piln[24] = -{ - 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, - 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 -}; - // update the state with given number of rounds void keccakf(uint64_t st[25], int rounds) @@ -63,26 +51,86 @@ void keccakf(uint64_t st[25], int rounds) // Rho Pi t = st[1]; - for (i = 0; i < 24; ++i) { - bc[0] = st[keccakf_piln[i]]; - st[keccakf_piln[i]] = ROTL64(t, keccakf_rotc[i]); - t = bc[0]; - } + st[ 1] = ROTL64(st[ 6], 44); + st[ 6] = ROTL64(st[ 9], 20); + st[ 9] = ROTL64(st[22], 61); + st[22] = ROTL64(st[14], 39); + st[14] = ROTL64(st[20], 18); + st[20] = ROTL64(st[ 2], 62); + st[ 2] = ROTL64(st[12], 43); + st[12] = ROTL64(st[13], 25); + st[13] = ROTL64(st[19], 8); + st[19] = ROTL64(st[23], 56); + st[23] = ROTL64(st[15], 41); + st[15] = ROTL64(st[ 4], 27); + st[ 4] = ROTL64(st[24], 14); + st[24] = ROTL64(st[21], 2); + st[21] = ROTL64(st[ 8], 55); + st[ 8] = ROTL64(st[16], 45); + st[16] = ROTL64(st[ 5], 36); + st[ 5] = ROTL64(st[ 3], 28); + st[ 3] = ROTL64(st[18], 21); + st[18] = ROTL64(st[17], 15); + st[17] = ROTL64(st[11], 10); + st[11] = ROTL64(st[ 7], 6); + st[ 7] = ROTL64(st[10], 3); + st[10] = ROTL64(t, 1); // Chi - for (j = 0; j < 25; j += 5) { - bc[0] = st[j ]; - bc[1] = st[j + 1]; - bc[2] = st[j + 2]; - bc[3] = st[j + 3]; - bc[4] = st[j + 4]; - st[j ] ^= (~bc[1]) & bc[2]; - st[j + 1] ^= (~bc[2]) & bc[3]; - st[j + 2] ^= (~bc[3]) & bc[4]; - st[j + 3] ^= (~bc[4]) & bc[0]; - st[j + 4] ^= (~bc[0]) & bc[1]; - } - + // unrolled loop, where only last iteration is different + j = 0; + bc[0] = st[j ]; + bc[1] = st[j + 1]; + + st[j ] ^= (~st[j + 1]) & st[j + 2]; + st[j + 1] ^= (~st[j + 2]) & st[j + 3]; + st[j + 2] ^= (~st[j + 3]) & st[j + 4]; + st[j + 3] ^= (~st[j + 4]) & bc[0]; + st[j + 4] ^= (~bc[0]) & bc[1]; + + j = 5; + bc[0] = st[j ]; + bc[1] = st[j + 1]; + + st[j ] ^= (~st[j + 1]) & st[j + 2]; + st[j + 1] ^= (~st[j + 2]) & st[j + 3]; + st[j + 2] ^= (~st[j + 3]) & st[j + 4]; + st[j + 3] ^= (~st[j + 4]) & bc[0]; + st[j + 4] ^= (~bc[0]) & bc[1]; + + j = 10; + bc[0] = st[j ]; + bc[1] = st[j + 1]; + + st[j ] ^= (~st[j + 1]) & st[j + 2]; + st[j + 1] ^= (~st[j + 2]) & st[j + 3]; + st[j + 2] ^= (~st[j + 3]) & st[j + 4]; + st[j + 3] ^= (~st[j + 4]) & bc[0]; + st[j + 4] ^= (~bc[0]) & bc[1]; + + j = 15; + bc[0] = st[j ]; + bc[1] = st[j + 1]; + + st[j ] ^= (~st[j + 1]) & st[j + 2]; + st[j + 1] ^= (~st[j + 2]) & st[j + 3]; + st[j + 2] ^= (~st[j + 3]) & st[j + 4]; + st[j + 3] ^= (~st[j + 4]) & bc[0]; + st[j + 4] ^= (~bc[0]) & bc[1]; + + j = 20; + bc[0] = st[j ]; + bc[1] = st[j + 1]; + bc[2] = st[j + 2]; + bc[3] = st[j + 3]; + bc[4] = st[j + 4]; + + st[j ] ^= (~bc[1]) & bc[2]; + st[j + 1] ^= (~bc[2]) & bc[3]; + st[j + 2] ^= (~bc[3]) & bc[4]; + st[j + 3] ^= (~bc[4]) & bc[0]; + st[j + 4] ^= (~bc[0]) & bc[1]; + // Iota st[0] ^= keccakf_rndc[round]; } diff --git a/crypto/cryptonight_aesni.h b/crypto/cryptonight_aesni.h index 6d8479ce..8bbb27ce 100644 --- a/crypto/cryptonight_aesni.h +++ b/crypto/cryptonight_aesni.h @@ -368,9 +368,11 @@ void cryptonight_double_hash(const void* input, size_t len, void* output, crypto uint8_t* l1 = ctx1->long_state; uint64_t* h1 = (uint64_t*)ctx1->hash_state; - __m128i ax0 = _mm_set_epi64x(h0[1] ^ h0[5], h0[0] ^ h0[4]); + uint64_t axl0 = h0[0] ^ h0[4]; + uint64_t axh0 = h0[1] ^ h0[5]; __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]); - __m128i ax1 = _mm_set_epi64x(h1[1] ^ h1[5], h1[0] ^ h1[4]); + uint64_t axl1 = h1[0] ^ h1[4]; + uint64_t axh1 = h1[1] ^ h1[5]; __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]); uint64_t idx0 = h0[0] ^ h0[4]; @@ -383,9 +385,9 @@ void cryptonight_double_hash(const void* input, size_t len, void* output, crypto cx = _mm_load_si128((__m128i *)&l0[idx0 & 0x1FFFF0]); if(SOFT_AES) - cx = soft_aesenc(cx, ax0); + cx = soft_aesenc(cx, _mm_set_epi64x(axh0, axl0)); else - cx = _mm_aesenc_si128(cx, ax0); + cx = _mm_aesenc_si128(cx, _mm_set_epi64x(axh0, axl0)); _mm_store_si128((__m128i *)&l0[idx0 & 0x1FFFF0], _mm_xor_si128(bx0, cx)); idx0 = _mm_cvtsi128_si64(cx); @@ -397,9 +399,9 @@ void cryptonight_double_hash(const void* input, size_t len, void* output, crypto cx = _mm_load_si128((__m128i *)&l1[idx1 & 0x1FFFF0]); if(SOFT_AES) - cx = soft_aesenc(cx, ax1); + cx = soft_aesenc(cx, _mm_set_epi64x(axh1, axl1)); else - cx = _mm_aesenc_si128(cx, ax1); + cx = _mm_aesenc_si128(cx, _mm_set_epi64x(axh1, axl1)); _mm_store_si128((__m128i *)&l1[idx1 & 0x1FFFF0], _mm_xor_si128(bx1, cx)); idx1 = _mm_cvtsi128_si64(cx); @@ -408,27 +410,35 @@ void cryptonight_double_hash(const void* input, size_t len, void* output, crypto if(PREFETCH) _mm_prefetch((const char*)&l1[idx1 & 0x1FFFF0], _MM_HINT_T0); - uint64_t hi, lo; - cx = _mm_load_si128((__m128i *)&l0[idx0 & 0x1FFFF0]); + uint64_t hi, lo, cl, ch; + cl = ((uint64_t*)&l0[idx0 & 0x1FFFF0])[0]; + ch = ((uint64_t*)&l0[idx0 & 0x1FFFF0])[1]; - lo = _umul128(idx0, _mm_cvtsi128_si64(cx), &hi); + lo = _umul128(idx0, cl, &hi); - ax0 = _mm_add_epi64(ax0, _mm_set_epi64x(lo, hi)); - _mm_store_si128((__m128i*)&l0[idx0 & 0x1FFFF0], ax0); - ax0 = _mm_xor_si128(ax0, cx); - idx0 = _mm_cvtsi128_si64(ax0); + axl0 += hi; + axh0 += lo; + ((uint64_t*)&l0[idx0 & 0x1FFFF0])[0] = axl0; + ((uint64_t*)&l0[idx0 & 0x1FFFF0])[1] = axh0; + axh0 ^= ch; + axl0 ^= cl; + idx0 = axl0; if(PREFETCH) _mm_prefetch((const char*)&l0[idx0 & 0x1FFFF0], _MM_HINT_T0); - cx = _mm_load_si128((__m128i *)&l1[idx1 & 0x1FFFF0]); + cl = ((uint64_t*)&l1[idx1 & 0x1FFFF0])[0]; + ch = ((uint64_t*)&l1[idx1 & 0x1FFFF0])[1]; - lo = _umul128(idx1, _mm_cvtsi128_si64(cx), &hi); + lo = _umul128(idx1, cl, &hi); - ax1 = _mm_add_epi64(ax1, _mm_set_epi64x(lo, hi)); - _mm_store_si128((__m128i*)&l1[idx1 & 0x1FFFF0], ax1); - ax1 = _mm_xor_si128(ax1, cx); - idx1 = _mm_cvtsi128_si64(ax1); + axl1 += hi; + axh1 += lo; + ((uint64_t*)&l1[idx1 & 0x1FFFF0])[0] = axl1; + ((uint64_t*)&l1[idx1 & 0x1FFFF0])[1] = axh1; + axh1 ^= ch; + axl1 ^= cl; + idx1 = axl1; if(PREFETCH) _mm_prefetch((const char*)&l1[idx1 & 0x1FFFF0], _MM_HINT_T0); diff --git a/crypto/cryptonight_common.cpp b/crypto/cryptonight_common.cpp index 63ce3a4e..9d03ed7d 100644 --- a/crypto/cryptonight_common.cpp +++ b/crypto/cryptonight_common.cpp @@ -146,6 +146,9 @@ cryptonight_ctx* cryptonight_alloc_ctx(size_t use_fast_mem, size_t use_mlock, al #if defined(__APPLE__) ptr->long_state = (uint8_t*)mmap(0, MEMORY, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0); +#elif defined(__FreeBSD__) + ptr->long_state = (uint8_t*)mmap(0, MEMORY, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER | MAP_PREFAULT_READ, -1, 0); #else ptr->long_state = (uint8_t*)mmap(0, MEMORY, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, 0, 0); diff --git a/donate-level.h b/donate-level.h index ccae28f9..71b79628 100644 --- a/donate-level.h +++ b/donate-level.h @@ -3,13 +3,16 @@ /* * Dev donation. * Percentage of your hashing power that you want to donate to the developer, can be 0.0 if you don't want to do that. - * Example of how it works for the default setting of 1.0: - * You miner will mine into your usual pool for 99 minutes, then switch to the developer's pool for 1.0 minute. + * Example of how it works for the default setting of 2.0: + * You miner will mine into your usual pool for 98 minutes, then switch to the developer's pool for 2.0 minute. * Switching is instant, and only happens after a successful connection, so you never loose any hashes. * - * If you plan on changing this setting to 0.0 please consider making a one off donation to my wallet: + * If you plan on changing this setting to 0.0 please consider making a one off donation to our wallets: + * fireice-uk: * 4581HhZkQHgZrZjKeCfCJxZff9E3xCgHGF25zABZz7oR71TnbbgiS7sK9jveE6Dx6uMs2LwszDuvQJgRZQotdpHt1fTdDhk + * psychocrypt: + * 43NoJVEXo21hGZ6tDG6Z3g4qimiGdJPE6GRxAmiWwm26gwr62Lqo7zRiCJFSBmbkwTGNuuES9ES5TgaVHceuYc4Y75txCTU * */ -constexpr double fDevDonationLevel = 1.0 / 100.0; +constexpr double fDevDonationLevel = 2.0 / 100.0; diff --git a/executor.cpp b/executor.cpp index af108111..948b156d 100644 --- a/executor.cpp +++ b/executor.cpp @@ -43,7 +43,6 @@ executor* executor::oInst = NULL; executor::executor() { - my_thd = nullptr; } void executor::push_timed_event(ex_event&& ev, size_t sec) @@ -461,6 +460,7 @@ void executor::ex_main() case EV_HTML_HASHRATE: case EV_HTML_RESULTS: case EV_HTML_CONNSTAT: + case EV_HTML_JSON: http_report(ev.iName); break; @@ -826,6 +826,121 @@ void executor::http_connection_report(std::string& out) out.append(sHtmlConnectionBodyLow); } +inline const char* hps_format_json(double h, char* buf, size_t l) +{ + if(std::isnormal(h) || h == 0.0) + { + snprintf(buf, l, "%.1f", h); + return buf; + } + else + return "null"; +} + +void executor::http_json_report(std::string& out) +{ + const char *a, *b, *c; + char num_a[32], num_b[32], num_c[32]; + char hr_buffer[64]; + std::string hr_thds, res_error, cn_error; + + size_t nthd = pvThreads->size(); + double fTotal[3] = { 0.0, 0.0, 0.0}; + hr_thds.reserve(nthd * 32); + + for(size_t i=0; i < nthd; i++) + { + if(i != 0) hr_thds.append(1, ','); + + double fHps[3]; + fHps[0] = telem->calc_telemetry_data(2500, i); + fHps[1] = telem->calc_telemetry_data(60000, i); + fHps[2] = telem->calc_telemetry_data(900000, i); + + fTotal[0] += fHps[0]; + fTotal[1] += fHps[1]; + fTotal[2] += fHps[2]; + + a = hps_format_json(fHps[0], num_a, sizeof(num_a)); + b = hps_format_json(fHps[1], num_b, sizeof(num_b)); + c = hps_format_json(fHps[2], num_c, sizeof(num_c)); + snprintf(hr_buffer, sizeof(hr_buffer), sJsonApiThdHashrate, a, b, c); + hr_thds.append(hr_buffer); + } + + a = hps_format_json(fTotal[0], num_a, sizeof(num_a)); + b = hps_format_json(fTotal[1], num_b, sizeof(num_b)); + c = hps_format_json(fTotal[2], num_c, sizeof(num_c)); + snprintf(hr_buffer, sizeof(hr_buffer), sJsonApiThdHashrate, a, b, c); + + a = hps_format_json(fHighestHps, num_a, sizeof(num_a)); + + size_t iGoodRes = vMineResults[0].count, iTotalRes = iGoodRes; + size_t ln = vMineResults.size(); + + for(size_t i=1; i < ln; i++) + iTotalRes += vMineResults[i].count; + + jpsock* pool = pick_pool_by_id(dev_pool_id + 1); + + size_t iConnSec = 0; + if(pool->is_running() && pool->is_logged_in()) + { + using namespace std::chrono; + iConnSec = duration_cast(system_clock::now() - tPoolConnTime).count(); + } + + double fAvgResTime = 0.0; + if(iPoolCallTimes.size() > 0) + fAvgResTime = double(iConnSec) / iPoolCallTimes.size(); + + res_error.reserve((vMineResults.size() - 1) * 128); + char buffer[256]; + for(size_t i=1; i < vMineResults.size(); i++) + { + using namespace std::chrono; + if(i != 1) res_error.append(1, ','); + + snprintf(buffer, sizeof(buffer), sJsonApiResultError, int_port(vMineResults[i].count), + int_port(duration_cast(vMineResults[i].time.time_since_epoch()).count()), + vMineResults[i].msg.c_str()); + res_error.append(buffer); + } + + size_t n_calls = iPoolCallTimes.size(); + size_t iPoolPing = 0; + if (n_calls > 1) + { + //Not-really-but-good-enough median + std::nth_element(iPoolCallTimes.begin(), iPoolCallTimes.begin() + n_calls/2, iPoolCallTimes.end()); + iPoolPing = iPoolCallTimes[n_calls/2]; + } + + cn_error.reserve(vSocketLog.size() * 128); + for(size_t i=0; i < vSocketLog.size(); i++) + { + using namespace std::chrono; + if(i != 0) cn_error.append(1, ','); + + snprintf(buffer, sizeof(buffer), sJsonApiConnectionError, + int_port(duration_cast(vMineResults[i].time.time_since_epoch()).count()), + vSocketLog[i].msg.c_str()); + cn_error.append(buffer); + } + + size_t bb_size = 1024 + hr_thds.size() + res_error.size() + cn_error.size(); + std::unique_ptr bigbuf( new char[ bb_size ] ); + + int bb_len = snprintf(bigbuf.get(), bb_size, sJsonApiFormat, + hr_thds.c_str(), hr_buffer, a, + int_port(iPoolDiff), int_port(iGoodRes), int_port(iTotalRes), fAvgResTime, int_port(iPoolHashes), + int_port(iTopDiff[0]), int_port(iTopDiff[1]), int_port(iTopDiff[2]), int_port(iTopDiff[3]), int_port(iTopDiff[4]), + int_port(iTopDiff[5]), int_port(iTopDiff[6]), int_port(iTopDiff[7]), int_port(iTopDiff[8]), int_port(iTopDiff[9]), + res_error.c_str(), jconf::inst()->GetPoolAddress(), int_port(iConnSec), int_port(iPoolPing), cn_error.c_str()); + + out = std::string(bigbuf.get(), bigbuf.get() + bb_len); +} + void executor::http_report(ex_event_name ev) { assert(pHttpString != nullptr); @@ -843,6 +958,11 @@ void executor::http_report(ex_event_name ev) case EV_HTML_CONNSTAT: http_connection_report(*pHttpString); break; + + case EV_HTML_JSON: + http_json_report(*pHttpString); + break; + default: assert(false); break; @@ -856,7 +976,8 @@ void executor::get_http_report(ex_event_name ev_id, std::string& data) std::lock_guard lck(httpMutex); assert(pHttpString == nullptr); - assert(ev_id == EV_HTML_HASHRATE || ev_id == EV_HTML_RESULTS || ev_id == EV_HTML_CONNSTAT); + assert(ev_id == EV_HTML_HASHRATE || ev_id == EV_HTML_RESULTS + || ev_id == EV_HTML_CONNSTAT || ev_id == EV_HTML_JSON); pHttpString = &data; httpReady = std::promise(); diff --git a/executor.h b/executor.h index d900b418..968db061 100644 --- a/executor.h +++ b/executor.h @@ -19,8 +19,7 @@ class executor return oInst; }; - void ex_start() { my_thd = new std::thread(&executor::ex_main, this); } - void ex_main(); + void ex_start(bool daemon) { daemon ? ex_main() : std::thread(&executor::ex_main, this).detach(); } void get_http_report(ex_event_name ev_id, std::string& data); @@ -53,7 +52,6 @@ class executor telemetry* telem; std::vector* pvThreads; - std::thread* my_thd; size_t current_pool_id; @@ -67,6 +65,8 @@ class executor executor(); static executor* oInst; + void ex_main(); + void ex_clock_thd(); void pool_connect(jpsock* pool); @@ -77,6 +77,7 @@ class executor void http_hashrate_report(std::string& out); void http_result_report(std::string& out); void http_connection_report(std::string& out); + void http_json_report(std::string& out); void http_report(ex_event_name ev); void print_report(ex_event_name ev); @@ -126,10 +127,7 @@ class executor bool compare(std::string& err) { if(msg == err) - { - increment(); return true; - } else return false; } diff --git a/httpd.cpp b/httpd.cpp index 7c94f766..53b73f17 100644 --- a/httpd.cpp +++ b/httpd.cpp @@ -36,11 +36,9 @@ #include "webdesign.h" +#include #ifdef _WIN32 -#include "libmicrohttpd/microhttpd.h" #define strcasecmp _stricmp -#else -#include #endif // _WIN32 httpd* httpd::oInst = nullptr; @@ -84,6 +82,13 @@ int httpd::req_handler(void * cls, MHD_add_response_header(rsp, "ETag", sHtmlCssEtag); MHD_add_response_header(rsp, "Content-Type", "text/css; charset=utf-8"); } + else if(strcasecmp(url, "/api.json") == 0) + { + executor::inst()->get_http_report(EV_HTML_JSON, str); + + rsp = MHD_create_response_from_buffer(str.size(), (void*)str.c_str(), MHD_RESPMEM_MUST_COPY); + MHD_add_response_header(rsp, "Content-Type", "application/json; charset=utf-8"); + } else if(strcasecmp(url, "/h") == 0 || strcasecmp(url, "/hashrate") == 0) { executor::inst()->get_http_report(EV_HTML_HASHRATE, str); diff --git a/hwlocMemory.hpp b/hwlocMemory.hpp new file mode 100644 index 00000000..f471951d --- /dev/null +++ b/hwlocMemory.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "console.h" + +#ifndef CONF_NO_HWLOC + +#include + +/** pin memory to NUMA node + * + * Set the default memory policy for the current thread to bind memory to the + * NUMA node. + * + * @param puId core id + */ +void bindMemoryToNUMANode( size_t puId ) +{ + int depth; + hwloc_topology_t topology; + + hwloc_topology_init(&topology); + hwloc_topology_load(topology); + + depth = hwloc_get_type_depth(topology, HWLOC_OBJ_PU); + + for( size_t i = 0; + i < hwloc_get_nbobjs_by_depth(topology, depth); + i++ ) + { + hwloc_obj_t pu = hwloc_get_obj_by_depth(topology, depth, i); + if( pu->os_index == puId ) + { + if( 0 > hwloc_set_membind_nodeset( + topology, + pu->nodeset, + HWLOC_MEMBIND_BIND, + HWLOC_MEMBIND_THREAD)) + { + printer::inst()->print_msg(L0, "hwloc: can't bind memory"); + } + else + { + printer::inst()->print_msg(L0, "hwloc: memory pinned"); + break; + } + } + } +} +#else + +void bindMemoryToNUMANode( size_t ) +{ +} + +#endif diff --git a/jconf.cpp b/jconf.cpp index d272325c..4ac4c13c 100644 --- a/jconf.cpp +++ b/jconf.cpp @@ -45,10 +45,10 @@ using namespace rapidjson; /* * This enum needs to match index in oConfigValues, otherwise we will get a runtime error */ -enum configEnum { aCpuThreadsConf, sUseSlowMem, bNiceHashMode, +enum configEnum { aCpuThreadsConf, sUseSlowMem, bNiceHashMode, bAesOverride, bTlsMode, bTlsSecureAlgo, sTlsFingerprint, sPoolAddr, sWalletAddr, sPoolPwd, iCallTimeout, iNetRetry, iGiveUpLimit, iVerboseLevel, iAutohashTime, - sOutputFile, iHttpdPort, bPreferIpv4 }; + bDaemonMode, sOutputFile, iHttpdPort, bPreferIpv4 }; struct configVal { configEnum iName; @@ -62,6 +62,7 @@ configVal oConfigValues[] = { { aCpuThreadsConf, "cpu_threads_conf", kNullType }, { sUseSlowMem, "use_slow_memory", kStringType }, { bNiceHashMode, "nicehash_nonce", kTrueType }, + { bAesOverride, "aes_override", kNullType }, { bTlsMode, "use_tls", kTrueType }, { bTlsSecureAlgo, "tls_secure_algo", kTrueType }, { sTlsFingerprint, "tls_fingerprint", kStringType }, @@ -73,6 +74,7 @@ configVal oConfigValues[] = { { iGiveUpLimit, "giveup_limit", kNumberType }, { iVerboseLevel, "verbose_level", kNumberType }, { iAutohashTime, "h_print_time", kNumberType }, + { bDaemonMode, "daemon_mode", kTrueType }, { sOutputFile, "output_file", kStringType }, { iHttpdPort, "httpd_port", kNumberType }, { bPreferIpv4, "prefer_ipv4", kTrueType } @@ -251,6 +253,11 @@ bool jconf::NiceHashMode() return prv->configValues[bNiceHashMode]->GetBool(); } +bool jconf::DaemonMode() +{ + return prv->configValues[bDaemonMode]->GetBool(); +} + const char* jconf::GetOutputFile() { return prv->configValues[sOutputFile]->GetString(); @@ -447,11 +454,14 @@ bool jconf::parse_config(const char* sFilename) printer::inst()->set_verbose_level(prv->configValues[iVerboseLevel]->GetUint64()); - if(!NeedsAutoconf()) - { - if(!bHaveAes) - printer::inst()->print_msg(L0, "Your CPU doesn't support hardware AES. Don't expect high hashrates."); - } + if(NeedsAutoconf()) + return true; + + if(prv->configValues[bAesOverride]->IsBool()) + bHaveAes = prv->configValues[bAesOverride]->GetBool(); + + if(!bHaveAes) + printer::inst()->print_msg(L0, "Your CPU doesn't support hardware AES. Don't expect high hashrates."); return true; } diff --git a/jconf.h b/jconf.h index f932728f..c42fbe03 100644 --- a/jconf.h +++ b/jconf.h @@ -54,6 +54,8 @@ class jconf bool NiceHashMode(); + bool DaemonMode(); + bool PreferIpv4(); inline bool HaveHardwareAes() { return bHaveAes; } diff --git a/jpsock.cpp b/jpsock.cpp index 913f9162..d179f2af 100644 --- a/jpsock.cpp +++ b/jpsock.cpp @@ -32,8 +32,9 @@ #include "jext.h" #include "socks.h" #include "socket.h" +#include "version.h" -#define AGENTID_STR "xmr-stak-cpu/1.3.1" +#define AGENTID_STR XMR_STAK_NAME "/" XMR_STAK_VERSION using namespace rapidjson; diff --git a/libmicrohttpd/microhttpd.h b/libmicrohttpd/microhttpd.h deleted file mode 100644 index ff292280..00000000 --- a/libmicrohttpd/microhttpd.h +++ /dev/null @@ -1,2875 +0,0 @@ -/* - This file is part of libmicrohttpd - Copyright (C) 2006-2015 Christian Grothoff (and other contributing authors) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/** - * @file microhttpd.h - * @brief public interface to libmicrohttpd - * @author Christian Grothoff - * @author Karlson2k (Evgeny Grin) - * @author Chris GauthierDickey - * - * All symbols defined in this header start with MHD. MHD is a small - * HTTP daemon library. As such, it does not have any API for logging - * errors (you can only enable or disable logging to stderr). Also, - * it may not support all of the HTTP features directly, where - * applicable, portions of HTTP may have to be handled by clients of - * the library. - * - * The library is supposed to handle everything that it must handle - * (because the API would not allow clients to do this), such as basic - * connection management; however, detailed interpretations of headers - * -- such as range requests -- and HTTP methods are left to clients. - * The library does understand HEAD and will only send the headers of - * the response and not the body, even if the client supplied a body. - * The library also understands headers that control connection - * management (specifically, "Connection: close" and "Expect: 100 - * continue" are understood and handled automatically). - * - * MHD understands POST data and is able to decode certain formats - * (at the moment only "application/x-www-form-urlencoded" and - * "mulitpart/formdata"). Unsupported encodings and large POST - * submissions may require the application to manually process - * the stream, which is provided to the main application (and thus can be - * processed, just not conveniently by MHD). - * - * The header file defines various constants used by the HTTP protocol. - * This does not mean that MHD actually interprets all of these - * values. The provided constants are exported as a convenience - * for users of the library. MHD does not verify that transmitted - * HTTP headers are part of the standard specification; users of the - * library are free to define their own extensions of the HTTP - * standard and use those with MHD. - * - * All functions are guaranteed to be completely reentrant and - * thread-safe (with the exception of #MHD_set_connection_value, - * which must only be used in a particular context). - * - * - * @defgroup event event-loop control - * MHD API to start and stop the HTTP server and manage the event loop. - * @defgroup response generation of responses - * MHD API used to generate responses. - * @defgroup request handling of requests - * MHD API used to access information about requests. - * @defgroup authentication HTTP authentication - * MHD API related to basic and digest HTTP authentication. - * @defgroup logging logging - * MHD API to mange logging and error handling - * @defgroup specialized misc. specialized functions - * This group includes functions that do not fit into any particular - * category and that are rarely used. - */ - -#ifndef MHD_MICROHTTPD_H -#define MHD_MICROHTTPD_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -/* While we generally would like users to use a configure-driven - build process which detects which headers are present and - hence works on any platform, we use "standard" includes here - to build out-of-the-box for beginning users on common systems. - - If generic headers don't work on your platform, include headers - which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', - 'uint16_t', 'uint32_t', 'uint64_t', 'off_t', 'struct sockaddr', - 'socklen_t', 'fd_set' and "#define MHD_PLATFORM_H" before - including "microhttpd.h". Then the following "standard" - includes won't be used (which might be a good idea, especially - on platforms where they do not exist). - */ -#ifndef MHD_PLATFORM_H -#include -#include -#include -#if defined(_WIN32) && !defined(__CYGWIN__) -#include -#if defined(_MSC_FULL_VER) && !defined (_SSIZE_T_DEFINED) -#define _SSIZE_T_DEFINED -typedef intptr_t ssize_t; -#endif /* !_SSIZE_T_DEFINED */ -#else -#include -#include -#include -#endif -#endif - -#if defined(__CYGWIN__) && !defined(_SYS_TYPES_FD_SET) -/* Do not define __USE_W32_SOCKETS under Cygwin! */ -#error Cygwin with winsock fd_set is not supported -#endif - -/** - * Current version of the library. - * 0x01093001 = 1.9.30-1. - */ -#define MHD_VERSION 0x00095100 - -/** - * MHD-internal return code for "YES". - */ -#define MHD_YES 1 - -/** - * MHD-internal return code for "NO". - */ -#define MHD_NO 0 - -/** - * MHD digest auth internal code for an invalid nonce. - */ -#define MHD_INVALID_NONCE -1 - -/** - * Constant used to indicate unknown size (use when - * creating a response). - */ -#ifdef UINT64_MAX -#define MHD_SIZE_UNKNOWN UINT64_MAX -#else -#define MHD_SIZE_UNKNOWN ((uint64_t) -1LL) -#endif - -#ifdef SIZE_MAX -#define MHD_CONTENT_READER_END_OF_STREAM SIZE_MAX -#define MHD_CONTENT_READER_END_WITH_ERROR (SIZE_MAX - 1) -#else -#define MHD_CONTENT_READER_END_OF_STREAM ((size_t) -1LL) -#define MHD_CONTENT_READER_END_WITH_ERROR (((size_t) -1LL) - 1) -#endif - -#ifndef _MHD_EXTERN -#if defined(_WIN32) && defined(MHD_W32LIB) -#define _MHD_EXTERN extern -#elif defined (_WIN32) && defined(MHD_W32DLL) -/* Define MHD_W32DLL when using MHD as W32 .DLL to speed up linker a little */ -#define _MHD_EXTERN __declspec(dllimport) -#else -#define _MHD_EXTERN extern -#endif -#endif - -#ifndef MHD_SOCKET_DEFINED -/** - * MHD_socket is type for socket FDs - */ -#if !defined(_WIN32) || defined(_SYS_TYPES_FD_SET) -#define MHD_POSIX_SOCKETS 1 -typedef int MHD_socket; -#define MHD_INVALID_SOCKET (-1) -#else /* !defined(_WIN32) || defined(_SYS_TYPES_FD_SET) */ -#define MHD_WINSOCK_SOCKETS 1 -#include -typedef SOCKET MHD_socket; -#define MHD_INVALID_SOCKET (INVALID_SOCKET) -#endif /* !defined(_WIN32) || defined(_SYS_TYPES_FD_SET) */ -#define MHD_SOCKET_DEFINED 1 -#endif /* MHD_SOCKET_DEFINED */ - -/** - * Define MHD_NO_DEPRECATION before including "microhttpd.h" to disable deprecation messages - */ -#ifdef MHD_NO_DEPRECATION -#define _MHD_DEPR_MACRO(msg) -#define _MHD_NO_DEPR_IN_MACRO 1 -#define _MHD_DEPR_IN_MACRO(msg) -#define _MHD_NO_DEPR_FUNC 1 -#define _MHD_DEPR_FUNC(msg) -#endif /* MHD_NO_DEPRECATION */ - -#ifndef _MHD_DEPR_MACRO -#if defined(_MSC_FULL_VER) && _MSC_VER+0 >= 1500 -/* VS 2008 or later */ -/* Stringify macros */ -#define _MHD_INSTRMACRO(a) #a -#define _MHD_STRMACRO(a) _MHD_INSTRMACRO(a) -/* deprecation message */ -#define _MHD_DEPR_MACRO(msg) __pragma(message(__FILE__ "(" _MHD_STRMACRO(__LINE__)"): warning: " msg)) -#define _MHD_DEPR_IN_MACRO(msg) _MHD_DEPR_MACRO(msg) -#elif defined(__clang__) || defined (__GNUC_PATCHLEVEL__) -/* clang or GCC since 3.0 */ -#define _MHD_GCC_PRAG(x) _Pragma (#x) -#if __clang_major__+0 >= 5 || \ - (!defined(__apple_build_version__) && (__clang_major__+0 > 3 || (__clang_major__+0 == 3 && __clang_minor__ >= 3))) || \ - __GNUC__+0 > 4 || (__GNUC__+0 == 4 && __GNUC_MINOR__+0 >= 8) -/* clang >= 3.3 (or XCode's clang >= 5.0) or - GCC >= 4.8 */ -#define _MHD_DEPR_MACRO(msg) _MHD_GCC_PRAG(GCC warning msg) -#define _MHD_DEPR_IN_MACRO(msg) _MHD_DEPR_MACRO(msg) -#else /* older clang or GCC */ -/* clang < 3.3, XCode's clang < 5.0, 3.0 <= GCC < 4.8 */ -#define _MHD_DEPR_MACRO(msg) _MHD_GCC_PRAG(message msg) -#if (__clang_major__+0 > 2 || (__clang_major__+0 == 2 && __clang_minor__ >= 9)) /* FIXME: clang >= 2.9, earlier versions not tested */ -/* clang handles inline pragmas better than GCC */ -#define _MHD_DEPR_IN_MACRO(msg) _MHD_DEPR_MACRO(msg) -#endif /* clang >= 2.9 */ -#endif /* older clang or GCC */ -/* #elif defined(SOMEMACRO) */ /* add compiler-specific macros here if required */ -#endif /* clang || GCC >= 3.0 */ -#endif /* !_MHD_DEPR_MACRO */ - -#ifndef _MHD_DEPR_MACRO -#define _MHD_DEPR_MACRO(msg) -#endif /* !_MHD_DEPR_MACRO */ - -#ifndef _MHD_DEPR_IN_MACRO -#define _MHD_NO_DEPR_IN_MACRO 1 -#define _MHD_DEPR_IN_MACRO(msg) -#endif /* !_MHD_DEPR_IN_MACRO */ - -#ifndef _MHD_DEPR_FUNC -#if defined(_MSC_FULL_VER) && _MSC_VER+0 >= 1400 -/* VS 2005 or later */ -#define _MHD_DEPR_FUNC(msg) __declspec(deprecated(msg)) -#elif defined(_MSC_FULL_VER) && _MSC_VER+0 >= 1310 -/* VS .NET 2003 deprecation do not support custom messages */ -#define _MHD_DEPR_FUNC(msg) __declspec(deprecated) -#elif (__GNUC__+0 >= 5) || (defined (__clang__) && \ - (__clang_major__+0 > 2 || (__clang_major__+0 == 2 && __clang_minor__ >= 9))) /* FIXME: earlier versions not tested */ -/* GCC >= 5.0 or clang >= 2.9 */ -#define _MHD_DEPR_FUNC(msg) __attribute__((deprecated(msg))) -#elif defined (__clang__) || __GNUC__+0 > 3 || (__GNUC__+0 == 3 && __GNUC_MINOR__+0 >= 1) -/* 3.1 <= GCC < 5.0 or clang < 2.9 */ -/* old GCC-style deprecation do not support custom messages */ -#define _MHD_DEPR_FUNC(msg) __attribute__((__deprecated__)) -/* #elif defined(SOMEMACRO) */ /* add compiler-specific macros here if required */ -#endif /* clang < 2.9 || GCC >= 3.1 */ -#endif /* !_MHD_DEPR_FUNC */ - -#ifndef _MHD_DEPR_FUNC -#define _MHD_NO_DEPR_FUNC 1 -#define _MHD_DEPR_FUNC(msg) -#endif /* !_MHD_DEPR_FUNC */ - -/** - * Not all architectures and `printf()`'s support the `long long` type. - * This gives the ability to replace `long long` with just a `long`, - * standard `int` or a `short`. - */ -#ifndef MHD_LONG_LONG -/** - * @deprecated use #MHD_UNSIGNED_LONG_LONG instead! - */ -#define MHD_LONG_LONG long long -#define MHD_UNSIGNED_LONG_LONG unsigned long long -#else /* MHD_LONG_LONG */ -_MHD_DEPR_MACRO("Macro MHD_LONG_LONG is deprecated, use MHD_UNSIGNED_LONG_LONG") -#endif -/** - * Format string for printing a variable of type #MHD_LONG_LONG. - * You should only redefine this if you also define #MHD_LONG_LONG. - */ -#ifndef MHD_LONG_LONG_PRINTF -/** - * @deprecated use #MHD_UNSIGNED_LONG_LONG_PRINTF instead! - */ -#define MHD_LONG_LONG_PRINTF "ll" -#define MHD_UNSIGNED_LONG_LONG_PRINTF "%llu" -#else /* MHD_LONG_LONG_PRINTF */ -_MHD_DEPR_MACRO("Macro MHD_LONG_LONG_PRINTF is deprecated, use MHD_UNSIGNED_LONG_LONG_PRINTF") -#endif - - -/** - * @defgroup httpcode HTTP response codes. - * These are the status codes defined for HTTP responses. - * @{ - */ -#define MHD_HTTP_CONTINUE 100 -#define MHD_HTTP_SWITCHING_PROTOCOLS 101 -#define MHD_HTTP_PROCESSING 102 - -#define MHD_HTTP_OK 200 -#define MHD_HTTP_CREATED 201 -#define MHD_HTTP_ACCEPTED 202 -#define MHD_HTTP_NON_AUTHORITATIVE_INFORMATION 203 -#define MHD_HTTP_NO_CONTENT 204 -#define MHD_HTTP_RESET_CONTENT 205 -#define MHD_HTTP_PARTIAL_CONTENT 206 -#define MHD_HTTP_MULTI_STATUS 207 - -#define MHD_HTTP_MULTIPLE_CHOICES 300 -#define MHD_HTTP_MOVED_PERMANENTLY 301 -#define MHD_HTTP_FOUND 302 -#define MHD_HTTP_SEE_OTHER 303 -#define MHD_HTTP_NOT_MODIFIED 304 -#define MHD_HTTP_USE_PROXY 305 -#define MHD_HTTP_SWITCH_PROXY 306 -#define MHD_HTTP_TEMPORARY_REDIRECT 307 -#define MHD_HTTP_PERMANENT_REDIRECT 308 - -#define MHD_HTTP_BAD_REQUEST 400 -#define MHD_HTTP_UNAUTHORIZED 401 -#define MHD_HTTP_PAYMENT_REQUIRED 402 -#define MHD_HTTP_FORBIDDEN 403 -#define MHD_HTTP_NOT_FOUND 404 -#define MHD_HTTP_METHOD_NOT_ALLOWED 405 -#define MHD_HTTP_NOT_ACCEPTABLE 406 -/** @deprecated */ -#define MHD_HTTP_METHOD_NOT_ACCEPTABLE \ - _MHD_DEPR_IN_MACRO("Value MHD_HTTP_METHOD_NOT_ACCEPTABLE is deprecated, use MHD_HTTP_NOT_ACCEPTABLE") 406 -#define MHD_HTTP_PROXY_AUTHENTICATION_REQUIRED 407 -#define MHD_HTTP_REQUEST_TIMEOUT 408 -#define MHD_HTTP_CONFLICT 409 -#define MHD_HTTP_GONE 410 -#define MHD_HTTP_LENGTH_REQUIRED 411 -#define MHD_HTTP_PRECONDITION_FAILED 412 -#define MHD_HTTP_REQUEST_ENTITY_TOO_LARGE 413 -#define MHD_HTTP_REQUEST_URI_TOO_LONG 414 -#define MHD_HTTP_UNSUPPORTED_MEDIA_TYPE 415 -#define MHD_HTTP_REQUESTED_RANGE_NOT_SATISFIABLE 416 -#define MHD_HTTP_EXPECTATION_FAILED 417 -#define MHD_HTTP_UNPROCESSABLE_ENTITY 422 -#define MHD_HTTP_LOCKED 423 -#define MHD_HTTP_FAILED_DEPENDENCY 424 -#define MHD_HTTP_UNORDERED_COLLECTION 425 -#define MHD_HTTP_UPGRADE_REQUIRED 426 -#define MHD_HTTP_NO_RESPONSE 444 -#define MHD_HTTP_RETRY_WITH 449 -#define MHD_HTTP_BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS 450 -#define MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS 451 - -#define MHD_HTTP_INTERNAL_SERVER_ERROR 500 -#define MHD_HTTP_NOT_IMPLEMENTED 501 -#define MHD_HTTP_BAD_GATEWAY 502 -#define MHD_HTTP_SERVICE_UNAVAILABLE 503 -#define MHD_HTTP_GATEWAY_TIMEOUT 504 -#define MHD_HTTP_HTTP_VERSION_NOT_SUPPORTED 505 -#define MHD_HTTP_VARIANT_ALSO_NEGOTIATES 506 -#define MHD_HTTP_INSUFFICIENT_STORAGE 507 -#define MHD_HTTP_BANDWIDTH_LIMIT_EXCEEDED 509 -#define MHD_HTTP_NOT_EXTENDED 510 - -/** @} */ /* end of group httpcode */ - -/** - * Returns the string reason phrase for a response code. - * - * If we don't have a string for a status code, we give the first - * message in that status code class. - */ -_MHD_EXTERN const char * -MHD_get_reason_phrase_for (unsigned int code); - - -/** - * Flag to be or-ed with MHD_HTTP status code for - * SHOUTcast. This will cause the response to begin - * with the SHOUTcast "ICY" line instad of "HTTP". - * @ingroup specialized - */ -#define MHD_ICY_FLAG ((uint32_t)(((uint32_t)1) << 31)) - -/** - * @defgroup headers HTTP headers - * These are the standard headers found in HTTP requests and responses. - * @{ - */ -/* See also: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html */ -#define MHD_HTTP_HEADER_ACCEPT "Accept" -#define MHD_HTTP_HEADER_ACCEPT_CHARSET "Accept-Charset" -#define MHD_HTTP_HEADER_ACCEPT_ENCODING "Accept-Encoding" -#define MHD_HTTP_HEADER_ACCEPT_LANGUAGE "Accept-Language" -#define MHD_HTTP_HEADER_ACCEPT_RANGES "Accept-Ranges" -#define MHD_HTTP_HEADER_AGE "Age" -#define MHD_HTTP_HEADER_ALLOW "Allow" -#define MHD_HTTP_HEADER_AUTHORIZATION "Authorization" -#define MHD_HTTP_HEADER_CACHE_CONTROL "Cache-Control" -#define MHD_HTTP_HEADER_CONNECTION "Connection" -#define MHD_HTTP_HEADER_CONTENT_ENCODING "Content-Encoding" -#define MHD_HTTP_HEADER_CONTENT_LANGUAGE "Content-Language" -#define MHD_HTTP_HEADER_CONTENT_LENGTH "Content-Length" -#define MHD_HTTP_HEADER_CONTENT_LOCATION "Content-Location" -#define MHD_HTTP_HEADER_CONTENT_MD5 "Content-MD5" -#define MHD_HTTP_HEADER_CONTENT_RANGE "Content-Range" -#define MHD_HTTP_HEADER_CONTENT_TYPE "Content-Type" -#define MHD_HTTP_HEADER_COOKIE "Cookie" -#define MHD_HTTP_HEADER_DATE "Date" -#define MHD_HTTP_HEADER_ETAG "ETag" -#define MHD_HTTP_HEADER_EXPECT "Expect" -#define MHD_HTTP_HEADER_EXPIRES "Expires" -#define MHD_HTTP_HEADER_FROM "From" -#define MHD_HTTP_HEADER_HOST "Host" -#define MHD_HTTP_HEADER_IF_MATCH "If-Match" -#define MHD_HTTP_HEADER_IF_MODIFIED_SINCE "If-Modified-Since" -#define MHD_HTTP_HEADER_IF_NONE_MATCH "If-None-Match" -#define MHD_HTTP_HEADER_IF_RANGE "If-Range" -#define MHD_HTTP_HEADER_IF_UNMODIFIED_SINCE "If-Unmodified-Since" -#define MHD_HTTP_HEADER_LAST_MODIFIED "Last-Modified" -#define MHD_HTTP_HEADER_LOCATION "Location" -#define MHD_HTTP_HEADER_MAX_FORWARDS "Max-Forwards" -#define MHD_HTTP_HEADER_PRAGMA "Pragma" -#define MHD_HTTP_HEADER_PROXY_AUTHENTICATE "Proxy-Authenticate" -#define MHD_HTTP_HEADER_PROXY_AUTHORIZATION "Proxy-Authorization" -#define MHD_HTTP_HEADER_RANGE "Range" -/* This is not a typo, see HTTP spec */ -#define MHD_HTTP_HEADER_REFERER "Referer" -#define MHD_HTTP_HEADER_RETRY_AFTER "Retry-After" -#define MHD_HTTP_HEADER_SERVER "Server" -#define MHD_HTTP_HEADER_SET_COOKIE "Set-Cookie" -#define MHD_HTTP_HEADER_SET_COOKIE2 "Set-Cookie2" -#define MHD_HTTP_HEADER_TE "TE" -#define MHD_HTTP_HEADER_TRAILER "Trailer" -#define MHD_HTTP_HEADER_TRANSFER_ENCODING "Transfer-Encoding" -#define MHD_HTTP_HEADER_UPGRADE "Upgrade" -#define MHD_HTTP_HEADER_USER_AGENT "User-Agent" -#define MHD_HTTP_HEADER_VARY "Vary" -#define MHD_HTTP_HEADER_VIA "Via" -#define MHD_HTTP_HEADER_WARNING "Warning" -#define MHD_HTTP_HEADER_WWW_AUTHENTICATE "WWW-Authenticate" -#define MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN "Access-Control-Allow-Origin" -#define MHD_HTTP_HEADER_CONTENT_DISPOSITION "Content-Disposition" - -/** @} */ /* end of group headers */ - -/** - * @defgroup versions HTTP versions - * These strings should be used to match against the first line of the - * HTTP header. - * @{ - */ -#define MHD_HTTP_VERSION_1_0 "HTTP/1.0" -#define MHD_HTTP_VERSION_1_1 "HTTP/1.1" - -/** @} */ /* end of group versions */ - -/** - * @defgroup methods HTTP methods - * Standard HTTP methods (as strings). - * @{ - */ -#define MHD_HTTP_METHOD_CONNECT "CONNECT" -#define MHD_HTTP_METHOD_DELETE "DELETE" -#define MHD_HTTP_METHOD_GET "GET" -#define MHD_HTTP_METHOD_HEAD "HEAD" -#define MHD_HTTP_METHOD_OPTIONS "OPTIONS" -#define MHD_HTTP_METHOD_POST "POST" -#define MHD_HTTP_METHOD_PUT "PUT" -#define MHD_HTTP_METHOD_PATCH "PATCH" -#define MHD_HTTP_METHOD_TRACE "TRACE" - -/** @} */ /* end of group methods */ - -/** - * @defgroup postenc HTTP POST encodings - * See also: http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 - * @{ - */ -#define MHD_HTTP_POST_ENCODING_FORM_URLENCODED "application/x-www-form-urlencoded" -#define MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA "multipart/form-data" - -/** @} */ /* end of group postenc */ - - -/** - * @brief Handle for the daemon (listening on a socket for HTTP traffic). - * @ingroup event - */ -struct MHD_Daemon; - -/** - * @brief Handle for a connection / HTTP request. - * - * With HTTP/1.1, multiple requests can be run over the same - * connection. However, MHD will only show one request per TCP - * connection to the client at any given time. - * @ingroup request - */ -struct MHD_Connection; - -/** - * @brief Handle for a response. - * @ingroup response - */ -struct MHD_Response; - -/** - * @brief Handle for POST processing. - * @ingroup response - */ -struct MHD_PostProcessor; - - -/** - * @brief Flags for the `struct MHD_Daemon`. - * - * Note that if neither #MHD_USE_THREAD_PER_CONNECTION nor - * #MHD_USE_SELECT_INTERNALLY is used, the client wants control over - * the process and will call the appropriate microhttpd callbacks. - * - * Starting the daemon may also fail if a particular option is not - * implemented or not supported on the target platform (i.e. no - * support for SSL, threads or IPv6). - */ -enum MHD_FLAG -{ - /** - * No options selected. - */ - MHD_NO_FLAG = 0, - - /** - * Run in debug mode. If this flag is used, the library should - * print error messages and warnings to `stderr`. - */ - MHD_USE_DEBUG = 1, - - /** - * Run in HTTPS mode. - */ - MHD_USE_SSL = 2, - - /** - * Run using one thread per connection. - */ - MHD_USE_THREAD_PER_CONNECTION = 4, - - /** - * Run using an internal thread (or thread pool) doing `select()`. - */ - MHD_USE_SELECT_INTERNALLY = 8, - - /** - * Run using the IPv6 protocol (otherwise, MHD will just support - * IPv4). If you want MHD to support IPv4 and IPv6 using a single - * socket, pass #MHD_USE_DUAL_STACK, otherwise, if you only pass - * this option, MHD will try to bind to IPv6-only (resulting in - * no IPv4 support). - */ - MHD_USE_IPv6 = 16, - - /** - * Be pedantic about the protocol (as opposed to as tolerant as - * possible). Specifically, at the moment, this flag causes MHD to - * reject HTTP 1.1 connections without a "Host" header. This is - * required by the standard, but of course in violation of the "be - * as liberal as possible in what you accept" norm. It is - * recommended to turn this ON if you are testing clients against - * MHD, and OFF in production. - */ - MHD_USE_PEDANTIC_CHECKS = 32, - - /** - * Use `poll()` instead of `select()`. This allows sockets with `fd >= - * FD_SETSIZE`. This option is not compatible with using an - * 'external' `select()` mode (as there is no API to get the file - * descriptors for the external select from MHD) and must also not - * be used in combination with #MHD_USE_EPOLL. - */ - MHD_USE_POLL = 64, - - /** - * Run using an internal thread (or thread pool) doing `poll()`. - */ - MHD_USE_POLL_INTERNALLY = MHD_USE_SELECT_INTERNALLY | MHD_USE_POLL, - - /** - * Suppress (automatically) adding the 'Date:' header to HTTP responses. - * This option should ONLY be used on systems that do not have a clock - * and that DO provide other mechanisms for cache control. See also - * RFC 2616, section 14.18 (exception 3). - */ - MHD_SUPPRESS_DATE_NO_CLOCK = 128, - - /** - * Run without a listen socket. This option only makes sense if - * #MHD_add_connection is to be used exclusively to connect HTTP - * clients to the HTTP server. This option is incompatible with - * using a thread pool; if it is used, #MHD_OPTION_THREAD_POOL_SIZE - * is ignored. - */ - MHD_USE_NO_LISTEN_SOCKET = 256, - - /** - * Use `epoll()` instead of `select()` or `poll()` for the event loop. - * This option is only available on some systems; using the option on - * systems without epoll will cause #MHD_start_daemon to fail. Using - * this option is not supported with #MHD_USE_THREAD_PER_CONNECTION. - * @sa ::MHD_FEATURE_EPOLL - */ - MHD_USE_EPOLL = 512, - -/** @deprecated */ -#define MHD_USE_EPOLL_LINUX_ONLY \ - _MHD_DEPR_IN_MACRO("Value MHD_USE_EPOLL_LINUX_ONLY is deprecated, use MHD_USE_EPOLL") \ - MHD_USE_EPOLL - - /** - * Run using an internal thread (or thread pool) doing `epoll()`. - * This option is only available on Linux; using the option on - * non-Linux systems will cause #MHD_start_daemon to fail. - */ - MHD_USE_EPOLL_INTERNALLY = MHD_USE_SELECT_INTERNALLY | MHD_USE_EPOLL, - -/** @deprecated */ -#define MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY \ - _MHD_DEPR_IN_MACRO("Value MHD_USE_EPOLL_INTERNALLY_LINUX_ONLY is deprecated, use MHD_USE_EPOLL_INTERNALLY") \ - MHD_USE_EPOLL_INTERNALLY - - /** - * Force MHD to use a signal pipe to notify the event loop (of - * threads) of our shutdown. This is required if an appliction uses - * #MHD_USE_SELECT_INTERNALLY or #MHD_USE_THREAD_PER_CONNECTION and - * then performs #MHD_quiesce_daemon (which eliminates our ability - * to signal termination via the listen socket). In these modes, - * #MHD_quiesce_daemon will fail if this option was not set. Also, - * use of this option is automatic (as in, you do not even have to - * specify it), if #MHD_USE_NO_LISTEN_SOCKET is specified. In - * "external" `select()` mode, this option is always simply ignored. - * MHD can be build for use a pair of sockets instead of a pipe. - * Pair of sockets is forced on W32. - * - * You must also use this option if you use internal select mode - * or a thread pool in conjunction with #MHD_add_connection. - */ - MHD_USE_PIPE_FOR_SHUTDOWN = 1024, - - /** - * Use a single socket for IPv4 and IPv6. - */ - MHD_USE_DUAL_STACK = MHD_USE_IPv6 | 2048, - - /** - * Enable `epoll()` turbo. Disables certain calls to `shutdown()` - * and enables aggressive non-blocking optimisitc reads. - * Most effects only happen with #MHD_USE_EPOLL. - * Enalbed always on W32 as winsock does not properly behave - * with `shutdown()` and this then fixes potential problems. - */ - MHD_USE_EPOLL_TURBO = 4096, - - /** - * Enable suspend/resume functions, which also implies setting up - * pipes to signal resume. - */ - MHD_USE_SUSPEND_RESUME = 8192 | MHD_USE_PIPE_FOR_SHUTDOWN, - - /** - * Enable TCP_FASTOPEN option. This option is only available on Linux with a - * kernel >= 3.6. On other systems, using this option cases #MHD_start_daemon - * to fail. - */ - MHD_USE_TCP_FASTOPEN = 16384 - -}; - - -/** - * Type of a callback function used for logging by MHD. - * - * @param cls closure - * @param fm format string (`printf()`-style) - * @param ap arguments to @a fm - * @ingroup logging - */ -typedef void -(*MHD_LogCallback)(void *cls, - const char *fm, - va_list ap); - - -/** - * @brief MHD options. - * - * Passed in the varargs portion of #MHD_start_daemon. - */ -enum MHD_OPTION -{ - - /** - * No more options / last option. This is used - * to terminate the VARARGs list. - */ - MHD_OPTION_END = 0, - - /** - * Maximum memory size per connection (followed by a `size_t`). - * Default is 32 kb (#MHD_POOL_SIZE_DEFAULT). - * Values above 128k are unlikely to result in much benefit, as half - * of the memory will be typically used for IO, and TCP buffers are - * unlikely to support window sizes above 64k on most systems. - */ - MHD_OPTION_CONNECTION_MEMORY_LIMIT = 1, - - /** - * Maximum number of concurrent connections to - * accept (followed by an `unsigned int`). - */ - MHD_OPTION_CONNECTION_LIMIT = 2, - - /** - * After how many seconds of inactivity should a - * connection automatically be timed out? (followed - * by an `unsigned int`; use zero for no timeout). - */ - MHD_OPTION_CONNECTION_TIMEOUT = 3, - - /** - * Register a function that should be called whenever a request has - * been completed (this can be used for application-specific clean - * up). Requests that have never been presented to the application - * (via #MHD_AccessHandlerCallback) will not result in - * notifications. - * - * This option should be followed by TWO pointers. First a pointer - * to a function of type #MHD_RequestCompletedCallback and second a - * pointer to a closure to pass to the request completed callback. - * The second pointer maybe NULL. - */ - MHD_OPTION_NOTIFY_COMPLETED = 4, - - /** - * Limit on the number of (concurrent) connections made to the - * server from the same IP address. Can be used to prevent one - * IP from taking over all of the allowed connections. If the - * same IP tries to establish more than the specified number of - * connections, they will be immediately rejected. The option - * should be followed by an `unsigned int`. The default is - * zero, which means no limit on the number of connections - * from the same IP address. - */ - MHD_OPTION_PER_IP_CONNECTION_LIMIT = 5, - - /** - * Bind daemon to the supplied `struct sockaddr`. This option should - * be followed by a `struct sockaddr *`. If #MHD_USE_IPv6 is - * specified, the `struct sockaddr*` should point to a `struct - * sockaddr_in6`, otherwise to a `struct sockaddr_in`. - */ - MHD_OPTION_SOCK_ADDR = 6, - - /** - * Specify a function that should be called before parsing the URI from - * the client. The specified callback function can be used for processing - * the URI (including the options) before it is parsed. The URI after - * parsing will no longer contain the options, which maybe inconvenient for - * logging. This option should be followed by two arguments, the first - * one must be of the form - * - * void * my_logger(void *cls, const char *uri, struct MHD_Connection *con) - * - * where the return value will be passed as - * (`* con_cls`) in calls to the #MHD_AccessHandlerCallback - * when this request is processed later; returning a - * value of NULL has no special significance (however, - * note that if you return non-NULL, you can no longer - * rely on the first call to the access handler having - * `NULL == *con_cls` on entry;) - * "cls" will be set to the second argument following - * #MHD_OPTION_URI_LOG_CALLBACK. Finally, uri will - * be the 0-terminated URI of the request. - * - * Note that during the time of this call, most of the connection's - * state is not initialized (as we have not yet parsed he headers). - * However, information about the connecting client (IP, socket) - * is available. - */ - MHD_OPTION_URI_LOG_CALLBACK = 7, - - /** - * Memory pointer for the private key (key.pem) to be used by the - * HTTPS daemon. This option should be followed by a - * `const char *` argument. - * This should be used in conjunction with #MHD_OPTION_HTTPS_MEM_CERT. - */ - MHD_OPTION_HTTPS_MEM_KEY = 8, - - /** - * Memory pointer for the certificate (cert.pem) to be used by the - * HTTPS daemon. This option should be followed by a - * `const char *` argument. - * This should be used in conjunction with #MHD_OPTION_HTTPS_MEM_KEY. - */ - MHD_OPTION_HTTPS_MEM_CERT = 9, - - /** - * Daemon credentials type. - * Followed by an argument of type - * `gnutls_credentials_type_t`. - */ - MHD_OPTION_HTTPS_CRED_TYPE = 10, - - /** - * Memory pointer to a `const char *` specifying the - * cipher algorithm (default: "NORMAL"). - */ - MHD_OPTION_HTTPS_PRIORITIES = 11, - - /** - * Pass a listen socket for MHD to use (systemd-style). If this - * option is used, MHD will not open its own listen socket(s). The - * argument passed must be of type `MHD_socket` and refer to an - * existing socket that has been bound to a port and is listening. - */ - MHD_OPTION_LISTEN_SOCKET = 12, - - /** - * Use the given function for logging error messages. This option - * must be followed by two arguments; the first must be a pointer to - * a function of type #MHD_LogCallback and the second a pointer - * `void *` which will be passed as the first argument to the log - * callback. - * - * Note that MHD will not generate any log messages - * if it was compiled without the "--enable-messages" - * flag being set. - */ - MHD_OPTION_EXTERNAL_LOGGER = 13, - - /** - * Number (`unsigned int`) of threads in thread pool. Enable - * thread pooling by setting this value to to something - * greater than 1. Currently, thread model must be - * #MHD_USE_SELECT_INTERNALLY if thread pooling is enabled - * (#MHD_start_daemon returns NULL for an unsupported thread - * model). - */ - MHD_OPTION_THREAD_POOL_SIZE = 14, - - /** - * Additional options given in an array of `struct MHD_OptionItem`. - * The array must be terminated with an entry `{MHD_OPTION_END, 0, NULL}`. - * An example for code using #MHD_OPTION_ARRAY is: - * - * struct MHD_OptionItem ops[] = { - * { MHD_OPTION_CONNECTION_LIMIT, 100, NULL }, - * { MHD_OPTION_CONNECTION_TIMEOUT, 10, NULL }, - * { MHD_OPTION_END, 0, NULL } - * }; - * d = MHD_start_daemon (0, 8080, NULL, NULL, dh, NULL, - * MHD_OPTION_ARRAY, ops, - * MHD_OPTION_END); - * - * For options that expect a single pointer argument, the - * second member of the `struct MHD_OptionItem` is ignored. - * For options that expect two pointer arguments, the first - * argument must be cast to `intptr_t`. - */ - MHD_OPTION_ARRAY = 15, - - /** - * Specify a function that should be called for unescaping escape - * sequences in URIs and URI arguments. Note that this function - * will NOT be used by the `struct MHD_PostProcessor`. If this - * option is not specified, the default method will be used which - * decodes escape sequences of the form "%HH". This option should - * be followed by two arguments, the first one must be of the form - * - * size_t my_unescaper(void *cls, - * struct MHD_Connection *c, - * char *s) - * - * where the return value must be "strlen(s)" and "s" should be - * updated. Note that the unescape function must not lengthen "s" - * (the result must be shorter than the input and still be - * 0-terminated). "cls" will be set to the second argument - * following #MHD_OPTION_UNESCAPE_CALLBACK. - */ - MHD_OPTION_UNESCAPE_CALLBACK = 16, - - /** - * Memory pointer for the random values to be used by the Digest - * Auth module. This option should be followed by two arguments. - * First an integer of type `size_t` which specifies the size - * of the buffer pointed to by the second argument in bytes. - * Note that the application must ensure that the buffer of the - * second argument remains allocated and unmodified while the - * deamon is running. - */ - MHD_OPTION_DIGEST_AUTH_RANDOM = 17, - - /** - * Size of the internal array holding the map of the nonce and - * the nonce counter. This option should be followed by an `unsigend int` - * argument. - */ - MHD_OPTION_NONCE_NC_SIZE = 18, - - /** - * Desired size of the stack for threads created by MHD. Followed - * by an argument of type `size_t`. Use 0 for system default. - */ - MHD_OPTION_THREAD_STACK_SIZE = 19, - - /** - * Memory pointer for the certificate (ca.pem) to be used by the - * HTTPS daemon for client authentification. - * This option should be followed by a `const char *` argument. - */ - MHD_OPTION_HTTPS_MEM_TRUST = 20, - - /** - * Increment to use for growing the read buffer (followed by a - * `size_t`). Must fit within #MHD_OPTION_CONNECTION_MEMORY_LIMIT. - */ - MHD_OPTION_CONNECTION_MEMORY_INCREMENT = 21, - - /** - * Use a callback to determine which X.509 certificate should be - * used for a given HTTPS connection. This option should be - * followed by a argument of type `gnutls_certificate_retrieve_function2 *`. - * This option provides an - * alternative to #MHD_OPTION_HTTPS_MEM_KEY, - * #MHD_OPTION_HTTPS_MEM_CERT. You must use this version if - * multiple domains are to be hosted at the same IP address using - * TLS's Server Name Indication (SNI) extension. In this case, - * the callback is expected to select the correct certificate - * based on the SNI information provided. The callback is expected - * to access the SNI data using `gnutls_server_name_get()`. - * Using this option requires GnuTLS 3.0 or higher. - */ - MHD_OPTION_HTTPS_CERT_CALLBACK = 22, - - /** - * When using #MHD_USE_TCP_FASTOPEN, this option changes the default TCP - * fastopen queue length of 50. Note that having a larger queue size can - * cause resource exhaustion attack as the TCP stack has to now allocate - * resources for the SYN packet along with its DATA. This option should be - * followed by an `unsigned int` argument. - */ - MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE = 23, - - /** - * Memory pointer for the Diffie-Hellman parameters (dh.pem) to be used by the - * HTTPS daemon for key exchange. - * This option must be followed by a `const char *` argument. - */ - MHD_OPTION_HTTPS_MEM_DHPARAMS = 24, - - /** - * If present and set to true, allow reusing address:port socket - * (by using SO_REUSEPORT on most platform, or platform-specific ways). - * If present and set to false, disallow reusing address:port socket - * (does nothing on most plaform, but uses SO_EXCLUSIVEADDRUSE on Windows). - * This option must be followed by a `unsigned int` argument. - */ - MHD_OPTION_LISTENING_ADDRESS_REUSE = 25, - - /** - * Memory pointer for a password that decrypts the private key (key.pem) - * to be used by the HTTPS daemon. This option should be followed by a - * `const char *` argument. - * This should be used in conjunction with #MHD_OPTION_HTTPS_MEM_KEY. - * @sa ::MHD_FEATURE_HTTPS_KEY_PASSWORD - */ - MHD_OPTION_HTTPS_KEY_PASSWORD = 26, - - /** - * Register a function that should be called whenever a connection is - * started or closed. - * - * This option should be followed by TWO pointers. First a pointer - * to a function of type #MHD_NotifyConnectionCallback and second a - * pointer to a closure to pass to the request completed callback. - * The second pointer maybe NULL. - */ - MHD_OPTION_NOTIFY_CONNECTION = 27, - - /** - * Allow to change maximum length of the queue of pending connections on - * listen socket. If not present than default platform-specific SOMAXCONN - * value is used. This option should be followed by an `unsigned int` - * argument. - */ - MHD_OPTION_LISTEN_BACKLOG_SIZE = 28 -}; - - -/** - * Entry in an #MHD_OPTION_ARRAY. - */ -struct MHD_OptionItem -{ - /** - * Which option is being given. Use #MHD_OPTION_END - * to terminate the array. - */ - enum MHD_OPTION option; - - /** - * Option value (for integer arguments, and for options requiring - * two pointer arguments); should be 0 for options that take no - * arguments or only a single pointer argument. - */ - intptr_t value; - - /** - * Pointer option value (use NULL for options taking no arguments - * or only an integer option). - */ - void *ptr_value; - -}; - - -/** - * The `enum MHD_ValueKind` specifies the source of - * the key-value pairs in the HTTP protocol. - */ -enum MHD_ValueKind -{ - - /** - * Response header - */ - MHD_RESPONSE_HEADER_KIND = 0, - - /** - * HTTP header. - */ - MHD_HEADER_KIND = 1, - - /** - * Cookies. Note that the original HTTP header containing - * the cookie(s) will still be available and intact. - */ - MHD_COOKIE_KIND = 2, - - /** - * POST data. This is available only if a content encoding - * supported by MHD is used (currently only URL encoding), - * and only if the posted content fits within the available - * memory pool. Note that in that case, the upload data - * given to the #MHD_AccessHandlerCallback will be - * empty (since it has already been processed). - */ - MHD_POSTDATA_KIND = 4, - - /** - * GET (URI) arguments. - */ - MHD_GET_ARGUMENT_KIND = 8, - - /** - * HTTP footer (only for HTTP 1.1 chunked encodings). - */ - MHD_FOOTER_KIND = 16 -}; - - -/** - * The `enum MHD_RequestTerminationCode` specifies reasons - * why a request has been terminated (or completed). - * @ingroup request - */ -enum MHD_RequestTerminationCode -{ - - /** - * We finished sending the response. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_COMPLETED_OK = 0, - - /** - * Error handling the connection (resources - * exhausted, other side closed connection, - * application error accepting request, etc.) - * @ingroup request - */ - MHD_REQUEST_TERMINATED_WITH_ERROR = 1, - - /** - * No activity on the connection for the number - * of seconds specified using - * #MHD_OPTION_CONNECTION_TIMEOUT. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_TIMEOUT_REACHED = 2, - - /** - * We had to close the session since MHD was being - * shut down. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN = 3, - - /** - * We tried to read additional data, but the other side closed the - * connection. This error is similar to - * #MHD_REQUEST_TERMINATED_WITH_ERROR, but specific to the case where - * the connection died because the other side did not send expected - * data. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_READ_ERROR = 4, - - /** - * The client terminated the connection by closing the socket - * for writing (TCP half-closed); MHD aborted sending the - * response according to RFC 2616, section 8.1.4. - * @ingroup request - */ - MHD_REQUEST_TERMINATED_CLIENT_ABORT = 5 - -}; - - -/** - * The `enum MHD_ConnectionNotificationCode` specifies types - * of connection notifications. - * @ingroup request - */ -enum MHD_ConnectionNotificationCode -{ - - /** - * A new connection has been started. - * @ingroup request - */ - MHD_CONNECTION_NOTIFY_STARTED = 0, - - /** - * A connection is closed. - * @ingroup request - */ - MHD_CONNECTION_NOTIFY_CLOSED = 1 - -}; - - -/** - * Information about a connection. - */ -union MHD_ConnectionInfo -{ - - /** - * Cipher algorithm used, of type "enum gnutls_cipher_algorithm". - */ - int /* enum gnutls_cipher_algorithm */ cipher_algorithm; - - /** - * Protocol used, of type "enum gnutls_protocol". - */ - int /* enum gnutls_protocol */ protocol; - - /** - * The suspended status of a connection. - */ - int /* MHD_YES or MHD_NO */ suspended; - - /** - * Connect socket - */ - MHD_socket connect_fd; - - /** - * GNUtls session handle, of type "gnutls_session_t". - */ - void * /* gnutls_session_t */ tls_session; - - /** - * GNUtls client certificate handle, of type "gnutls_x509_crt_t". - */ - void * /* gnutls_x509_crt_t */ client_cert; - - /** - * Address information for the client. - */ - struct sockaddr *client_addr; - - /** - * Which daemon manages this connection (useful in case there are many - * daemons running). - */ - struct MHD_Daemon *daemon; - - /** - * Socket-specific client context. Points to the same address as - * the "socket_context" of the #MHD_NotifyConnectionCallback. - */ - void **socket_context; -}; - - -/** - * Values of this enum are used to specify what - * information about a connection is desired. - * @ingroup request - */ -enum MHD_ConnectionInfoType -{ - /** - * What cipher algorithm is being used. - * Takes no extra arguments. - * @ingroup request - */ - MHD_CONNECTION_INFO_CIPHER_ALGO, - - /** - * - * Takes no extra arguments. - * @ingroup request - */ - MHD_CONNECTION_INFO_PROTOCOL, - - /** - * Obtain IP address of the client. Takes no extra arguments. - * Returns essentially a `struct sockaddr **` (since the API returns - * a `union MHD_ConnectionInfo *` and that union contains a `struct - * sockaddr *`). - * @ingroup request - */ - MHD_CONNECTION_INFO_CLIENT_ADDRESS, - - /** - * Get the gnuTLS session handle. - * @ingroup request - */ - MHD_CONNECTION_INFO_GNUTLS_SESSION, - - /** - * Get the gnuTLS client certificate handle. Dysfunctional (never - * implemented, deprecated). Use #MHD_CONNECTION_INFO_GNUTLS_SESSION - * to get the `gnutls_session_t` and then call - * gnutls_certificate_get_peers(). - */ - MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT, - - /** - * Get the `struct MHD_Daemon *` responsible for managing this connection. - * @ingroup request - */ - MHD_CONNECTION_INFO_DAEMON, - - /** - * Request the file descriptor for the listening socket. - * No extra arguments should be passed. - * @ingroup request - */ - MHD_CONNECTION_INFO_CONNECTION_FD, - - /** - * Returns the client-specific pointer to a `void *` that was (possibly) - * set during a #MHD_NotifyConnectionCallback when the socket was - * first accepted. Note that this is NOT the same as the "con_cls" - * argument of the #MHD_AccessHandlerCallback. The "con_cls" is - * fresh for each HTTP request, while the "socket_context" is fresh - * for each socket. - */ - MHD_CONNECTION_INFO_SOCKET_CONTEXT, - - /** - * Check wheter the connection is suspended. - * @ingroup request - */ - MHD_CONNECTION_INFO_CONNECTION_SUSPENDED -}; - - -/** - * Values of this enum are used to specify what - * information about a deamon is desired. - */ -enum MHD_DaemonInfoType -{ - /** - * No longer supported (will return NULL). - */ - MHD_DAEMON_INFO_KEY_SIZE, - - /** - * No longer supported (will return NULL). - */ - MHD_DAEMON_INFO_MAC_KEY_SIZE, - - /** - * Request the file descriptor for the listening socket. - * No extra arguments should be passed. - */ - MHD_DAEMON_INFO_LISTEN_FD, - - /** - * Request the file descriptor for the external epoll. - * No extra arguments should be passed. - */ - MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY, - - /** - * Request the number of current connections handled by the daemon. - * No extra arguments should be passed. - */ - MHD_DAEMON_INFO_CURRENT_CONNECTIONS -}; - - -/** - * Callback for serious error condition. The default action is to print - * an error message and `abort()`. - * - * @param cls user specified value - * @param file where the error occured - * @param line where the error occured - * @param reason error detail, may be NULL - * @ingroup logging - */ -typedef void -(*MHD_PanicCallback) (void *cls, - const char *file, - unsigned int line, - const char *reason); - -/** - * Allow or deny a client to connect. - * - * @param cls closure - * @param addr address information from the client - * @param addrlen length of @a addr - * @return #MHD_YES if connection is allowed, #MHD_NO if not - */ -typedef int -(*MHD_AcceptPolicyCallback) (void *cls, - const struct sockaddr *addr, - socklen_t addrlen); - - -/** - * A client has requested the given url using the given method - * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT, - * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback - * must call MHD callbacks to provide content to give back to the - * client and return an HTTP status code (i.e. #MHD_HTTP_OK, - * #MHD_HTTP_NOT_FOUND, etc.). - * - * @param cls argument given together with the function - * pointer when the handler was registered with MHD - * @param url the requested url - * @param method the HTTP method used (#MHD_HTTP_METHOD_GET, - * #MHD_HTTP_METHOD_PUT, etc.) - * @param version the HTTP version string (i.e. - * #MHD_HTTP_VERSION_1_1) - * @param upload_data the data being uploaded (excluding HEADERS, - * for a POST that fits into memory and that is encoded - * with a supported encoding, the POST data will NOT be - * given in upload_data and is instead available as - * part of #MHD_get_connection_values; very large POST - * data *will* be made available incrementally in - * @a upload_data) - * @param upload_data_size set initially to the size of the - * @a upload_data provided; the method must update this - * value to the number of bytes NOT processed; - * @param con_cls pointer that the callback can set to some - * address and that will be preserved by MHD for future - * calls for this request; since the access handler may - * be called many times (i.e., for a PUT/POST operation - * with plenty of upload data) this allows the application - * to easily associate some request-specific state. - * If necessary, this state can be cleaned up in the - * global #MHD_RequestCompletedCallback (which - * can be set with the #MHD_OPTION_NOTIFY_COMPLETED). - * Initially, `*con_cls` will be NULL. - * @return #MHD_YES if the connection was handled successfully, - * #MHD_NO if the socket must be closed due to a serios - * error while handling the request - */ -typedef int -(*MHD_AccessHandlerCallback) (void *cls, - struct MHD_Connection *connection, - const char *url, - const char *method, - const char *version, - const char *upload_data, - size_t *upload_data_size, - void **con_cls); - - -/** - * Signature of the callback used by MHD to notify the - * application about completed requests. - * - * @param cls client-defined closure - * @param connection connection handle - * @param con_cls value as set by the last call to - * the #MHD_AccessHandlerCallback - * @param toe reason for request termination - * @see #MHD_OPTION_NOTIFY_COMPLETED - * @ingroup request - */ -typedef void -(*MHD_RequestCompletedCallback) (void *cls, - struct MHD_Connection *connection, - void **con_cls, - enum MHD_RequestTerminationCode toe); - -/** - * Signature of the callback used by MHD to notify the - * application about started/stopped connections - * - * @param cls client-defined closure - * @param connection connection handle - * @param socket_context socket-specific pointer where the - * client can associate some state specific - * to the TCP connection; note that this is - * different from the "con_cls" which is per - * HTTP request. The client can initialize - * during #MHD_CONNECTION_NOTIFY_STARTED and - * cleanup during #MHD_CONNECTION_NOTIFY_CLOSED - * and access in the meantime using - * #MHD_CONNECTION_INFO_SOCKET_CONTEXT. - * @param toe reason for connection notification - * @see #MHD_OPTION_NOTIFY_CONNECTION - * @ingroup request - */ -typedef void -(*MHD_NotifyConnectionCallback) (void *cls, - struct MHD_Connection *connection, - void **socket_context, - enum MHD_ConnectionNotificationCode toe); - - -/** - * Iterator over key-value pairs. This iterator - * can be used to iterate over all of the cookies, - * headers, or POST-data fields of a request, and - * also to iterate over the headers that have been - * added to a response. - * - * @param cls closure - * @param kind kind of the header we are looking at - * @param key key for the value, can be an empty string - * @param value corresponding value, can be NULL - * @return #MHD_YES to continue iterating, - * #MHD_NO to abort the iteration - * @ingroup request - */ -typedef int -(*MHD_KeyValueIterator) (void *cls, - enum MHD_ValueKind kind, - const char *key, - const char *value); - - -/** - * Callback used by libmicrohttpd in order to obtain content. The - * callback is to copy at most @a max bytes of content into @a buf. The - * total number of bytes that has been placed into @a buf should be - * returned. - * - * Note that returning zero will cause libmicrohttpd to try again. - * Thus, returning zero should only be used in conjunction - * with MHD_suspend_connection() to avoid busy waiting. - * - * @param cls extra argument to the callback - * @param pos position in the datastream to access; - * note that if a `struct MHD_Response` object is re-used, - * it is possible for the same content reader to - * be queried multiple times for the same data; - * however, if a `struct MHD_Response` is not re-used, - * libmicrohttpd guarantees that "pos" will be - * the sum of all non-negative return values - * obtained from the content reader so far. - * @param buf where to copy the data - * @param max maximum number of bytes to copy to @a buf (size of @a buf) - * @return number of bytes written to @a buf; - * 0 is legal unless we are running in internal select mode (since - * this would cause busy-waiting); 0 in external select mode - * will cause this function to be called again once the external - * select calls MHD again; - * #MHD_CONTENT_READER_END_OF_STREAM (-1) for the regular - * end of transmission (with chunked encoding, MHD will then - * terminate the chunk and send any HTTP footers that might be - * present; without chunked encoding and given an unknown - * response size, MHD will simply close the connection; note - * that while returning #MHD_CONTENT_READER_END_OF_STREAM is not technically - * legal if a response size was specified, MHD accepts this - * and treats it just as #MHD_CONTENT_READER_END_WITH_ERROR; - * #MHD_CONTENT_READER_END_WITH_ERROR (-2) to indicate a server - * error generating the response; this will cause MHD to simply - * close the connection immediately. If a response size was - * given or if chunked encoding is in use, this will indicate - * an error to the client. Note, however, that if the client - * does not know a response size and chunked encoding is not in - * use, then clients will not be able to tell the difference between - * #MHD_CONTENT_READER_END_WITH_ERROR and #MHD_CONTENT_READER_END_OF_STREAM. - * This is not a limitation of MHD but rather of the HTTP protocol. - */ -typedef ssize_t -(*MHD_ContentReaderCallback) (void *cls, - uint64_t pos, - char *buf, - size_t max); - - -/** - * This method is called by libmicrohttpd if we - * are done with a content reader. It should - * be used to free resources associated with the - * content reader. - * - * @param cls closure - * @ingroup response - */ -typedef void -(*MHD_ContentReaderFreeCallback) (void *cls); - - -/** - * Iterator over key-value pairs where the value - * maybe made available in increments and/or may - * not be zero-terminated. Used for processing - * POST data. - * - * @param cls user-specified closure - * @param kind type of the value, always #MHD_POSTDATA_KIND when called from MHD - * @param key 0-terminated key for the value - * @param filename name of the uploaded file, NULL if not known - * @param content_type mime-type of the data, NULL if not known - * @param transfer_encoding encoding of the data, NULL if not known - * @param data pointer to @a size bytes of data at the - * specified offset - * @param off offset of data in the overall value - * @param size number of bytes in @a data available - * @return #MHD_YES to continue iterating, - * #MHD_NO to abort the iteration - */ -typedef int -(*MHD_PostDataIterator) (void *cls, - enum MHD_ValueKind kind, - const char *key, - const char *filename, - const char *content_type, - const char *transfer_encoding, - const char *data, - uint64_t off, - size_t size); - -/* **************** Daemon handling functions ***************** */ - -/** - * Start a webserver on the given port. - * - * @param flags combination of `enum MHD_FLAG` values - * @param port port to bind to (in host byte order) - * @param apc callback to call to check which clients - * will be allowed to connect; you can pass NULL - * in which case connections from any IP will be - * accepted - * @param apc_cls extra argument to apc - * @param dh handler called for all requests (repeatedly) - * @param dh_cls extra argument to @a dh - * @param ap list of options (type-value pairs, - * terminated with #MHD_OPTION_END). - * @return NULL on error, handle to daemon on success - * @ingroup event - */ -_MHD_EXTERN struct MHD_Daemon * -MHD_start_daemon_va (unsigned int flags, - uint16_t port, - MHD_AcceptPolicyCallback apc, void *apc_cls, - MHD_AccessHandlerCallback dh, void *dh_cls, - va_list ap); - - -/** - * Start a webserver on the given port. Variadic version of - * #MHD_start_daemon_va. - * - * @param flags combination of `enum MHD_FLAG` values - * @param port port to bind to - * @param apc callback to call to check which clients - * will be allowed to connect; you can pass NULL - * in which case connections from any IP will be - * accepted - * @param apc_cls extra argument to apc - * @param dh handler called for all requests (repeatedly) - * @param dh_cls extra argument to @a dh - * @return NULL on error, handle to daemon on success - * @ingroup event - */ -_MHD_EXTERN struct MHD_Daemon * -MHD_start_daemon (unsigned int flags, - uint16_t port, - MHD_AcceptPolicyCallback apc, void *apc_cls, - MHD_AccessHandlerCallback dh, void *dh_cls, - ...); - - -/** - * Stop accepting connections from the listening socket. Allows - * clients to continue processing, but stops accepting new - * connections. Note that the caller is responsible for closing the - * returned socket; however, if MHD is run using threads (anything but - * external select mode), it must not be closed until AFTER - * #MHD_stop_daemon has been called (as it is theoretically possible - * that an existing thread is still using it). - * - * Note that some thread modes require the caller to have passed - * #MHD_USE_PIPE_FOR_SHUTDOWN when using this API. If this daemon is - * in one of those modes and this option was not given to - * #MHD_start_daemon, this function will return #MHD_INVALID_SOCKET. - * - * @param daemon daemon to stop accepting new connections for - * @return old listen socket on success, #MHD_INVALID_SOCKET if - * the daemon was already not listening anymore - * @ingroup specialized - */ -_MHD_EXTERN MHD_socket -MHD_quiesce_daemon (struct MHD_Daemon *daemon); - - -/** - * Shutdown an HTTP daemon. - * - * @param daemon daemon to stop - * @ingroup event - */ -_MHD_EXTERN void -MHD_stop_daemon (struct MHD_Daemon *daemon); - - -/** - * Add another client connection to the set of connections managed by - * MHD. This API is usually not needed (since MHD will accept inbound - * connections on the server socket). Use this API in special cases, - * for example if your HTTP server is behind NAT and needs to connect - * out to the HTTP client, or if you are building a proxy. - * - * If you use this API in conjunction with a internal select or a - * thread pool, you must set the option - * #MHD_USE_PIPE_FOR_SHUTDOWN to ensure that the freshly added - * connection is immediately processed by MHD. - * - * The given client socket will be managed (and closed!) by MHD after - * this call and must no longer be used directly by the application - * afterwards. - * - * Per-IP connection limits are ignored when using this API. - * - * @param daemon daemon that manages the connection - * @param client_socket socket to manage (MHD will expect - * to receive an HTTP request from this socket next). - * @param addr IP address of the client - * @param addrlen number of bytes in @a addr - * @return #MHD_YES on success, #MHD_NO if this daemon could - * not handle the connection (i.e. `malloc()` failed, etc). - * The socket will be closed in any case; `errno` is - * set to indicate further details about the error. - * @ingroup specialized - */ -_MHD_EXTERN int -MHD_add_connection (struct MHD_Daemon *daemon, - MHD_socket client_socket, - const struct sockaddr *addr, - socklen_t addrlen); - - -/** - * Obtain the `select()` sets for this daemon. - * Daemon's FDs will be added to fd_sets. To get only - * daemon FDs in fd_sets, call FD_ZERO for each fd_set - * before calling this function. FD_SETSIZE is assumed - * to be platform's default. - * - * @param daemon daemon to get sets from - * @param read_fd_set read set - * @param write_fd_set write set - * @param except_fd_set except set - * @param max_fd increased to largest FD added (if larger - * than existing value); can be NULL - * @return #MHD_YES on success, #MHD_NO if this - * daemon was not started with the right - * options for this call or any FD didn't - * fit fd_set. - * @ingroup event - */ -_MHD_EXTERN int -MHD_get_fdset (struct MHD_Daemon *daemon, - fd_set *read_fd_set, - fd_set *write_fd_set, - fd_set *except_fd_set, - MHD_socket *max_fd); - - -/** - * Obtain the `select()` sets for this daemon. - * Daemon's FDs will be added to fd_sets. To get only - * daemon FDs in fd_sets, call FD_ZERO for each fd_set - * before calling this function. Passing custom FD_SETSIZE - * as @a fd_setsize allow usage of larger/smaller than - * platform's default fd_sets. - * - * @param daemon daemon to get sets from - * @param read_fd_set read set - * @param write_fd_set write set - * @param except_fd_set except set - * @param max_fd increased to largest FD added (if larger - * than existing value); can be NULL - * @param fd_setsize value of FD_SETSIZE - * @return #MHD_YES on success, #MHD_NO if this - * daemon was not started with the right - * options for this call or any FD didn't - * fit fd_set. - * @ingroup event - */ -_MHD_EXTERN int -MHD_get_fdset2 (struct MHD_Daemon *daemon, - fd_set *read_fd_set, - fd_set *write_fd_set, - fd_set *except_fd_set, - MHD_socket *max_fd, - unsigned int fd_setsize); - - -/** - * Obtain the `select()` sets for this daemon. - * Daemon's FDs will be added to fd_sets. To get only - * daemon FDs in fd_sets, call FD_ZERO for each fd_set - * before calling this function. Size of fd_set is - * determined by current value of FD_SETSIZE. - * - * @param daemon daemon to get sets from - * @param read_fd_set read set - * @param write_fd_set write set - * @param except_fd_set except set - * @param max_fd increased to largest FD added (if larger - * than existing value); can be NULL - * @return #MHD_YES on success, #MHD_NO if this - * daemon was not started with the right - * options for this call or any FD didn't - * fit fd_set. - * @ingroup event - */ -#define MHD_get_fdset(daemon,read_fd_set,write_fd_set,except_fd_set,max_fd) \ - MHD_get_fdset2((daemon),(read_fd_set),(write_fd_set),(except_fd_set),(max_fd),FD_SETSIZE) - - -/** - * Obtain timeout value for `select()` for this daemon (only needed if - * connection timeout is used). The returned value is how many milliseconds - * `select()` or `poll()` should at most block, not the timeout value set for - * connections. This function MUST NOT be called if MHD is running with - * #MHD_USE_THREAD_PER_CONNECTION. - * - * @param daemon daemon to query for timeout - * @param timeout set to the timeout (in milliseconds) - * @return #MHD_YES on success, #MHD_NO if timeouts are - * not used (or no connections exist that would - * necessiate the use of a timeout right now). - * @ingroup event - */ -_MHD_EXTERN int -MHD_get_timeout (struct MHD_Daemon *daemon, - MHD_UNSIGNED_LONG_LONG *timeout); - - -/** - * Run webserver operations (without blocking unless in client - * callbacks). This method should be called by clients in combination - * with #MHD_get_fdset if the client-controlled select method is used. - * - * This function is a convenience method, which is useful if the - * fd_sets from #MHD_get_fdset were not directly passed to `select()`; - * with this function, MHD will internally do the appropriate `select()` - * call itself again. While it is always safe to call #MHD_run (in - * external select mode), you should call #MHD_run_from_select if - * performance is important (as it saves an expensive call to - * `select()`). - * - * @param daemon daemon to run - * @return #MHD_YES on success, #MHD_NO if this - * daemon was not started with the right - * options for this call. - * @ingroup event - */ -_MHD_EXTERN int -MHD_run (struct MHD_Daemon *daemon); - - -/** - * Run webserver operations. This method should be called by clients - * in combination with #MHD_get_fdset if the client-controlled select - * method is used. - * - * You can use this function instead of #MHD_run if you called - * `select()` on the result from #MHD_get_fdset. File descriptors in - * the sets that are not controlled by MHD will be ignored. Calling - * this function instead of #MHD_run is more efficient as MHD will - * not have to call `select()` again to determine which operations are - * ready. - * - * @param daemon daemon to run select loop for - * @param read_fd_set read set - * @param write_fd_set write set - * @param except_fd_set except set (not used, can be NULL) - * @return #MHD_NO on serious errors, #MHD_YES on success - * @ingroup event - */ -_MHD_EXTERN int -MHD_run_from_select (struct MHD_Daemon *daemon, - const fd_set *read_fd_set, - const fd_set *write_fd_set, - const fd_set *except_fd_set); - - - - -/* **************** Connection handling functions ***************** */ - -/** - * Get all of the headers from the request. - * - * @param connection connection to get values from - * @param kind types of values to iterate over, can be a bitmask - * @param iterator callback to call on each header; - * maybe NULL (then just count headers) - * @param iterator_cls extra argument to @a iterator - * @return number of entries iterated over - * @ingroup request - */ -_MHD_EXTERN int -MHD_get_connection_values (struct MHD_Connection *connection, - enum MHD_ValueKind kind, - MHD_KeyValueIterator iterator, - void *iterator_cls); - - -/** - * This function can be used to add an entry to the HTTP headers of a - * connection (so that the #MHD_get_connection_values function will - * return them -- and the `struct MHD_PostProcessor` will also see - * them). This maybe required in certain situations (see Mantis - * #1399) where (broken) HTTP implementations fail to supply values - * needed by the post processor (or other parts of the application). - * - * This function MUST only be called from within the - * #MHD_AccessHandlerCallback (otherwise, access maybe improperly - * synchronized). Furthermore, the client must guarantee that the key - * and value arguments are 0-terminated strings that are NOT freed - * until the connection is closed. (The easiest way to do this is by - * passing only arguments to permanently allocated strings.). - * - * @param connection the connection for which a - * value should be set - * @param kind kind of the value - * @param key key for the value - * @param value the value itself - * @return #MHD_NO if the operation could not be - * performed due to insufficient memory; - * #MHD_YES on success - * @ingroup request - */ -_MHD_EXTERN int -MHD_set_connection_value (struct MHD_Connection *connection, - enum MHD_ValueKind kind, - const char *key, - const char *value); - - -/** - * Sets the global error handler to a different implementation. @a cb - * will only be called in the case of typically fatal, serious - * internal consistency issues. These issues should only arise in the - * case of serious memory corruption or similar problems with the - * architecture. While @a cb is allowed to return and MHD will then - * try to continue, this is never safe. - * - * The default implementation that is used if no panic function is set - * simply prints an error message and calls `abort()`. Alternative - * implementations might call `exit()` or other similar functions. - * - * @param cb new error handler - * @param cls passed to @a cb - * @ingroup logging - */ -_MHD_EXTERN void -MHD_set_panic_func (MHD_PanicCallback cb, void *cls); - - -/** - * Process escape sequences ('%HH') Updates val in place; the - * result should be UTF-8 encoded and cannot be larger than the input. - * The result must also still be 0-terminated. - * - * @param val value to unescape (modified in the process) - * @return length of the resulting val (`strlen(val)` may be - * shorter afterwards due to elimination of escape sequences) - */ -_MHD_EXTERN size_t -MHD_http_unescape (char *val); - - -/** - * Get a particular header value. If multiple - * values match the kind, return any one of them. - * - * @param connection connection to get values from - * @param kind what kind of value are we looking for - * @param key the header to look for, NULL to lookup 'trailing' value without a key - * @return NULL if no such item was found - * @ingroup request - */ -_MHD_EXTERN const char * -MHD_lookup_connection_value (struct MHD_Connection *connection, - enum MHD_ValueKind kind, - const char *key); - - -/** - * Queue a response to be transmitted to the client (as soon as - * possible but after #MHD_AccessHandlerCallback returns). - * - * @param connection the connection identifying the client - * @param status_code HTTP status code (i.e. #MHD_HTTP_OK) - * @param response response to transmit - * @return #MHD_NO on error (i.e. reply already sent), - * #MHD_YES on success or if message has been queued - * @ingroup response - */ -_MHD_EXTERN int -MHD_queue_response (struct MHD_Connection *connection, - unsigned int status_code, - struct MHD_Response *response); - - -/** - * Suspend handling of network data for a given connection. This can - * be used to dequeue a connection from MHD's event loop (external - * select, internal select or thread pool; not applicable to - * thread-per-connection!) for a while. - * - * If you use this API in conjunction with a internal select or a - * thread pool, you must set the option #MHD_USE_PIPE_FOR_SHUTDOWN to - * ensure that a resumed connection is immediately processed by MHD. - * - * Suspended connections continue to count against the total number of - * connections allowed (per daemon, as well as per IP, if such limits - * are set). Suspended connections will NOT time out; timeouts will - * restart when the connection handling is resumed. While a - * connection is suspended, MHD will not detect disconnects by the - * client. - * - * The only safe time to suspend a connection is from the - * #MHD_AccessHandlerCallback. - * - * Finally, it is an API violation to call #MHD_stop_daemon while - * having suspended connections (this will at least create memory and - * socket leaks or lead to undefined behavior). You must explicitly - * resume all connections before stopping the daemon. - * - * @param connection the connection to suspend - */ -_MHD_EXTERN void -MHD_suspend_connection (struct MHD_Connection *connection); - - -/** - * Resume handling of network data for suspended connection. It is - * safe to resume a suspended connection at any time. Calling this - * function on a connection that was not previously suspended will - * result in undefined behavior. - * - * @param connection the connection to resume - */ -_MHD_EXTERN void -MHD_resume_connection (struct MHD_Connection *connection); - - -/* **************** Response manipulation functions ***************** */ - - -/** - * Flags for special handling of responses. - */ -enum MHD_ResponseFlags -{ - /** - * Default: no special flags. - */ - MHD_RF_NONE = 0, - - /** - * Only respond in conservative HTTP 1.0-mode. In particular, - * do not (automatically) sent "Connection" headers and always - * close the connection after generating the response. - */ - MHD_RF_HTTP_VERSION_1_0_ONLY = 1 - -}; - - -/** - * MHD options (for future extensions). - */ -enum MHD_ResponseOptions -{ - /** - * End of the list of options. - */ - MHD_RO_END = 0 -}; - - -/** - * Set special flags and options for a response. - * - * @param response the response to modify - * @param flags to set for the response - * @param ... #MHD_RO_END terminated list of options - * @return #MHD_YES on success, #MHD_NO on error - */ -_MHD_EXTERN int -MHD_set_response_options (struct MHD_Response *response, - enum MHD_ResponseFlags flags, - ...); - - -/** - * Create a response object. The response object can be extended with - * header information and then be used any number of times. - * - * @param size size of the data portion of the response, #MHD_SIZE_UNKNOWN for unknown - * @param block_size preferred block size for querying crc (advisory only, - * MHD may still call @a crc using smaller chunks); this - * is essentially the buffer size used for IO, clients - * should pick a value that is appropriate for IO and - * memory performance requirements - * @param crc callback to use to obtain response data - * @param crc_cls extra argument to @a crc - * @param crfc callback to call to free @a crc_cls resources - * @return NULL on error (i.e. invalid arguments, out of memory) - * @ingroup response - */ -_MHD_EXTERN struct MHD_Response * -MHD_create_response_from_callback (uint64_t size, - size_t block_size, - MHD_ContentReaderCallback crc, void *crc_cls, - MHD_ContentReaderFreeCallback crfc); - - -/** - * Create a response object. The response object can be extended with - * header information and then be used any number of times. - * - * @param size size of the @a data portion of the response - * @param data the data itself - * @param must_free libmicrohttpd should free data when done - * @param must_copy libmicrohttpd must make a copy of @a data - * right away, the data maybe released anytime after - * this call returns - * @return NULL on error (i.e. invalid arguments, out of memory) - * @deprecated use #MHD_create_response_from_buffer instead - * @ingroup response - */ -_MHD_DEPR_FUNC("MHD_create_response_from_data() is deprecated, use MHD_create_response_from_buffer()") \ -_MHD_EXTERN struct MHD_Response * -MHD_create_response_from_data (size_t size, - void *data, - int must_free, - int must_copy); - - -/** - * Specification for how MHD should treat the memory buffer - * given for the response. - * @ingroup response - */ -enum MHD_ResponseMemoryMode -{ - - /** - * Buffer is a persistent (static/global) buffer that won't change - * for at least the lifetime of the response, MHD should just use - * it, not free it, not copy it, just keep an alias to it. - * @ingroup response - */ - MHD_RESPMEM_PERSISTENT, - - /** - * Buffer is heap-allocated with `malloc()` (or equivalent) and - * should be freed by MHD after processing the response has - * concluded (response reference counter reaches zero). - * @ingroup response - */ - MHD_RESPMEM_MUST_FREE, - - /** - * Buffer is in transient memory, but not on the heap (for example, - * on the stack or non-`malloc()` allocated) and only valid during the - * call to #MHD_create_response_from_buffer. MHD must make its - * own private copy of the data for processing. - * @ingroup response - */ - MHD_RESPMEM_MUST_COPY - -}; - - -/** - * Create a response object. The response object can be extended with - * header information and then be used any number of times. - * - * @param size size of the data portion of the response - * @param buffer size bytes containing the response's data portion - * @param mode flags for buffer management - * @return NULL on error (i.e. invalid arguments, out of memory) - * @ingroup response - */ -_MHD_EXTERN struct MHD_Response * -MHD_create_response_from_buffer (size_t size, - void *buffer, - enum MHD_ResponseMemoryMode mode); - - -/** - * Create a response object. The response object can be extended with - * header information and then be used any number of times. - * - * @param size size of the data portion of the response - * @param fd file descriptor referring to a file on disk with the - * data; will be closed when response is destroyed; - * fd should be in 'blocking' mode - * @return NULL on error (i.e. invalid arguments, out of memory) - * @ingroup response - */ -_MHD_EXTERN struct MHD_Response * -MHD_create_response_from_fd (size_t size, - int fd); - - -/** - * Create a response object. The response object can be extended with - * header information and then be used any number of times. - * - * @param size size of the data portion of the response; - * sizes larger than 2 GiB may be not supported by OS or - * MHD build; see ::MHD_FEATURE_LARGE_FILE - * @param fd file descriptor referring to a file on disk with the - * data; will be closed when response is destroyed; - * fd should be in 'blocking' mode - * @return NULL on error (i.e. invalid arguments, out of memory) - * @ingroup response - */ -_MHD_EXTERN struct MHD_Response * -MHD_create_response_from_fd64 (uint64_t size, - int fd); - - -/** - * Create a response object. The response object can be extended with - * header information and then be used any number of times. - * - * @param size size of the data portion of the response - * @param fd file descriptor referring to a file on disk with the - * data; will be closed when response is destroyed; - * fd should be in 'blocking' mode - * @param offset offset to start reading from in the file; - * Be careful! `off_t` may have been compiled to be a - * 64-bit variable for MHD, in which case your application - * also has to be compiled using the same options! Read - * the MHD manual for more details. - * @return NULL on error (i.e. invalid arguments, out of memory) - * @ingroup response - */ -_MHD_DEPR_FUNC("Function MHD_create_response_from_fd_at_offset() is deprecated, use MHD_create_response_from_fd_at_offset64()") \ -_MHD_EXTERN struct MHD_Response * -MHD_create_response_from_fd_at_offset (size_t size, - int fd, - off_t offset); - -#if !defined(_MHD_NO_DEPR_IN_MACRO) || defined(_MHD_NO_DEPR_FUNC) -/* Substitute MHD_create_response_from_fd_at_offset64() instead of MHD_create_response_from_fd_at_offset() - to minimize potential problems with different off_t sizes */ -#define MHD_create_response_from_fd_at_offset(size,fd,offset) \ - _MHD_DEPR_IN_MACRO("Usage of MHD_create_response_from_fd_at_offset() is deprecated, use MHD_create_response_from_fd_at_offset64()") \ - MHD_create_response_from_fd_at_offset64((size),(fd),(offset)) -#endif /* !_MHD_NO_DEPR_IN_MACRO || _MHD_NO_DEPR_FUNC */ - - -/** - * Create a response object. The response object can be extended with - * header information and then be used any number of times. - * - * @param size size of the data portion of the response; - * sizes larger than 2 GiB may be not supported by OS or - * MHD build; see ::MHD_FEATURE_LARGE_FILE - * @param fd file descriptor referring to a file on disk with the - * data; will be closed when response is destroyed; - * fd should be in 'blocking' mode - * @param offset offset to start reading from in the file; - * reading file beyond 2 GiB may be not supported by OS or - * MHD build; see ::MHD_FEATURE_LARGE_FILE - * @return NULL on error (i.e. invalid arguments, out of memory) - * @ingroup response - */ -_MHD_EXTERN struct MHD_Response * -MHD_create_response_from_fd_at_offset64 (uint64_t size, - int fd, - uint64_t offset); - - -#if 0 -/** - * Enumeration for actions MHD should perform on the underlying socket - * of the upgrade. This API is not finalized, and in particular - * the final set of actions is yet to be decided. This is just an - * idea for what we might want. - */ -enum MHD_UpgradeAction -{ - - /** - * Close the socket, the application is done with it. - * - * Takes no extra arguments. - */ - MHD_UPGRADE_ACTION_CLOSE = 0, - - /** - * Uncork the TCP write buffer (that is, tell the OS to transmit all - * bytes in the buffer now, and to not use TCP-CORKing). - * - * Takes no extra arguments. - * - * NOTE: it is unclear if we want to have this in the - * "final" API, this is just an idea right now. - */ - MHD_UPGRADE_ACTION_CORK - -}; - - -/** - * Handle given to the application to manage special - * actions relating to MHD responses that "upgrade" - * the HTTP protocol (i.e. to WebSockets). - */ -struct MHD_UpgradeResponseHandle; - - -/** - * This connection-specific callback is provided by MHD to - * applications (unusual) during the #MHD_UpgradeHandler. - * It allows applications to perform 'special' actions on - * the underlying socket from the upgrade. - * - * @param urh the handle identifying the connection to perform - * the upgrade @a action on. - * @param action which action should be performed - * @param ... arguments to the action (depends on the action) - * @return #MHD_NO on error, #MHD_YES on success - */ -_MHD_EXTERN int -MHD_upgrade_action (struct MHD_UpgradeResponseHandle *urh, - enum MHD_UpgradeAction action, - ...); - - -/** - * Function called after a protocol "upgrade" response was sent - * successfully and the socket should now be controlled by some - * protocol other than HTTP. - * - * Any data received on the socket will be made available in - * 'data_in'. The function should update 'data_in_size' to - * reflect the number of bytes consumed from 'data_in' (the remaining - * bytes will be made available in the next call to the handler). - * - * Any data that should be transmitted on the socket should be - * stored in 'data_out'. '*data_out_size' is initially set to - * the available buffer space in 'data_out'. It should be set to - * the number of bytes stored in 'data_out' (which can be zero). - * - * The return value is a BITMASK that indicates how the function - * intends to interact with the event loop. It can request to be - * notified for reading, writing, request to UNCORK the send buffer - * (which MHD is allowed to ignore, if it is not possible to uncork on - * the local platform), to wait for the 'external' select loop to - * trigger another round. It is also possible to specify "no events" - * to terminate the connection; in this case, the - * #MHD_RequestCompletedCallback will be called and all resources of - * the connection will be released. - * - * Except when in 'thread-per-connection' mode, implementations - * of this function should never block (as it will still be called - * from within the main event loop). - * - * @param cls closure, whatever was given to #MHD_create_response_for_upgrade(). - * @param connection original HTTP connection handle, - * giving the function a last chance - * to inspect the original HTTP request - * @param extra_in if we happened to have read bytes after the - * HTTP header already (because the client sent - * more than the HTTP header of the request before - * we sent the upgrade response), - * these are the extra bytes already read from @a sock - * by MHD. The application should treat these as if - * it had read them from @a sock. - * @param extra_in_size number of bytes in @a extra_in - * @param sock socket to use for bi-directional communication - * with the client. For HTTPS, this may not be a socket - * that is directly connected to the client and thus certain - * operations (TCP-specific setsockopt(), getsockopt(), etc.) - * may not work as expected (as the socket could be from a - * socketpair() or a TCP-loopback) - * @param urh argument for #MHD_upgrade_action()s on this @a connection. - * Applications must eventually use this callback to perform the - * close() action on the @a sock. - */ -typedef void -(*MHD_UpgradeHandler)(void *cls, - struct MHD_Connection *connection, - const char *extra_in, - size_t extra_in_size, - MHD_SOCKET sock, - struct MHD_UpgradeResponseHandle *urh); - - -/** - * Create a response object that can be used for 101 UPGRADE - * responses, for example to implement WebSockets. After sending the - * response, control over the data stream is given to the callback (which - * can then, for example, start some bi-directional communication). - * If the response is queued for multiple connections, the callback - * will be called for each connection. The callback - * will ONLY be called after the response header was successfully passed - * to the OS; if there are communication errors before, the usual MHD - * connection error handling code will be performed. - * - * Setting the correct HTTP code (i.e. MHD_HTTP_SWITCHING_PROTOCOLS) - * and setting correct HTTP headers for the upgrade must be done - * manually (this way, it is possible to implement most existing - * WebSocket versions using this API; in fact, this API might be useful - * for any protocol switch, not just WebSockets). Note that - * draft-ietf-hybi-thewebsocketprotocol-00 cannot be implemented this - * way as the header "HTTP/1.1 101 WebSocket Protocol Handshake" - * cannot be generated; instead, MHD will always produce "HTTP/1.1 101 - * Switching Protocols" (if the response code 101 is used). - * - * As usual, the response object can be extended with header - * information and then be used any number of times (as long as the - * header information is not connection-specific). - * - * @param upgrade_handler function to call with the 'upgraded' socket - * @param upgrade_handler_cls closure for @a upgrade_handler - * @return NULL on error (i.e. invalid arguments, out of memory) - */ -_MHD_EXTERN struct MHD_Response * -MHD_create_response_for_upgrade (MHD_UpgradeHandler upgrade_handler, - void *upgrade_handler_cls); -#endif - -/** - * Destroy a response object and associated resources. Note that - * libmicrohttpd may keep some of the resources around if the response - * is still in the queue for some clients, so the memory may not - * necessarily be freed immediatley. - * - * @param response response to destroy - * @ingroup response - */ -_MHD_EXTERN void -MHD_destroy_response (struct MHD_Response *response); - - -/** - * Add a header line to the response. - * - * @param response response to add a header to - * @param header the header to add - * @param content value to add - * @return #MHD_NO on error (i.e. invalid header or content format), - * or out of memory - * @ingroup response - */ -_MHD_EXTERN int -MHD_add_response_header (struct MHD_Response *response, - const char *header, - const char *content); - - -/** - * Add a footer line to the response. - * - * @param response response to remove a header from - * @param footer the footer to delete - * @param content value to delete - * @return #MHD_NO on error (i.e. invalid footer or content format). - * @ingroup response - */ -_MHD_EXTERN int -MHD_add_response_footer (struct MHD_Response *response, - const char *footer, - const char *content); - - -/** - * Delete a header (or footer) line from the response. - * - * @param response response to remove a header from - * @param header the header to delete - * @param content value to delete - * @return #MHD_NO on error (no such header known) - * @ingroup response - */ -_MHD_EXTERN int -MHD_del_response_header (struct MHD_Response *response, - const char *header, - const char *content); - - -/** - * Get all of the headers (and footers) added to a response. - * - * @param response response to query - * @param iterator callback to call on each header; - * maybe NULL (then just count headers) - * @param iterator_cls extra argument to @a iterator - * @return number of entries iterated over - * @ingroup response - */ -_MHD_EXTERN int -MHD_get_response_headers (struct MHD_Response *response, - MHD_KeyValueIterator iterator, void *iterator_cls); - - -/** - * Get a particular header (or footer) from the response. - * - * @param response response to query - * @param key which header to get - * @return NULL if header does not exist - * @ingroup response - */ -_MHD_EXTERN const char * -MHD_get_response_header (struct MHD_Response *response, - const char *key); - - -/* ********************** PostProcessor functions ********************** */ - -/** - * Create a `struct MHD_PostProcessor`. - * - * A `struct MHD_PostProcessor` can be used to (incrementally) parse - * the data portion of a POST request. Note that some buggy browsers - * fail to set the encoding type. If you want to support those, you - * may have to call #MHD_set_connection_value with the proper encoding - * type before creating a post processor (if no supported encoding - * type is set, this function will fail). - * - * @param connection the connection on which the POST is - * happening (used to determine the POST format) - * @param buffer_size maximum number of bytes to use for - * internal buffering (used only for the parsing, - * specifically the parsing of the keys). A - * tiny value (256-1024) should be sufficient. - * Do NOT use a value smaller than 256. For good - * performance, use 32 or 64k (i.e. 65536). - * @param iter iterator to be called with the parsed data, - * Must NOT be NULL. - * @param iter_cls first argument to @a iter - * @return NULL on error (out of memory, unsupported encoding), - * otherwise a PP handle - * @ingroup request - */ -_MHD_EXTERN struct MHD_PostProcessor * -MHD_create_post_processor (struct MHD_Connection *connection, - size_t buffer_size, - MHD_PostDataIterator iter, void *iter_cls); - - -/** - * Parse and process POST data. Call this function when POST data is - * available (usually during an #MHD_AccessHandlerCallback) with the - * "upload_data" and "upload_data_size". Whenever possible, this will - * then cause calls to the #MHD_PostDataIterator. - * - * @param pp the post processor - * @param post_data @a post_data_len bytes of POST data - * @param post_data_len length of @a post_data - * @return #MHD_YES on success, #MHD_NO on error - * (out-of-memory, iterator aborted, parse error) - * @ingroup request - */ -_MHD_EXTERN int -MHD_post_process (struct MHD_PostProcessor *pp, - const char *post_data, size_t post_data_len); - - -/** - * Release PostProcessor resources. - * - * @param pp the PostProcessor to destroy - * @return #MHD_YES if processing completed nicely, - * #MHD_NO if there were spurious characters / formatting - * problems; it is common to ignore the return - * value of this function - * @ingroup request - */ -_MHD_EXTERN int -MHD_destroy_post_processor (struct MHD_PostProcessor *pp); - - -/* ********************* Digest Authentication functions *************** */ - - -/** - * Constant to indicate that the nonce of the provided - * authentication code was wrong. - * @ingroup authentication - */ -#define MHD_INVALID_NONCE -1 - - -/** - * Get the username from the authorization header sent by the client - * - * @param connection The MHD connection structure - * @return NULL if no username could be found, a pointer - * to the username if found - * @ingroup authentication - */ -_MHD_EXTERN char * -MHD_digest_auth_get_username (struct MHD_Connection *connection); - - -/** - * Authenticates the authorization header sent by the client - * - * @param connection The MHD connection structure - * @param realm The realm presented to the client - * @param username The username needs to be authenticated - * @param password The password used in the authentication - * @param nonce_timeout The amount of time for a nonce to be - * invalid in seconds - * @return #MHD_YES if authenticated, #MHD_NO if not, - * #MHD_INVALID_NONCE if nonce is invalid - * @ingroup authentication - */ -_MHD_EXTERN int -MHD_digest_auth_check (struct MHD_Connection *connection, - const char *realm, - const char *username, - const char *password, - unsigned int nonce_timeout); - - -/** - * Queues a response to request authentication from the client - * - * @param connection The MHD connection structure - * @param realm The realm presented to the client - * @param opaque string to user for opaque value - * @param response reply to send; should contain the "access denied" - * body; note that this function will set the "WWW Authenticate" - * header and that the caller should not do this - * @param signal_stale #MHD_YES if the nonce is invalid to add - * 'stale=true' to the authentication header - * @return #MHD_YES on success, #MHD_NO otherwise - * @ingroup authentication - */ -_MHD_EXTERN int -MHD_queue_auth_fail_response (struct MHD_Connection *connection, - const char *realm, - const char *opaque, - struct MHD_Response *response, - int signal_stale); - - -/** - * Get the username and password from the basic authorization header sent by the client - * - * @param connection The MHD connection structure - * @param password a pointer for the password - * @return NULL if no username could be found, a pointer - * to the username if found - * @ingroup authentication - */ -_MHD_EXTERN char * -MHD_basic_auth_get_username_password (struct MHD_Connection *connection, - char** password); - - -/** - * Queues a response to request basic authentication from the client - * The given response object is expected to include the payload for - * the response; the "WWW-Authenticate" header will be added and the - * response queued with the 'UNAUTHORIZED' status code. - * - * @param connection The MHD connection structure - * @param realm the realm presented to the client - * @param response response object to modify and queue - * @return #MHD_YES on success, #MHD_NO otherwise - * @ingroup authentication - */ -_MHD_EXTERN int -MHD_queue_basic_auth_fail_response (struct MHD_Connection *connection, - const char *realm, - struct MHD_Response *response); - -/* ********************** generic query functions ********************** */ - - -/** - * Obtain information about the given connection. - * - * @param connection what connection to get information about - * @param info_type what information is desired? - * @param ... depends on @a info_type - * @return NULL if this information is not available - * (or if the @a info_type is unknown) - * @ingroup specialized - */ -_MHD_EXTERN const union MHD_ConnectionInfo * -MHD_get_connection_info (struct MHD_Connection *connection, - enum MHD_ConnectionInfoType info_type, - ...); - - -/** - * MHD connection options. Given to #MHD_set_connection_option to - * set custom options for a particular connection. - */ -enum MHD_CONNECTION_OPTION -{ - - /** - * Set a custom timeout for the given connection. Specified - * as the number of seconds, given as an `unsigned int`. Use - * zero for no timeout. - */ - MHD_CONNECTION_OPTION_TIMEOUT - -}; - - -/** - * Set a custom option for the given connection, overriding defaults. - * - * @param connection connection to modify - * @param option option to set - * @param ... arguments to the option, depending on the option type - * @return #MHD_YES on success, #MHD_NO if setting the option failed - * @ingroup specialized - */ -_MHD_EXTERN int -MHD_set_connection_option (struct MHD_Connection *connection, - enum MHD_CONNECTION_OPTION option, - ...); - - -/** - * Information about an MHD daemon. - */ -union MHD_DaemonInfo -{ - /** - * Size of the key, no longer supported. - * @deprecated - */ - size_t key_size; - - /** - * Size of the mac key, no longer supported. - * @deprecated - */ - size_t mac_key_size; - - /** - * Listen socket file descriptor, for #MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY - * and #MHD_DAEMON_INFO_LISTEN_FD. - */ - MHD_socket listen_fd; - - /** - * Number of active connections, for #MHD_DAEMON_INFO_CURRENT_CONNECTIONS. - */ - unsigned int num_connections; -}; - - -/** - * Obtain information about the given daemon - * (not fully implemented!). - * - * @param daemon what daemon to get information about - * @param info_type what information is desired? - * @param ... depends on @a info_type - * @return NULL if this information is not available - * (or if the @a info_type is unknown) - * @ingroup specialized - */ -_MHD_EXTERN const union MHD_DaemonInfo * -MHD_get_daemon_info (struct MHD_Daemon *daemon, - enum MHD_DaemonInfoType info_type, - ...); - - -/** - * Obtain the version of this library - * - * @return static version string, e.g. "0.9.9" - * @ingroup specialized - */ -_MHD_EXTERN const char* -MHD_get_version (void); - - -/** - * Types of information about MHD features, - * used by #MHD_is_feature_supported(). - */ -enum MHD_FEATURE -{ - /** - * Get whether messages are supported. If supported then in debug - * mode messages can be printed to stderr or to external logger. - */ - MHD_FEATURE_MESSGES = 1, - - /** - * Get whether HTTPS is supported. If supported then flag - * #MHD_USE_SSL and options #MHD_OPTION_HTTPS_MEM_KEY, - * #MHD_OPTION_HTTPS_MEM_CERT, #MHD_OPTION_HTTPS_MEM_TRUST, - * #MHD_OPTION_HTTPS_MEM_DHPARAMS, #MHD_OPTION_HTTPS_CRED_TYPE, - * #MHD_OPTION_HTTPS_PRIORITIES can be used. - */ - MHD_FEATURE_SSL = 2, - - /** - * Get whether option #MHD_OPTION_HTTPS_CERT_CALLBACK is - * supported. - */ - MHD_FEATURE_HTTPS_CERT_CALLBACK = 3, - - /** - * Get whether IPv6 is supported. If supported then flag - * #MHD_USE_IPv6 can be used. - */ - MHD_FEATURE_IPv6 = 4, - - /** - * Get whether IPv6 without IPv4 is supported. If not supported - * then IPv4 is always enabled in IPv6 sockets and - * flag #MHD_USE_DUAL_STACK if always used when #MHD_USE_IPv6 is - * specified. - */ - MHD_FEATURE_IPv6_ONLY = 5, - - /** - * Get whether `poll()` is supported. If supported then flag - * #MHD_USE_POLL can be used. - */ - MHD_FEATURE_POLL = 6, - - /** - * Get whether `epoll()` is supported. If supported then Flags - * #MHD_USE_EPOLL and - * #MHD_USE_EPOLL_INTERNALLY can be used. - */ - MHD_FEATURE_EPOLL = 7, - - /** - * Get whether shutdown on listen socket to signal other - * threads is supported. If not supported flag - * #MHD_USE_PIPE_FOR_SHUTDOWN is automatically forced. - */ - MHD_FEATURE_SHUTDOWN_LISTEN_SOCKET = 8, - - /** - * Get whether socketpair is used internally instead of pipe to - * signal other threads. - */ - MHD_FEATURE_SOCKETPAIR = 9, - - /** - * Get whether TCP Fast Open is supported. If supported then - * flag #MHD_USE_TCP_FASTOPEN and option - * #MHD_OPTION_TCP_FASTOPEN_QUEUE_SIZE can be used. - */ - MHD_FEATURE_TCP_FASTOPEN = 10, - - /** - * Get whether HTTP Basic authorization is supported. If supported - * then functions #MHD_basic_auth_get_username_password and - * #MHD_queue_basic_auth_fail_response can be used. - */ - MHD_FEATURE_BASIC_AUTH = 11, - - /** - * Get whether HTTP Digest authorization is supported. If - * supported then options #MHD_OPTION_DIGEST_AUTH_RANDOM, - * #MHD_OPTION_NONCE_NC_SIZE and - * #MHD_digest_auth_check() can be used. - */ - MHD_FEATURE_DIGEST_AUTH = 12, - - /** - * Get whether postprocessor is supported. If supported then - * functions #MHD_create_post_processor(), #MHD_post_process() and - * #MHD_destroy_post_processor() can - * be used. - */ - MHD_FEATURE_POSTPROCESSOR = 13, - - /** - * Get whether password encrypted private key for HTTPS daemon is - * supported. If supported then option - * ::MHD_OPTION_HTTPS_KEY_PASSWORD can be used. - */ - MHD_FEATURE_HTTPS_KEY_PASSWORD = 14, - - /** - * Get whether reading files beyond 2 GiB boundary is supported. - * If supported then #MHD_create_response_from_fd(), - * #MHD_create_response_from_fd64 #MHD_create_response_from_fd_at_offset() - * and #MHD_create_response_from_fd_at_offset64() can be used with sizes and - * offsets larger than 2 GiB. If not supported value of size+offset is - * limited to 2 GiB. - */ - MHD_FEATURE_LARGE_FILE = 15, - - /** - * Get whether MHD set names on generated threads. - */ - MHD_THREAD_NAMES = 16 -}; - - -/** - * Get information about supported MHD features. - * Indicate that MHD was compiled with or without support for - * particular feature. Some features require additional support - * by kernel. Kernel support is not checked by this function. - * - * @param feature type of requested information - * @return #MHD_YES if feature is supported by MHD, #MHD_NO if - * feature is not supported or feature is unknown. - * @ingroup specialized - */ -_MHD_EXTERN int -MHD_is_feature_supported (enum MHD_FEATURE feature); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -#endif diff --git a/minethd.cpp b/minethd.cpp index 199779ee..5c7871d2 100644 --- a/minethd.cpp +++ b/minethd.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "console.h" @@ -42,15 +43,23 @@ void thd_setaffinity(std::thread::native_handle_type h, uint64_t cpu_id) #include #include #define SYSCTL_CORE_COUNT "machdep.cpu.core_count" +#elif defined(__FreeBSD__) +#include #endif + void thd_setaffinity(std::thread::native_handle_type h, uint64_t cpu_id) { #if defined(__APPLE__) thread_port_t mach_thread; - thread_affinity_policy_data_t policy = { cpu_id }; + thread_affinity_policy_data_t policy = { static_cast(cpu_id) }; mach_thread = pthread_mach_thread_np(h); thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, 1); +#elif defined(__FreeBSD__) + cpuset_t mn; + CPU_ZERO(&mn); + CPU_SET(cpu_id, &mn); + pthread_setaffinity_np(h, sizeof(cpuset_t), &mn); #else cpu_set_t mn; CPU_ZERO(&mn); @@ -64,6 +73,7 @@ void thd_setaffinity(std::thread::native_handle_type h, uint64_t cpu_id) #include "minethd.h" #include "jconf.h" #include "crypto/cryptonight_aesni.h" +#include "hwlocMemory.hpp" telemetry::telemetry(size_t iThd) { @@ -140,7 +150,7 @@ void telemetry::push_perf_value(size_t iThd, uint64_t iHashCount, uint64_t iTime iBucketTop[iThd] = (iTop + 1) & iBucketMask; } -minethd::minethd(miner_work& pWork, size_t iNo, bool double_work, bool no_prefetch) +minethd::minethd(miner_work& pWork, size_t iNo, bool double_work, bool no_prefetch, int64_t affinity) { oWork = pWork; bQuit = 0; @@ -149,6 +159,7 @@ minethd::minethd(miner_work& pWork, size_t iNo, bool double_work, bool no_prefet iHashCount = 0; iTimestamp = 0; bNoPrefetch = no_prefetch; + this->affinity = affinity; if(double_work) oWorkThd = std::thread(&minethd::double_work_main, this); @@ -295,16 +306,7 @@ std::vector* minethd::thread_starter(miner_work& pWork) { jconf::inst()->GetThreadConfig(i, cfg); - minethd* thd = new minethd(pWork, i, cfg.bDoubleMode, cfg.bNoPrefetch); - - if(cfg.iCpuAff >= 0) - { -#if defined(__APPLE__) - printer::inst()->print_msg(L1, "WARNING on MacOS thread affinity is only advisory."); -#endif - thd_setaffinity(thd->oWorkThd.native_handle(), cfg.iCpuAff); - } - + minethd* thd = new minethd(pWork, i, cfg.bDoubleMode, cfg.bNoPrefetch, cfg.iCpuAff); pvThreads->push_back(thd); if(cfg.iCpuAff >= 0) @@ -359,8 +361,22 @@ minethd::cn_hash_fun minethd::func_selector(bool bHaveAes, bool bNoPrefetch) return func_table[digit.to_ulong()]; } +void minethd::pin_thd_affinity() +{ + // pin memory to NUMA node + bindMemoryToNUMANode(affinity); + +#if defined(__APPLE__) + printer::inst()->print_msg(L1, "WARNING on MacOS thread affinity is only advisory."); +#endif + thd_setaffinity(oWorkThd.native_handle(), affinity); +} + void minethd::work_main() { + if(affinity >= 0) //-1 means no affinity + pin_thd_affinity(); + cn_hash_fun hash_fun; cryptonight_ctx* ctx; uint64_t iCount = 0; @@ -448,6 +464,9 @@ minethd::cn_hash_fun_dbl minethd::func_dbl_selector(bool bHaveAes, bool bNoPrefe void minethd::double_work_main() { + if(affinity >= 0) //-1 means no affinity + pin_thd_affinity(); + cn_hash_fun_dbl hash_fun; cryptonight_ctx* ctx0; cryptonight_ctx* ctx1; diff --git a/minethd.h b/minethd.h index 6ba269ef..3c88c267 100644 --- a/minethd.h +++ b/minethd.h @@ -101,7 +101,7 @@ class minethd typedef void (*cn_hash_fun)(const void*, size_t, void*, cryptonight_ctx*); typedef void (*cn_hash_fun_dbl)(const void*, size_t, void*, cryptonight_ctx* __restrict, cryptonight_ctx* __restrict); - minethd(miner_work& pWork, size_t iNo, bool double_work, bool no_prefetch); + minethd(miner_work& pWork, size_t iNo, bool double_work, bool no_prefetch, int64_t affinity); // We use the top 10 bits of the nonce for thread and resume // This allows us to resume up to 128 threads 4 times before @@ -129,8 +129,11 @@ class minethd static miner_work oGlobalWork; miner_work oWork; + void pin_thd_affinity(); + std::thread oWorkThd; uint8_t iThreadNo; + int64_t affinity; bool bQuit; bool bNoPrefetch; diff --git a/msgstruct.h b/msgstruct.h index d3b17096..6f4a6fbe 100644 --- a/msgstruct.h +++ b/msgstruct.h @@ -41,7 +41,7 @@ struct job_result enum ex_event_name { EV_INVALID_VAL, EV_SOCK_READY, EV_SOCK_ERROR, EV_POOL_HAVE_JOB, EV_MINER_HAVE_RESULT, EV_PERF_TICK, EV_RECONNECT, EV_SWITCH_POOL, EV_DEV_POOL_EXIT, EV_USR_HASHRATE, EV_USR_RESULTS, EV_USR_CONNSTAT, - EV_HASHRATE_LOOP, EV_HTML_HASHRATE, EV_HTML_RESULTS, EV_HTML_CONNSTAT }; + EV_HASHRATE_LOOP, EV_HTML_HASHRATE, EV_HTML_RESULTS, EV_HTML_CONNSTAT, EV_HTML_JSON }; /* This is how I learned to stop worrying and love c++11 =). diff --git a/socket.cpp b/socket.cpp index 565eb766..52f46b54 100644 --- a/socket.cpp +++ b/socket.cpp @@ -56,7 +56,10 @@ bool plain_socket::set_hostname(const char* sAddr) sAddrMb[ln] = '\0'; if ((sTmp = strstr(sAddrMb, "//")) != nullptr) + { + sTmp += 2; memmove(sAddrMb, sTmp, strlen(sTmp) + 1); + } if ((sPort = strchr(sAddrMb, ':')) == nullptr) return pCallback->set_socket_error("CONNECT error: Pool port number not specified, please use format :."); @@ -75,33 +78,34 @@ bool plain_socket::set_hostname(const char* sAddr) return pCallback->set_socket_error_strerr("CONNECT error: GetAddrInfo: ", err); addrinfo *ptr = pAddrRoot; - addrinfo *ipv4 = nullptr, *ipv6 = nullptr; + std::vector ipv4; + std::vector ipv6; while (ptr != nullptr) { if (ptr->ai_family == AF_INET) - ipv4 = ptr; + ipv4.push_back(ptr); if (ptr->ai_family == AF_INET6) - ipv6 = ptr; + ipv6.push_back(ptr); ptr = ptr->ai_next; } - if (ipv4 == nullptr && ipv6 == nullptr) + if (ipv4.empty() && ipv6.empty()) { freeaddrinfo(pAddrRoot); pAddrRoot = nullptr; return pCallback->set_socket_error("CONNECT error: I found some DNS records but no IPv4 or IPv6 addresses."); } - else if (ipv4 != nullptr && ipv6 == nullptr) - pSockAddr = ipv4; - else if (ipv4 == nullptr && ipv6 != nullptr) - pSockAddr = ipv6; - else if (ipv4 != nullptr && ipv6 != nullptr) + else if (!ipv4.empty() && ipv6.empty()) + pSockAddr = ipv4[rand() % ipv4.size()]; + else if (ipv4.empty() && !ipv6.empty()) + pSockAddr = ipv6[rand() % ipv6.size()]; + else if (!ipv4.empty() && !ipv6.empty()) { if(jconf::inst()->PreferIpv4()) - pSockAddr = ipv4; + pSockAddr = ipv4[rand() % ipv4.size()]; else - pSockAddr = ipv6; + pSockAddr = ipv6[rand() % ipv6.size()]; } hSocket = socket(pSockAddr->ai_family, pSockAddr->ai_socktype, pSockAddr->ai_protocol); diff --git a/socks.h b/socks.h index 77687065..82bfa2fc 100644 --- a/socks.h +++ b/socks.h @@ -60,6 +60,9 @@ inline const char* sock_gai_strerror(int err, char* buf, size_t len) #include /* Needed for close() */ #include #include +#if defined(__FreeBSD__) +#include /* Needed for IPPROTO_TCP */ +#endif inline void sock_init() {} typedef int SOCKET; @@ -76,7 +79,9 @@ inline void sock_close(SOCKET s) inline const char* sock_strerror(char* buf, size_t len) { buf[0] = '\0'; -#if defined(__APPLE__) + +#if defined(__APPLE__) || defined(__FreeBSD__) || !defined(_GNU_SOURCE) || !defined(__GLIBC__) + strerror_r(errno, buf, len); return buf; #else diff --git a/version.h b/version.h new file mode 100644 index 00000000..ab3d14aa --- /dev/null +++ b/version.h @@ -0,0 +1,4 @@ +#pragma once + +#define XMR_STAK_NAME "xmr-stak-cpu" +#define XMR_STAK_VERSION "1.3.0-1.5.0" diff --git a/webdesign.cpp b/webdesign.cpp index 958d3120..e07b0156 100644 --- a/webdesign.cpp +++ b/webdesign.cpp @@ -27,12 +27,12 @@ extern const char sHtmlCssFile [] = "a:active {" "color: rgb(204, 122, 0);" "}" - + ".all {" "max-width:600px;" "margin: auto;" "}" - + ".header {" "background-color: rgb(30, 30, 30);" "color: white;" @@ -167,6 +167,41 @@ extern const char sHtmlResultBodyHigh [] = extern const char sHtmlResultTableRow [] = "%s%llu%s"; -extern const char sHtmlResultBodyLow [] = +extern const char sHtmlResultBodyLow[] = ""; +extern const char sJsonApiThdHashrate[] = + "[%s,%s,%s]"; + +extern const char sJsonApiResultError[] = + "{\"count\":%llu,\"last_seen\":%llu,\"text\":\"%s\"}"; + +extern const char sJsonApiConnectionError[] = + "{\"last_seen\":%llu,\"text\":\"%s\"}"; + +extern const char sJsonApiFormat [] = +"{" + "\"hashrate\":{" + "\"threads\":[%s]," + "\"total\":%s," + "\"highest\":%s" + "}," + + "\"results\":{" + "\"diff_current\":%llu," + "\"shares_good\":%llu," + "\"shares_total\":%llu," + "\"avg_time\":%.1f," + "\"hashes_total\":%llu," + "\"best\":[%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu]," + "\"error_log\":[%s]" + "}," + + "\"connection\":{" + "\"pool\": \"%s\"," + "\"uptime\":%llu," + "\"ping\":%llu," + "\"error_log\":[%s]" + "}" +"}"; + diff --git a/webdesign.h b/webdesign.h index a516afbc..92639a03 100644 --- a/webdesign.h +++ b/webdesign.h @@ -17,3 +17,8 @@ extern const char sHtmlConnectionBodyLow[]; extern const char sHtmlResultBodyHigh[]; extern const char sHtmlResultTableRow[]; extern const char sHtmlResultBodyLow[]; + +extern const char sJsonApiThdHashrate[]; +extern const char sJsonApiResultError[]; +extern const char sJsonApiConnectionError[]; +extern const char sJsonApiFormat[]; diff --git a/xmr-stak-cpu.cbp b/xmr-stak-cpu.cbp index 6d8553c4..c2f3774f 100644 --- a/xmr-stak-cpu.cbp +++ b/xmr-stak-cpu.cbp @@ -67,8 +67,10 @@ + + @@ -107,6 +109,7 @@ +