diff --git a/.gitignore b/.gitignore index 3b16b614e3d3ca02b8f08edad4c171c72b5de8ae..df8065dfdd6cc533826459bcbc71a4768d7911a1 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,7 @@ xcuserdata # svn & cvs .svn CVS - +reports/* doc/html CMakeLists.txt.user* src/examples/gen/* diff --git a/.travis.yml b/.travis.yml index 284c684c59059d7fda29502e2f9ea85ab561977f..67ca6ea8ed38b52d657f7c045290dbf9aa93d139 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,23 @@ language: cpp before_install: + - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y - sudo apt-get update -qq - - sudo apt-get install -qq libcurl4-openssl-dev libjsoncpp-dev libargtable2-dev libboost-test-dev libgnutls-dev libgcrypt11-dev valgrind wget - - wget ftp://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-0.9.38.tar.gz - - tar -xvf libmicrohttpd-0.9.38.tar.gz - - cd libmicrohttpd-0.9.38 + - sudo apt-get install -qq libcurl4-openssl-dev libjsoncpp-dev libargtable2-dev libgnutls-dev libgcrypt11-dev valgrind wget gcc-4.8 g++-4.8 + - wget http://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-0.9.44.tar.gz + - tar -xvf libmicrohttpd-0.9.44.tar.gz + - cd libmicrohttpd-0.9.44 - ./configure && make - sudo make install && sudo ldconfig - - cd .. && sudo rm -rf libmicrohttpd-0.9.38 + - cd .. && sudo rm -rf libmicrohttpd-0.9.44 - sudo pip install cpp-coveralls + - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y + - sudo apt-get update -qq + - if [ "$CXX" = "g++" ]; then sudo apt-get install -qq g++-4.8; fi + - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi + +install: + - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi env: - HTTP_SERVER=YES HTTP_CLIENT=YES COMPILE_STUBGEN=YES @@ -21,7 +29,6 @@ script: - mkdir -p build && cd build - cmake -DCMAKE_BUILD_TYPE=Debug -DHTTP_CLIENT=${HTTP_CLIENT} -DHTTP_SERVER=${HTTP_SERVER} -DCOMPILE_STUBGEN=${COMPILE_STUBGEN} .. - make - - valgrind --leak-check=full --error-exitcode=1 ./bin/unit_testsuite - make test - sudo make install && sudo ldconfig - g++ ../src/examples/simpleclient.cpp -ljsonrpccpp-client -ljsoncpp -ljsonrpccpp-common -lcurl -o sampleclient diff --git a/AUTHORS.md b/AUTHORS.md index e5ea0c02919770aa3ae6c4c2315de07485adc327..081b7f70a3b1dbbad8040baa6a679c8a74de95aa 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -25,6 +25,14 @@ Yuriy Syrovetskiy <cblp@cblp.su> Veselin Rachev <veselin.raychev@gmail.com> + added HTTP OPTIONS request support +Marek Kotewicz <marek.kotewicz@gmail.com> ++ msvc support + +Alexandre Poirot <alexandre.poirot@gmail.com> ++ added client and server connectors that use Unix Domain Sockets ++ adapted build file to generate pkg-config file for this lib. ++ added client and server connectors that use Tcp Sockets on Linux and Windows (uses native socket and thread API on each OS) + Bugfixes (chronological order) ============================== @@ -48,3 +56,10 @@ Pascal Heijnsdijk <pascal@heijnsdijk.nl> Kasper Laudrup <laudrup@stacktrace.dk> + Code reviews + +Erik Lundin ++ bugfix in cpp-server stubgen ++ bugfix for gcc 4.7 compatibility + +MichaÅ‚ Górny <mgorny@gentoo.org> ++ bugfixes in the build system diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cb5f59bde4cb921a2ec6854052f36c09e94bd21..d3204857981f49c5e9075f065eed95ce47eaa6b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,40 @@ +Changes in v0.7.0 +----------------- +- Change: Requiring C++11 support (gcc >= 4.8) +- Fix: armhf compatibility +- Fix: Invalid client id field handling (removed int only check) +- Fix: Security issues in unixdomainsocket connectors +- Fix: Missing CURL include directive +- Fix: Parallel build which failed due to failing CATCH dependency +- Fix: Handling 64-bit ids +- Fix: Invalid parameter check +- Fix: Invalid pointer handling in HTTP-Server +- NEW: HttpServer can now be configured to listen localhost only +- NEW: TCP Server + Client connectors + +Changes in v0.6.0 +----------------- +- NEW: pkg-config files for all shared libraries +- NEW: UNIX Socket client + server connector +- NEW: multiarch support +- Change: unit testing framework to catch +- Change: allow disabling shared library build +- Change: split out shared/static library for stubgenerator + +Changes in v0.5.0 +----------------- +- Added `--version` option to jsonrpcstub. +- Added msvc support. +- Added data field support for JsonRpcException. +- Added contributions guide: https://github.com/cinemast/libjson-rpc-cpp#contributions +- HttpClient uses Http Keep-Alive, which improves performance drastically. +- Added multiarch support. +- Fixed building tests with examples disabled. +- Made static library build optional (via `BUILD_STATIC_LIBS`). +- Fixed unnecessary rebuilds of stubs on each `make` call. + Changes in v0.4.2 +----------------- - Fix of spelling mistakes. - Use CMAKE versioning in manpage. - Improving include scheme of jsoncpp. diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cb70f855910fc9c4d5a4a116b3c1270a5fc9040..a3cf5e0a78e2726a4507c4f2b7c0980220346757 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,90 +1,116 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.8) project(libjson-rpc-cpp) -cmake_policy(SET CMP0007 NEW) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") +# list command no longer ignores empty elements +cmake_policy(SET CMP0007 NEW) +cmake_policy(SET CMP0012 NEW) + +if (${CMAKE_MAJOR_VERSION} GREATER 2) + # old policy do not use MACOSX_RPATH + cmake_policy(SET CMP0042 OLD) +endif() + +set(MAJOR_VERSION 0) +set(MINOR_VERSION 7) +set(PATCH_VERSION 0) +set(SO_VERSION 0) + +set(BUILD_SHARED_LIBS YES CACHE BOOL "Build shared libraries") +set(BUILD_STATIC_LIBS NO CACHE BOOL "Build static libraries") +set(LIB_SUFFIX "" CACHE STRING "Suffix for library directory (32/64)") + +if (NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS) + message(FATAL_ERROR "Both BUILD_SHARED_LIBS and BUILD_STATIC_LIBS are disabled") +endif() + +# defaults for modules that can be enabled/disabled +if(UNIX) + set(UNIX_DOMAIN_SOCKET_SERVER YES CACHE BOOL "Include Unix Domain Socket server") + set(UNIX_DOMAIN_SOCKET_CLIENT YES CACHE BOOL "Include Unix Domain Socket client") +endif(UNIX) +set(TCP_SOCKET_SERVER NO CACHE BOOL "Include Tcp Socket server") +set(TCP_SOCKET_CLIENT NO CACHE BOOL "Include Tcp Socket client") +set(HTTP_SERVER YES CACHE BOOL "Include HTTP server using libmicrohttpd") +set(HTTP_CLIENT YES CACHE BOOL "Include HTTP client support using curl") +set(COMPILE_TESTS YES CACHE BOOL "Compile test framework") +set(COMPILE_STUBGEN YES CACHE BOOL "Compile the stubgenerator") +set(COMPILE_EXAMPLES YES CACHE BOOL "Compile example programs") + +# print actual settings +if(UNIX) + message(STATUS "UNIX_DOMAIN_SOCKET_SERVER: ${UNIX_DOMAIN_SOCKET_SERVER}") + message(STATUS "UNIX_DOMAIN_SOCKET_CLIENT: ${UNIX_DOMAIN_SOCKET_CLIENT}") +endif(UNIX) +message(STATUS "TCP_SOCKET_SERVER: ${TCP_SOCKET_SERVER}") +message(STATUS "TCP_SOCKET_CLIENT: ${TCP_SOCKET_CLIENT}") +message(STATUS "HTTP_SERVER: ${HTTP_SERVER}") +message(STATUS "HTTP_CLIENT: ${HTTP_CLIENT}") +if(UNIX) + message(STATUS "UNIXDOMAINSOCKET_SERVER: ${UNIX_DOMAIN_SOCKET_SERVER}") + message(STATUS "UNIXDOMAINSOCKET_CLIENT: ${UNIX_DOMAIN_SOCKET_CLIENT}") +endif(UNIX) +message(STATUS "COMPILE_TESTS: ${COMPILE_TESTS}") +message(STATUS "COMPILE_STUBGEN: ${COMPILE_STUBGEN}") +message(STATUS "COMPILE_EXAMPLES: ${COMPILE_EXAMPLES}") + +# setup directory where we should look for cmake files +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") + +# setup compiler settings && dependencies +include(CMakeCompilerSettings) +include(CMakeDependencies) + +# setup output directories set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -Wnon-virtual-dtor -fprofile-arcs -ftest-coverage -fPIC -O0") - -SET(MAJOR_VERSION 0) -SET(MINOR_VERSION 4) -SET(PATCH_VERSION 2) -SET(SO_VERSION 0) - -#possible modules that can be enabled/disabled -SET(HTTP_SERVER YES CACHE BOOL "Include HTTP server using libmicrohttpd") -SET(HTTP_CLIENT YES CACHE BOOL "Include HTTP client support using curl") +if (WIN32) + set(CMAKE_INSTALL_PREFIX ${PROJECT_BINARY_DIR}/dist) +endif() -SET(COMPILE_TESTS YES CACHE BOOL "Compile test framework") -SET(COMPILE_STUBGEN YES CACHE BOOL "Compile the stubgenerator") -SET(COMPILE_EXAMPLES YES CACHE BOOL "Compile example programs") +# setup global include_directories (for backwards compatibility) +include_directories("${CMAKE_BINARY_DIR}/gen/") +include_directories("${CMAKE_BINARY_DIR}/gen/jsonrpccpp/common") -IF(WIN32) - include_directories(${CMAKE_SOURCE_DIR}/win32-deps/include) - SET(CMAKE_INSTALL_PREFIX ${PROJECT_BINARY_DIR}/dist) - SET(BOOST_ROOT "C:/boost_1_57_0") -ENDIF() - -#the core framework +# the core framework add_subdirectory(src/jsonrpccpp) -include_directories("${PROJECT_SOURCE_DIR}/src/") -include_directories("${PROJECT_BINARY_DIR}/gen/") -include_directories("${PROJECT_BINARY_DIR}/gen/jsonrpccpp/common") - #the stubgenerator -IF(COMPILE_STUBGEN) - add_subdirectory(src/stubgenerator) -ENDIF() - -#the examples -IF(COMPILE_EXAMPLES AND HTTP_SERVER AND HTTP_CLIENT) - add_subdirectory(src/examples) -ENDIF() - -#the test suite -find_package(Boost COMPONENTS unit_test_framework) -IF(Boost_FOUND AND COMPILE_TESTS) - ENABLE_TESTING() - add_subdirectory(src/test) -ENDIF() - -find_package(Doxygen) -if(DOXYGEN_FOUND) - file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/doc) - message(STATUS "Found doxygen: ${DOXYGEN_EXECUTABLE}") - configure_file("${CMAKE_SOURCE_DIR}/doc/doxyfile.in" "${CMAKE_BINARY_DIR}/Doxyfile" @ONLY) - add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/doc COMMENT "Generating API documentation") +if (COMPILE_STUBGEN) + add_subdirectory(src/stubgenerator) +endif () + +# setup examples +if (COMPILE_EXAMPLES) + add_subdirectory(src/examples) +endif() + +# setup test suite +if (COMPILE_TESTS) + enable_testing(true) + add_subdirectory(src/test) +endif() + +# create documentation +if (DOXYGEN_FOUND) + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/doc) + message(STATUS "Found doxygen: ${DOXYGEN_EXECUTABLE}") + configure_file("${PROJECT_SOURCE_DIR}/doc/doxyfile.in" "${CMAKE_BINARY_DIR}/Doxyfile" @ONLY) + add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/doc COMMENT "Generating API documentation") endif(DOXYGEN_FOUND) - -# uninstall target +# setup uninstall target configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - IMMEDIATE @ONLY) -add_custom_target(uninstall -COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) - -#packaging stuff -INCLUDE(InstallRequiredSystemLibraries) -SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "libjson-rpc-cpp") -SET(CPACK_PACKAGE_VENDOR "Peter Spiess-Knafl <psk@autistici.org>") -SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") -SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt") -SET(CPACK_PACKAGE_VERSION_MAJOR "${MAJOR_VERSION}") -SET(CPACK_PACKAGE_VERSION_MINOR "${MINOR_VERSION}") -SET(CPACK_PACKAGE_VERSION_PATCH "${PATCH_VERSION}") - -IF(WIN32 AND NOT UNIX) - SET(CPACK_GENERATOR "NSIS") - SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} libjson-rpc-cpp") - SET(CPACK_NSIS_HELP_LINK "http://github.com/cinemast/libjson-rpc-cpp") - SET(CPACK_NSIS_URL_INFO_ABOUT "http://github.com/cinemast/libjson-rpc-cpp") - SET(CPACK_NSIS_CONTACT "psk@autistici.org") - SET(CPACK_NSIS_MODIFY_PATH ON) -ENDIF(WIN32 AND NOT UNIX) -INCLUDE(CPack) + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY +) + +add_custom_target( + uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake +) + +# packaging stuff +include(CMakePackaging) diff --git a/README.md b/README.md index c497dae0350e1f7dc9064bd768a26a9387d4ec94..08fdd5b6df54723295dfdf50580846cea1f2f449 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,19 @@ libjson-rpc-cpp This framework provides cross platform JSON-RPC (remote procedure call) support for C++. It is fully JSON-RPC [2.0 & 1.0 compatible](http://www.jsonrpc.org/specification). -**Notice: This framework is currently in a beta phase. Bug reports as well as contributions are very welcome! Heavy API/ABI changes might occur regularly but you can always find stable versions in the [Releases section](https://github.com/cinemast/libjson-rpc-cpp/releases)** -  **5 good reasons for using libjson-rpc-cpp in your next RPC project** - Full JSON-RPC 2.0 & 1.0 Client and Server Support. - jsonrpcstub - a tool that generates stub-classes for your JSON-RPC client AND server applications. -- Ready to use HTTP server and client to provide simple interfaces for your JSON-RPC application. -- Cross platform build support and [precompiled binaries for WIN32](http://spiessknafl.at/libjson-rpc-cpp/libjson-rpc-cpp-win32.exe). +- Ready to use HTTP + TCP server and client to provide simple interfaces for your JSON-RPC application. +- Cross platform build support and [precompiled binaries for WIN32](http://spiessknafl.at/libjson-rpc-cpp). - Super liberal [MIT-License](http://en.wikipedia.org/wiki/MIT_License). **Other good reasons to use libjson-rpc-cpp** - Easy to use [cmake](http://www.cmake.org) cross platform build system. - Clean and simple architecture, which makes it easy to extend. -- Tested under MacOS X (10.9), Linux (Debian 8 64-bit), Windows 7 (MinGW32) and Raspbian Wheezy (armhf). +- Tested under MacOS X (10.9), GNU/Linux (Debian 8 64-bit), Windows 7 (MinGW32) and Raspbian Wheezy (armhf). - Automated testing using `make test`. - Useful Examples provided. e.g. XBMC Remote using json-rpc client part and stub generator. - The stubgenerator currently supports C++ and JavaScript. @@ -29,25 +27,29 @@ Overview =========  -Build the framework -=================== +Install the framework +===================== + +**Debian (stretch) and Ubuntu (15.10 or later)** -Installing the dependencies ---------------------------- -**Debian based systems** ```sh -sudo apt-get install libcurl4-openssl-dev libmicrohttpd-dev libjsoncpp-dev libargtable2-dev cmake +sudo apt-get install libjsonrpccpp-dev libjsonrpccpp-tools ``` -**Arch Linux based systems** +**Arch Linux** -For Arch Linux there is a [PKGBUILD provided in the AUR](https://aur.archlinux.org/packages/libjson-rpc-cpp/). -This already takes care of dependencies and the framework itself. +For Arch Linux there is a [PKGBUILD provided in the AUR](https://aur.archlinux.org/packages/libjson-rpc-cpp/). ```sh sudo aura -A libjson-rpc-cpp ``` +**Gentoo Linux** + +```sh +sudo emerge dev-cpp/libjson-rpc-cpp +``` + **Mac OS X** For OS X a [Brew](http://brew.sh) package is available: @@ -57,18 +59,31 @@ brew install libjson-rpc-cpp **Windows** -There is a ready to use compiled package for WIN32 [here](http://spiessknafl.at/libjson-rpc-cpp/libjson-rpc-cpp-win32.exe). +There is a ready to use compiled package [here](http://spiessknafl.at/libjson-rpc-cpp). +Just download execute the installer EXE. -If you want to compile on your own, here is how: +Build from source +================= +Install the dependencies +------------------------ +- [libcurl](http://curl.haxx.se/) +- [libmicrohttpd](http://www.gnu.org/software/libmicrohttpd/) +- [libjsoncpp](https://github.com/open-source-parsers/jsoncpp) +- [libargtable](http://argtable.sourceforge.net/) +- [cmake](http://www.cmake.org/) + +**UNIX** + +For Debian and Arch GNU/Linux based systems, all dependencies are available via the package manager. +For OS X all dependencies are available in [Brew](http://brew.sh) + +**Windows** -- You will need [Git](http://git-scm.com/downloads) and [CMake](http://www.cmake.org/cmake/resources/software.html). - Download the precompiled dependencies form [here](https://spiessknafl.at/libjson-rpc-cpp/libjson-rpc-cpp_win32-deps.zip). - Extract it into the cloned repository, so that there is a `win32-deps` folder in the root project directory. -Build and install this framework --------------------------------- - -Open a terminal and copy the following commands: +Build +----- ```sh git clone git://github.com/cinemast/libjson-rpc-cpp.git @@ -89,14 +104,18 @@ sudo make uninstall Default configuration should be fine for most systems, but here are available compilation flags: -- `-DCOMPILE_TESTS=NO` disables unit test suite even if boost libraries are found. +- `-DCOMPILE_TESTS=NO` disables unit test suite. - `-DCOMPILE_STUBGEN=NO` disables building the stubgenerator. - `-DCOMPILE_EXAMPLES=NO` disables examples. -- `-DHTTP_SERVER=NO` disable the embedded mongoose webserver. +- `-DHTTP_SERVER=NO` disable the libmicrohttpd webserver. - `-DHTTP_CLIENT=NO` disable the curl client. +- `-DUNIX_DOMAIN_SOCKET_SERVER=NO` disable the unix domain socket server connector. +- `-DUNIX_DOMAIN_SOCKET_CLIENT=NO` disable the unix domain socket client connector. +- `-DTCP_SOCKET_SERVER=NO` disable the tcp socket server connector. +- `-DTCP_SOCKET_CLIENT=NO` disable the tcp socket client connector. -Simple Example -============== +Using the framework +=================== This example will show the most simple way to create a rpc server and client. If you only need the server, ignore step 4. If you only need the client, ignore step 3. You can find all resources of this sample in the `src/examples` directory of this repository. ### Step 1: Writing the specification file ### @@ -196,7 +215,7 @@ int main() StubClient c(httpclient); try { - cout << c.sayHello("Peter Knafl") << endl; + cout << c.sayHello("Peter") << endl; c.notifyServer(); } catch (JsonRpcException e) @@ -226,7 +245,37 @@ References If you use this library and find it useful, I would be very pleased if you let me know about it. Developer Information -====================== +===================== +Contributions +------------- +Contributions of any kind are always very welcome. +Here are some suggestions: +- Bugreports +- Bugfixes +- Extending documentation (especially doxygen) +- Suggestion of new features +- New features: + - Adding new connectors. + - Adding new languages to the stubgenerator. + +**Guidelines / Conventions** + +We do not want to prevent you from contributing by having too strict guidelines. +If you have ideas for improvement, just do it your way, rather than doing it not at all. + +Anyway here is a list of how we would prefer your contributions: +- Issues: + - Use the issue tracker on github to report bugs or improvements. + - Please avoid sending me mails directly, as this is not visible to others. + - Please close issues on your own if you think a problem has been dealt with. +- Code contributions: + - Please raise a pull-request against the develop branch. + - If you add features, please keep the test-coverage at 100% and document them (doxygen, manpage, etc.). + - If you fix a bug, please refer the issue in the [commit message](https://help.github.com/articles/closing-issues-via-commit-messages/). + - Please make sure that the travis-ci build passes (you will get notified if you raise a pull-request). + - Add yourself to the AUTHORS.md. + - Use 4 spaces instead of tabs. + Mailing list ------------ [libjsonrpccpp-devel@lists.sourceforge.net](https://lists.sourceforge.net/lists/listinfo/libjsonrpccpp-devel) @@ -234,50 +283,41 @@ Mailing list Roadmap for next release ------------------------ - Generate client stubs for other languages. +- Extend doxygen documentation. Changelogs ---------- Changelogs can be found [here](https://github.com/cinemast/libjson-rpc-cpp/blob/master/CHANGELOG.md). API compatibility ----------------- -Can be found [here](http://upstream.rosalinux.ru/versions/libjson-rpc-cpp.html) +----------------- +We do our best to keep the API/ABI stable, to prevent problems when updating this framework. +A compatiblity report can be found [here](http://upstream.rosalinux.ru/versions/libjson-rpc-cpp.html). License ------- This framework is licensed under [MIT](http://en.wikipedia.org/wiki/MIT_License). All of this libraries dependencies are licensed under MIT compatible licenses. -Dependencies ------------- -- [jsoncpp](http://jsoncpp.sourceforge.net) (licensed under MIT) -jsoncpp is a very easy to use and powerful json library. -It is used for all the JSON parsing and generation inside this library. -- [libmicrohttpd](http://www.gnu.org/software/libmicrohttpd/) (licensed under LGPL) -small gnu http server implementation. -- [curl](http://curl.haxx.se) -lib curl is used for the HttpClient connections. -- [argtable2](http://argtable.sourceforge.net/) (licensed under LGPL) -libargtable2 is used for handling commandline parameters of the jsonrpcstub tool. - -Run the tests +Documentation ------------- -For running the tests, the boost-test framework is required: -**Debian based systems** +The documentation for this library can be generated using doxygen. +If it is installed on your system, you can simply type: + ```sh cd build -sudo apt-get install libboost-test-dev -cmake .. && make test +make doc ``` -**Mac OS X** -You need [Brew](http://brew.sh) installed and type the following commands +This generates the Latex and HTML documentation into `build/doc` + +Run the tests +------------- +Simply run: + ```sh -cd build -brew install boost -cmake .. && make test +make test ``` -Testcoverage can be retrieved by invoking the [dev/testcoverage.sh script](https://github.com/cinemast/libjson-rpc-cpp/blob/master/dev/testcoverage.sh). - +Testcoverage can be retrieved by invoking the [dev/testcoverage.sh script](https://github.com/cinemast/libjson-rpc-cpp/blob/master/dev/testcoverage.sh) inside the `dev` folder. diff --git a/cmake/CMakeCompilerSettings.cmake b/cmake/CMakeCompilerSettings.cmake new file mode 100644 index 0000000000000000000000000000000000000000..cca7ebec9ed8e51c187971594e2be95007a3a8c5 --- /dev/null +++ b/cmake/CMakeCompilerSettings.cmake @@ -0,0 +1,14 @@ +# Set necessary compile and link flags + + +if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wformat -Wno-format-extra-args -Wformat-security -Wformat-nonliteral -Wformat=2 -Wextra -Wnon-virtual-dtor -fprofile-arcs -ftest-coverage -fPIC -O0") +elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") +# TODO figure clang stuff to enable test-coverage +# Instrument Program flow should be set to Yes +# http://stackoverflow.com/questions/7949781/undefined-symbols-for-architecture-i386-upgrading-project-to-ios-5 + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -Wnon-virtual-dtor -fPIC -O0") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") +# no msvc flags for now +endif() \ No newline at end of file diff --git a/cmake/CMakeDependencies.cmake b/cmake/CMakeDependencies.cmake new file mode 100644 index 0000000000000000000000000000000000000000..e283828396b7647ba441301069e4845043708738 --- /dev/null +++ b/cmake/CMakeDependencies.cmake @@ -0,0 +1,57 @@ +# all dependencies that are not directly included in the libjson-rpc-cpp distribution are defined here! +# default search directory for dependencies is ${CMAKE_SOURCE_DIR}/win32-deps (for backwards compatibility) +# if your dependencies directory is different, please run cmake with CMAKE_PREFIX_PATH option eg: +# +# cmake -DCMAKE_PREFIX_PATH=path_to_your_dependencies . + +# set default dependencies search path +set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${CMAKE_SOURCE_DIR}/win32-deps") + +# find JSONCPP +# TODO: handle windows debug libraries! +# TODO: fix FindJSONCPP file! +find_package(Jsoncpp) +message(STATUS "Jsoncpp header: ${JSONCPP_INCLUDE_DIRS}") +message(STATUS "Jsoncpp lib : ${JSONCPP_LIBRARIES}") +message(STATUS "Jsoncpp prefix: ${JSONCPP_INCLUDE_PREFIX}") + +# find Threads! +find_package(Threads) +message(STATUS "Threads: ${CMAKE_THREADS_LIBS_INIT}") + +# find Argtable +if(${COMPILE_STUBGEN}) + find_package(Argtable REQUIRED) + message(STATUS "Argtable header: ${ARGTABLE_INCLUDE_DIRS}") + message(STATUS "Argtable lib : ${ARGTABLE_LIBRARIES}") +endif() + +if(${HTTP_CLIENT}) +# find CURL + find_package(CURL REQUIRED) + message(STATUS "CURL header: ${CURL_INCLUDE_DIRS}") + message(STATUS "CURL lib : ${CURL_LIBRARIES}") +endif() + +if (${HTTP_SERVER}) +# find libmicrohttpd + find_package(MHD REQUIRED) + message(STATUS "MHD header: ${MHD_INCLUDE_DIRS}") + message(STATUS "MHD lib : ${MHD_LIBRARIES}") +endif() + +# find doxygen +find_package(Doxygen) + +if (${COMPILE_TESTS}) + + find_package(Catch) + if(NOT CATCH_FOUND) + message("Could not find catch, downloading it now") + # Includes Catch in the project: + add_subdirectory(${CMAKE_SOURCE_DIR}/src/catch) + include_directories(${CATCH_INCLUDE_DIR} ${COMMON_INCLUDES}) + else() + INCLUDE_DIRECTORIES(${CATCH_INCLUDE_DIRS}) + endif() +endif() diff --git a/cmake/CMakePackaging.cmake b/cmake/CMakePackaging.cmake new file mode 100644 index 0000000000000000000000000000000000000000..81aa402a4b4fb11eec6364a3aa5a1cc00dcb03cf --- /dev/null +++ b/cmake/CMakePackaging.cmake @@ -0,0 +1,18 @@ +include(InstallRequiredSystemLibraries) +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "libjson-rpc-cpp") +set(CPACK_PACKAGE_VENDOR "Peter Spiess-Knafl <dev@spiessknafl.at>") +set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt") +set(CPACK_PACKAGE_VERSION_MAJOR "${MAJOR_VERSION}") +set(CPACK_PACKAGE_VERSION_MINOR "${MINOR_VERSION}") +set(CPACK_PACKAGE_VERSION_PATCH "${PATCH_VERSION}") + +if (WIN32 AND NOT UNIX) + set(CPACK_GENERATOR "NSIS") + set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} libjson-rpc-cpp") + set(CPACK_NSIS_HELP_LINK "http://github.com/cinemast/libjson-rpc-cpp") + set(CPACK_NSIS_URL_INFO_ABOUT "http://github.com/cinemast/libjson-rpc-cpp") + set(CPACK_NSIS_CONTACT "Peter Spiess-Knafl <dev@spiessknafl.at>") + set(CPACK_NSIS_MODIFY_PATH ON) +endif(WIN32 AND NOT UNIX) +include(CPack) diff --git a/cmake/FindArgtable.cmake b/cmake/FindArgtable.cmake index 25e7cb8b7fb6c30a06dfd8779f8fb48f9e96212f..da2daae4218a5cd0ea923ccc770957b095eb3644 100644 --- a/cmake/FindArgtable.cmake +++ b/cmake/FindArgtable.cmake @@ -3,37 +3,41 @@ # # ARGTABLE_FOUND - system has ARGTABLE # ARGTABLE_INCLUDE_DIRS - the ARGTABLE include directory -# ARGTABLE_LIBRARY - Link these to use ARGTABLE +# ARGTABLE_LIBRARIES - Link these to use ARGTABLE -FIND_LIBRARY (ARGTABLE_LIBRARIES NAMES argtable2 - PATHS - /usr/lib - /usr/local/lib - ${CMAKE_SOURCE_DIR}/win32-deps/lib +find_path ( + ARGTABLE_INCLUDE_DIR + NAMES argtable2.h + DOC "argtable include dir" ) -FIND_PATH (ARGTABLE_INCLUDE_DIRS argtable2.h - PATHS - /usr/include - /usr/local/include - ${CMAKE_SOURCE_DIR}/win32-deps/include +find_library ( + ARGTABLE_LIBRARY + NAMES argtable2 + DOC "argtable library" ) -IF(ARGTABLE_INCLUDE_DIRS AND ARGTABLE_LIBRARIES) - SET(ARGTABLE_FOUND TRUE) -ENDIF(ARGTABLE_INCLUDE_DIRS AND ARGTABLE_LIBRARIES) +set(ARGTABLE_INCLUDE_DIRS ${ARGTABLE_INCLUDE_DIR}) +set(ARGTABLE_LIBRARIES ${ARGTABLE_LIBRARY}) -IF(ARGTABLE_FOUND) - IF(NOT ARGTABLE_FIND_QUIETLY) - MESSAGE(STATUS "Found libargtable: ${ARGTABLE_LIBRARIES}") - ENDIF(NOT ARGTABLE_FIND_QUIETLY) -ELSE(ARGTABLE_FOUND) - IF(ARGTABLE_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find libargtable") - ENDIF(ARGTABLE_FIND_REQUIRED) -ENDIF(ARGTABLE_FOUND) +# debug library on windows +# same naming convention as in qt (appending debug library with d) +# boost is using the same "hack" as us with "optimized" and "debug" +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + find_library( + ARGTABLE_LIBRARY_DEBUG + NAMES argtable2d + DOC "argtable debug library" + ) + + set(ARGTABLE_LIBRARIES optimized ${ARGTABLE_LIBRARIES} debug ${ARGTABLE_LIBRARY_DEBUG}) + +endif() + +# handle the QUIETLY and REQUIRED arguments and set JSONCPP_FOUND to TRUE +# if all listed variables are TRUE, hide their existence from configuration view +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(argtable DEFAULT_MSG + ARGTABLE_INCLUDE_DIR ARGTABLE_LIBRARY) +mark_as_advanced (ARGTABLE_INCLUDE_DIR ARGTABLE_LIBRARY) -MARK_AS_ADVANCED( - ARGTABLE_LIBRARIES - ARGTABLE_INCLUDE_DIRS -) diff --git a/cmake/FindCURL.cmake b/cmake/FindCURL.cmake index 275358179eda1c85887fe58f8ca472f918915883..ba66037840f7f26b49063e916bc106d1a3722f42 100644 --- a/cmake/FindCURL.cmake +++ b/cmake/FindCURL.cmake @@ -1,40 +1,49 @@ -# - Try to find CURL -# Once done this will define -# -# CURL_FOUND - system has CURL -# CURL_INCLUDE_DIRS - the CURL include directory -# CURL_LIBRARY - Link these to use CURL - -FIND_LIBRARY (CURL_LIBRARIES NAMES curl - PATHS - /usr/lib - /usr/local/lib - ${CMAKE_SOURCE_DIR}/win32-deps/lib -) - -FIND_PATH (CURL_INCLUDE_DIRS curl.h - PATHS - /usr/include - /usr/local/include - ${CMAKE_SOURCE_DIR}/win32-deps/include - PATH_SUFFIXES curl -) - -IF(CURL_INCLUDE_DIRS AND CURL_LIBRARIES) - SET(CURL_FOUND TRUE) -ENDIF(CURL_INCLUDE_DIRS AND CURL_LIBRARIES) - -IF(CURL_FOUND) - IF(NOT CURL_FIND_QUIETLY) - MESSAGE(STATUS "Found libcurl: ${CURL_LIBRARIES}") - ENDIF(NOT CURL_FIND_QUIETLY) -ELSE(CURL_FOUND) - IF(CURL_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find libcurl") - ENDIF(CURL_FIND_REQUIRED) -ENDIF(CURL_FOUND) - -MARK_AS_ADVANCED( - CURL_LIBRARIES - CURL_INCLUDE_DIRS -) +# Find CURL +# +# Find the curl includes and library +# +# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH +# +# This module defines +# CURL_INCLUDE_DIRS, where to find header, etc. +# CURL_LIBRARIES, the libraries needed to use curl. +# CURL_FOUND, If false, do not try to use curl. + +# only look in default directories +find_path( + CURL_INCLUDE_DIR + NAMES curl/curl.h + DOC "curl include dir" +) + +find_library( + CURL_LIBRARY + # names from cmake's FindCURL + NAMES curl curllib libcurl_imp curllib_static libcurl + DOC "curl library" +) + +set(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR}) +set(CURL_LIBRARIES ${CURL_LIBRARY}) + +# debug library on windows +# same naming convention as in qt (appending debug library with d) +# boost is using the same "hack" as us with "optimized" and "debug" +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + find_library( + CURL_LIBRARY_DEBUG + NAMES curld libcurld + DOC "curl debug library" + ) + + set(CURL_LIBRARIES optimized ${CURL_LIBRARIES} debug ${CURL_LIBRARY_DEBUG}) + +endif() + +# handle the QUIETLY and REQUIRED arguments and set CURL_FOUND to TRUE +# if all listed variables are TRUE, hide their existence from configuration view +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CURL DEFAULT_MSG + CURL_INCLUDE_DIR CURL_LIBRARY) +mark_as_advanced (CURL_INCLUDE_DIR CURL_LIBRARY) + diff --git a/cmake/FindCatch.cmake b/cmake/FindCatch.cmake new file mode 100644 index 0000000000000000000000000000000000000000..f9deaa8d56efa63cc7d6dbcff646b6100852e7e9 --- /dev/null +++ b/cmake/FindCatch.cmake @@ -0,0 +1,15 @@ +find_path( + CATCH_INCLUDE_DIR + NAMES catch.hpp + DOC "catch include dir" +) + + +set(CATCH_INCLUDE_DIRS ${CATCH_INCLUDE_DIR}) + + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(catch DEFAULT_MSG + CATCH_INCLUDE_DIR) +mark_as_advanced (CATCH_INCLUDE_DIR) + diff --git a/cmake/FindJSONCPP.cmake b/cmake/FindJSONCPP.cmake deleted file mode 100644 index 0a0517de33206b9ef544ab2ac2264052b59c5941..0000000000000000000000000000000000000000 --- a/cmake/FindJSONCPP.cmake +++ /dev/null @@ -1,44 +0,0 @@ -# - Try to find JSONCPP -# Once done this will define -# -# JSONCPP_FOUND - system has JSONCPP -# JSONCPP_INCLUDE_DIRS - the JSONCPP include directory -# JSONCPP_LIBRARY - Link these to use JSONCPP - -FIND_LIBRARY (JSONCPP_LIBRARIES NAMES jsoncpp - PATHS - /usr/lib - /usr/local/lib - ${CMAKE_SOURCE_DIR}/win32-deps/lib -) - -FIND_PATH (JSONCPP_INCLUDE_DIRS json.h - PATHS - /usr/include - /usr/local/include - ${CMAKE_SOURCE_DIR}/win32-deps/include - PATH_SUFFIXES jsoncpp/json json -) - -IF(JSONCPP_INCLUDE_DIRS AND JSONCPP_LIBRARIES) - SET(JSONCPP_FOUND TRUE) -ENDIF(JSONCPP_INCLUDE_DIRS AND JSONCPP_LIBRARIES) - -IF(JSONCPP_FOUND) - if(EXISTS "${JSONCPP_INCLUDE_DIRS}/version.h") - MESSAGE(STATUS "Found New libjsoncpp: ${JSONCPP_LIBRARIES}") - set(JSONCPP_INCLUDE_PREFIX "json") - else() - MESSAGE(STATUS "Found old libjsoncpp: ${JSONCPP_LIBRARIES}") - set(JSONCPP_INCLUDE_PREFIX "jsoncpp/json") - endif() -ELSE(JSONCPP_FOUND) - IF(JSONCPP_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find libjsoncpp") - ENDIF(JSONCPP_FIND_REQUIRED) -ENDIF(JSONCPP_FOUND) - -MARK_AS_ADVANCED( - JSONCPP_LIBRARIES - JSONCPP_INCLUDE_DIRS -) diff --git a/cmake/FindJsoncpp.cmake b/cmake/FindJsoncpp.cmake new file mode 100644 index 0000000000000000000000000000000000000000..725303bae6bb28a3fedf05fbce284286bdd4e89a --- /dev/null +++ b/cmake/FindJsoncpp.cmake @@ -0,0 +1,62 @@ +# Find jsoncpp +# +# Find the jsoncpp includes and library +# +# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH +# +# This module defines +# JSONCPP_INCLUDE_DIRS, where to find header, etc. +# JSONCPP_LIBRARIES, the libraries needed to use jsoncpp. +# JSONCPP_FOUND, If false, do not try to use jsoncpp. +# JSONCPP_INCLUDE_PREFIX, include prefix for jsoncpp + +# only look in default directories +find_path( + JSONCPP_INCLUDE_DIR + NAMES jsoncpp/json/json.h json/json.h + DOC "jsoncpp include dir" +) + +find_library( + JSONCPP_LIBRARY + NAMES jsoncpp + DOC "jsoncpp library" +) + +set(JSONCPP_INCLUDE_DIRS ${JSONCPP_INCLUDE_DIR}) +set(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY}) + +# debug library on windows +# same naming convention as in qt (appending debug library with d) +# boost is using the same "hack" as us with "optimized" and "debug" +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + find_library( + JSONCPP_LIBRARY_DEBUG + NAMES jsoncppd + DOC "jsoncpp debug library" + ) + + set(JSONCPP_LIBRARIES optimized ${JSONCPP_LIBRARIES} debug ${JSONCPP_LIBRARY_DEBUG}) + +endif() + +# find JSONCPP_INCLUDE_PREFIX +find_path( + JSONCPP_INCLUDE_PREFIX + NAMES json.h + PATH_SUFFIXES jsoncpp/json json +) + +if (${JSONCPP_INCLUDE_PREFIX} MATCHES "jsoncpp") + set(JSONCPP_INCLUDE_PREFIX "jsoncpp/json") +else() + set(JSONCPP_INCLUDE_PREFIX "json") +endif() + +# handle the QUIETLY and REQUIRED arguments and set JSONCPP_FOUND to TRUE +# if all listed variables are TRUE, hide their existence from configuration view +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(jsoncpp DEFAULT_MSG + JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY) +mark_as_advanced (JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY) + diff --git a/cmake/FindMHD.cmake b/cmake/FindMHD.cmake index 3ed99731f400714325c1b287be581999ff24b190..279a2e7b1b295b4278bed60fbdbde96cd8ae6516 100755 --- a/cmake/FindMHD.cmake +++ b/cmake/FindMHD.cmake @@ -5,35 +5,39 @@ # MHD_INCLUDE_DIRS - the MHD include directory # MHD_LIBRARY - Link these to use MHD -FIND_LIBRARY (MHD_LIBRARIES NAMES microhttpd microhttpd-10 - PATHS - /usr/lib - /usr/local/lib - ${CMAKE_SOURCE_DIR}/win32-deps/lib +find_path( + MHD_INCLUDE_DIR + NAMES microhttpd.h + DOC "microhttpd include dir" ) -FIND_PATH (MHD_INCLUDE_DIRS microhttpd.h - PATHS - /usr/include - /usr/local/include - ${CMAKE_SOURCE_DIR}/win32-deps/include +find_library( + MHD_LIBRARY + NAMES microhttpd microhttpd-10 libmicrohttpd libmicrohttpd-dll + DOC "microhttpd library" ) -IF(MHD_INCLUDE_DIRS AND MHD_LIBRARIES) - SET(MHD_FOUND TRUE) -ENDIF(MHD_INCLUDE_DIRS AND MHD_LIBRARIES) - -IF(MHD_FOUND) - IF(NOT MHD_FIND_QUIETLY) - MESSAGE(STATUS "Found libmicrohttpd: ${MHD_LIBRARIES}") - ENDIF(NOT MHD_FIND_QUIETLY) -ELSE(MHD_FOUND) - IF(MHD_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find libmicrohttpd") - ENDIF(MHD_FIND_REQUIRED) -ENDIF(MHD_FOUND) - -MARK_AS_ADVANCED( - MHD_LIBRARIES - MHD_INCLUDE_DIRS -) +set(MHD_INCLUDE_DIRS ${MHD_INCLUDE_DIR}) +set(MHD_LIBRARIES ${MHD_LIBRARY}) + +# debug library on windows +# same naming convention as in qt (appending debug library with d) +# boost is using the same "hack" as us with "optimized" and "debug" +# official MHD project actually uses _d suffix +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + find_library( + MHD_LIBRARY_DEBUG + NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d + DOC "mhd debug library" + ) + + set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) + +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(mhd DEFAULT_MSG + MHD_INCLUDE_DIR MHD_LIBRARY) + +mark_as_advanced(MHD_INCLUDE_DIR MHD_LIBRARY) + diff --git a/cmake/FindSocket.cmake b/cmake/FindSocket.cmake index 581f15181174d170e40ad38ddbe5e26dee8ec26e..f002083dc01d95fd244e43493b863a7b4426a51f 100644 --- a/cmake/FindSocket.cmake +++ b/cmake/FindSocket.cmake @@ -3,13 +3,18 @@ # Socket_LIBRARIES - the socket library # Socket_FOUND -if(${CMAKE_SYSTEM} MATCHES "Windows") - SET(Socket_LIBRARIES wsock32 ws2_32) - SET(Socket_FOUND 1) +if (${CMAKE_SYSTEM} MATCHES "Windows") + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(Socket_LIBRARIES ws2_32) + else() + set(Socket_LIBRARIES wsock32 ws2_32) + endif() + set(Socket_FOUND 1) elseif(${CMAKE_SYSTEM} MATCHES "INtime") - SET(Socket_LIBRARIES netlib) - SET(Socket_FOUND 1) + set(Socket_LIBRARIES netlib) + set(Socket_FOUND 1) else() - SET(Socket_LIBRARIES) - SET(Socket_FOUND 1) + set(Socket_LIBRARIES) + set(Socket_FOUND 1) endif() + diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in index 5fa558eab2017dd062c1fa5d2b8f1ad4d6c9c8f5..49183b66c565dec24af907ceb7aa3a52f110b251 100644 --- a/cmake/cmake_uninstall.cmake.in +++ b/cmake/cmake_uninstall.cmake.in @@ -2,24 +2,27 @@ cmake_policy(SET CMP0007 NEW) if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") + message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") list(REVERSE files) foreach (file ${files}) - message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") - if (EXISTS "$ENV{DESTDIR}${file}") - execute_process( - COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" - OUTPUT_VARIABLE rm_out - RESULT_VARIABLE rm_retval - ) - if(NOT ${rm_retval} EQUAL 0) - message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") - endif (NOT ${rm_retval} EQUAL 0) - else (EXISTS "$ENV{DESTDIR}${file}") - message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") - endif (EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if (EXISTS "$ENV{DESTDIR}${file}") + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + + if (NOT ${rm_retval} EQUAL 0) + message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif (NOT ${rm_retval} EQUAL 0) + + else (EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif (EXISTS "$ENV{DESTDIR}${file}") + endforeach(file) diff --git a/cmake/cross-mingw32-linux.cmake b/cmake/cross-mingw32-linux.cmake index bca3d80340ecafa756237d4b06920cfd16c52002..650cf462e998813227736ea7b36e6d6fe0f648ee 100644 --- a/cmake/cross-mingw32-linux.cmake +++ b/cmake/cross-mingw32-linux.cmake @@ -1,5 +1,5 @@ # the name of the target operating system -SET(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_NAME Windows) # Choose an appropriate compiler prefix @@ -22,7 +22,7 @@ find_program(CMAKE_CXX_COMPILER NAMES ${COMPILER_PREFIX}-g++) # here is the target environment located -SET(CMAKE_FIND_ROOT_PATH /usr/${COMPILER_PREFIX}) +set(CMAKE_FIND_ROOT_PATH /usr/${COMPILER_PREFIX}) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search diff --git a/cmake/libjsonrpccpp-client.pc.cmake b/cmake/libjsonrpccpp-client.pc.cmake new file mode 100644 index 0000000000000000000000000000000000000000..2d84a124ae88d2ecc4ae54fb8fe64a78de8fcb02 --- /dev/null +++ b/cmake/libjsonrpccpp-client.pc.cmake @@ -0,0 +1,5 @@ +Name: libjsonrpccpp-client +Description: A C++ client implementation of json-rpc. +Version: ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION} +Libs: -L${FULL_PATH_LIBDIR} -ljsoncpp -ljsonrpccpp-common -ljsonrpccpp-client -lcurl +Cflags: -I${FULL_PATH_INCLUDEDIR} diff --git a/cmake/libjsonrpccpp-common.pc.cmake b/cmake/libjsonrpccpp-common.pc.cmake new file mode 100644 index 0000000000000000000000000000000000000000..c43085420a49cfe33e968bdc91dd6c422e8d3c0d --- /dev/null +++ b/cmake/libjsonrpccpp-common.pc.cmake @@ -0,0 +1,5 @@ +Name: libjsonrpccpp-common +Description: Common libraries for libjson-rpc-cpp +Version: ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION} +Libs: -L${FULL_PATH_LIBDIR} -ljsoncpp +Cflags: -I${FULL_PATH_INCLUDEDIR} diff --git a/cmake/libjsonrpccpp-server.pc.cmake b/cmake/libjsonrpccpp-server.pc.cmake new file mode 100644 index 0000000000000000000000000000000000000000..580a94223355ebab4ea481e5bef86e320dd82beb --- /dev/null +++ b/cmake/libjsonrpccpp-server.pc.cmake @@ -0,0 +1,5 @@ +Name: libjsonrpccpp-server +Description: A C++ server implementation of json-rpc. +Version: ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION} +Libs: -L${FULL_PATH_LIBDIR} -ljsoncpp -ljsonrpccpp-common -ljsonrpccpp-server -lmicrohttpd +Cflags: -I${FULL_PATH_INCLUDEDIR} diff --git a/cmake/libjsonrpccpp-stub.pc.cmake b/cmake/libjsonrpccpp-stub.pc.cmake new file mode 100644 index 0000000000000000000000000000000000000000..4555d3e573ce3b18edb6cbd0c17ce7791e82ae81 --- /dev/null +++ b/cmake/libjsonrpccpp-stub.pc.cmake @@ -0,0 +1,5 @@ +Name: libjsonrpccpp-stub +Description: library for stub-generation of libjson-rpc-cpp servers/clients. +Version: ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION} +Libs: -L${FULL_PATH_LIBDIR} -ljsoncpp -ljsonrpccpp-common +Cflags: -I${FULL_PATH_INCLUDEDIR} diff --git a/dev/ci.sh b/dev/ci.sh index cbefad1a09287bd5526f108d1de330981e5070f8..5b6b1f4449e8b6604c957493b5d18860f0242d54 100755 --- a/dev/ci.sh +++ b/dev/ci.sh @@ -7,7 +7,6 @@ build_configuration() { cd build cmake $1 .. make - make test mkdir -p root make DESTDIR=root install cd .. @@ -17,14 +16,14 @@ cleanup() { cd build make DESTDIR=root uninstall make clean - rm sampleclient - rm sampleserver + rm -f sampleclient + rm -f sampleserver cd .. -# rm -rf build + rm -rf build } - -build_configuration "-DCMAKE_BUILD_TYPE=Debug -DHTTP_SERVER=YES -DHTTP_CLIENT=YES -DCOMPILE_STUBGEN=YES -DCOMPILE_EXAMPLES=YES -DCOMPILE_TESTS=YES" - +rm -rf reports +mkdir -p reports +build_configuration "-DCMAKE_BUILD_TYPE=Debug -DHTTP_SERVER=YES -DHTTP_CLIENT=YES -DCOMPILE_STUBGEN=YES -DCOMPILE_EXAMPLES=YES -DCOMPILE_TESTS=YES -DUNIX_DOMAIN_SOCKET_SERVER=YES -DUNIX_DOMAIN_SOCKET_CLIENT=YES" echo "Compiling examples" cd build g++ ../src/examples/simpleclient.cpp -Iroot/usr/local/include -Lroot/usr/local/lib -ljsonrpccpp-client -ljsoncpp -ljsonrpccpp-common -lcurl -o sampleclient @@ -32,21 +31,22 @@ g++ ../src/examples/simpleserver.cpp -Iroot/usr/local/include -Lroot/usr/local/l test -f sampleclient test -f sampleserver -mkdir -p reports - echo "Generating valgrind report" -valgrind --leak-check=full --xml=yes --xml-file=reports/valgrind.xml ./bin/unit_testsuite --log_format=XML --log_sink=reports/tests.xml --log_level=all --report_level=no +valgrind --leak-check=full --xml=yes --xml-file=../reports/valgrind.xml ./bin/unit_testsuite --reporter=junit --out=../reports/tests.xml echo "Generating coverage report" -gcovr -x -r .. > reports/coverage.xml -gcovr -r .. --html --html-details -o reports/coverage.html +gcovr -e "build" -e "src/test" -x -r .. > ../reports/coverage.xml +gcovr -e "build" -e "src/test" -r .. --html --html-details -o ../reports/coverage.html echo "Generating cppcheck report" -cppcheck --enable=all --xml ../src 2> reports/cppcheck.xml +cppcheck -I ../src --enable=all --xml ../src --xml-version=2 2> ../reports/cppcheck.xml cd .. echo "Cleanup that mess" cleanup +build_configuration "-DCMAKE_BUILD_TYPE=Debug -DHTTP_SERVER=NO -DHTTP_CLIENT=NO -DCOMPILE_STUBGEN=YES -DCOMPILE_EXAMPLES=YES -DCOMPILE_TESTS=YES -DUNIX_DOMAIN_SOCKET_SERVER=NO -DUNIX_DOMAIN_SOCKET_CLIENT=NO" +cleanup + echo "Integration successful" diff --git a/dev/codestyle/license.txt b/dev/codestyle/license.txt index 7a54a7402ca6910e98558fb1cb56e2d73ce3eb49..6eec411c763fd1ae14e354bfe9efef87255ea0e1 100644 --- a/dev/codestyle/license.txt +++ b/dev/codestyle/license.txt @@ -3,6 +3,6 @@ ************************************************************************* * @file %FILENAME% * @date %DATE% - * @author Peter Spiess-Knafl <peter.knafl@gmail.com> + * @author Peter Spiess-Knafl <dev@spiessknafl.at> * @license See attached LICENSE.txt ************************************************************************/ diff --git a/dev/installdeps.sh b/dev/installdeps.sh new file mode 100644 index 0000000000000000000000000000000000000000..cf6083db98605ed681f9e155d5a98e329e340d3f --- /dev/null +++ b/dev/installdeps.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +sudo apt-get install libmicrohttpd-dev libjsoncpp-dev libcurl4-openssl-dev cmake cppcheck valgrind gcovr diff --git a/dev/testcoverage.sh b/dev/testcoverage.sh index 64cfa2715518bc247d8c75b395e97c0d91c7c346..bec01900602e500bf2d581887d9346a957ec1953 100755 --- a/dev/testcoverage.sh +++ b/dev/testcoverage.sh @@ -10,7 +10,7 @@ bin/unit_testsuite echo "Generate HTML report" mkdir -p reports -gcovr -r .. -d -e "src/test" --html --html-details -o reports/coverage.html +gcovr -r .. -d -e "build" -e "src/test" --html --html-details -o reports/coverage.html xdg-open reports/coverage.html cd ../dev diff --git a/doc/manpage.in b/doc/manpage.in index c85af449772740c24ac65f94d16c089b1c461819..92b54fa5900f1d43fed2b1e408f73704e98b3d3a 100644 --- a/doc/manpage.in +++ b/doc/manpage.in @@ -1,6 +1,6 @@ .\" Manpage for jsonrpcstub. .\" Contact psk@autistici.org to correct errors or typos. -.TH man 1 "22 November 2014" "@MAJOR_VERSION@.@MINOR_VERSION@.@PATCH_VERSION@" "jsonrpcstub man page" +.TH man 1 "7 April 2015" "@MAJOR_VERSION@.@MINOR_VERSION@.@PATCH_VERSION@" "jsonrpcstub man page" .SH NAME jsonrpcstub \- genearate stubs for the libjson\-rpc\-cpp framework. .SH SYNOPSIS @@ -8,7 +8,7 @@ jsonrpcstub \- genearate stubs for the libjson\-rpc\-cpp framework. jsonrpcstub specfile.json [\-\-cpp\-server=namespace::ClassName] [\-\-cpp\-server\-file=classqname.h] [\-\-cpp\-client=namespace::ClassName] [\-\-cpp\-client-file=classname.h] [\-\-js\-client=ClassName] -[\-\-js-client-file=classname.js] [\-h] [\-v] +[\-\-js-client-file=classname.js] [\-h] [\-v] [\-\-version] .PP .SH DESCRIPTION @@ -16,18 +16,18 @@ jsonrpcstub specfile.json [\-\-cpp\-server=namespace::ClassName] jsonrpcstub is a tool to generate C++ and JavaScript classes from a procedure specification file. .SS SPECIFICATION SYNTAX .PP -The specifictaion file is a JSON file containing all available JSON-RPC methods and notifications -with their corresponding parameters and return values contained in a top-level JSON array. +The specifictaion file is a JSON file containing all available JSON\-RPC methods and notifications +with their corresponding parameters and return values contained in a top\-level JSON array. .PP .nf [ { - "name": "method_with_positional_params", - "params": [3,4], + "name": "method_with_positional_params", + "params": [3,4], "returns": 7 }, { - "name": "methid_with_named_params", + "name": "method_with_named_params", "params": {"param1": 3, "param2": 4}, "returns": 7 }, @@ -42,25 +42,27 @@ The literal in each \fB"params"\fP and \fB"returns"\fP section defines the corr If the \fb"params"\fP contains an array, the parameters are accepted by position, if it contains an object, they are accepted by name. .SH OPTIONS -.IP -h +.IP \-h Print usage information. -.IP -v +.IP \-v Print verbose information during generation. -.IP --cpp-server=ClassName +.IP \-\-version +Print version info and exit. +.IP \-\-cpp\-server=ClassName Creates a Abstract Server class. Namespaces can be provided using the :: notation (e.g. ns1::ns2::Classname). -.IP --cpp-server-file=filename.h +.IP \-\-cpp\-server\-file=filename.h Defines the filename to use when generating the C++ Abstract Server class. If this is not provided, the lowercase classname is used. -.IP --cpp-client=ClassName +.IP \-\-cpp\-client=ClassName Creates a C++ client class. Namespaces can be provided using the :: notation (e.g. ns1::ns2::Classname). -.IP --cpp-client-file=filename.h +.IP \-\-cpp\-client\-file=filename.h Defines the filename to use when generating the C++ client class. If this is not provided, the lowercase classname is used. -.IP --js-client=ClassName +.IP \-\-js\-client=ClassName Creates a JavaScript client class. No namespaces are supported in this option. -.IP --js-client-file=filename.js +.IP \-\-js\-client-file=filename.js Defines the filename to use when generating the JavaScrip client class. .SH EXAMPLES .PP @@ -84,7 +86,7 @@ No known bugs. Please report found bugs as an issue on github or send me an emai .SH COPYRIGHT -Copyright (C) 2011\-2014 Peter Spiess-Knafl +Copyright (C) 2011\-2015 Peter Spiess\-Knafl Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the @@ -104,4 +106,4 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH OR OTHER DEALINGS IN THE SOFTWARE. .SH AUTHOR -Peter Spiess-Knafl (psk@autistici.org) +Peter Spiess\-Knafl (dev@spiessknafl.at) diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..6c4e5b3e0970411dd3c21cfc388d8c7c4b7d1073 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,54 @@ +# THIS DOCKERFILE DOWNLOADS AND COMPILES CURL, LIBMICROHTTPD, JSONCPP, ARGTABLE AND LIBJSON-RPC-CPP FOR LINUX/DEBIAN + +# 2015, author: Péricles Lopes Machado (gogo40) <pericles.raskolnikoff@gmail.com> +# Based on Victor Laskin Dockerfile (http://vitiy.info/dockerfile-example-to-compile-libcurl-for-android-inside-docker-container/) + +FROM debian:sid + +MAINTAINER Péricles Lopes Machado <pericles.raskolnikoff@gmail.com> + +# Create output directories + +# Directory to export generated files +RUN mkdir /output + +# Directory with generated files +RUN mkdir /build && mkdir /build/include + +# Install compilation tools + +RUN apt-get update + +RUN apt-get install -y \ +wget \ +build-essential \ +cmake \ +libjsoncpp-dev \ +libargtable2-dev \ +libcurl4-openssl-dev \ +libmicrohttpd-dev \ +git + +# Clone and build libjson-rpc-cpp + +RUN git clone https://github.com/cinemast/libjson-rpc-cpp.git + +RUN cd /libjson-rpc-cpp && \ +cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=ON \ +/libjson-rpc-cpp + +RUN cd /libjson-rpc-cpp && \ +make -j $(nproc) && \ +make install + +# Copy to output generated files + +RUN cp -r /libjson-rpc-cpp/lib /build +RUN cp -r /usr/local/include/jsonrpccpp /build/include/jsonrpccpp + +# To get the results run container with output folder +# Example: docker run -v HOSTFOLDER:/output --rm=true IMAGENAME + +ENTRYPOINT cp -r /build/* /output + + diff --git a/docker/build_linux_debian_libs.sh b/docker/build_linux_debian_libs.sh new file mode 100755 index 0000000000000000000000000000000000000000..a0b56b5a38920aa12b0c2a413c33ce525cc4ed81 --- /dev/null +++ b/docker/build_linux_debian_libs.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +docker build -t debian/libjson-rpc-cpp . +docker run -v $PWD/output:/output --rm=true debian/libjson-rpc-cpp + diff --git a/src/catch/CMakeLists.txt b/src/catch/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..442ce28994f65fbc876f421f14e364cbe51036a0 --- /dev/null +++ b/src/catch/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 2.8) +project(catch_builder CXX) +include(ExternalProject) +find_package(Git REQUIRED) + +ExternalProject_Add( + catch + PREFIX ${CMAKE_BINARY_DIR}/catch + GIT_REPOSITORY https://github.com/philsquared/Catch.git + TIMEOUT 10 + UPDATE_COMMAND ${GIT_EXECUTABLE} pull + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD ON + ) + +# Expose required variable (CATCH_INCLUDE_DIR) to parent scope +ExternalProject_Get_Property(catch source_dir) +set(CATCH_INCLUDE_DIR ${source_dir}/include CACHE INTERNAL "Path to include folder for Catch") diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt index 361de4c15549edf17004da8d3d317374545a3921..e20bd0a26df3652594f3bec31fa8934caac5bbe6 100644 --- a/src/examples/CMakeLists.txt +++ b/src/examples/CMakeLists.txt @@ -1,43 +1,80 @@ file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/gen) -add_custom_command(OUTPUT abstractstubserver.h - COMMAND jsonrpcstub ARGS ${CMAKE_CURRENT_SOURCE_DIR}/spec.json --cpp-server=AbstractStubServer --cpp-server-file=${CMAKE_BINARY_DIR}/gen/abstractsubserver.h - MAIN_DEPENDENCY spec.json - DEPENDS jsonrpcstub - COMMENT "Generating Server Stubfiles" - VERBATIM) - -add_custom_command(OUTPUT stubclient.h - COMMAND jsonrpcstub ARGS ${CMAKE_CURRENT_SOURCE_DIR}/spec.json --cpp-client=StubClient --cpp-client-file=${CMAKE_BINARY_DIR}/gen/stubclient.h - MAIN_DEPENDENCY spec.json - DEPENDS jsonrpcstub - COMMENT "Generating Client Stubfile" - VERBATIM) - -add_custom_command(OUTPUT xbmcremote.h - COMMAND jsonrpcstub ARGS ${CMAKE_CURRENT_SOURCE_DIR}/xbmc_remote.json --cpp-client=XbmcRemoteClient --cpp-client-file=${CMAKE_BINARY_DIR}/gen/xbmcremote.h - MAIN_DEPENDENCY xbmc_remote.json - DEPENDS jsonrpcstub - COMMENT "Generating Client XBMC Stubfile" - VERBATIM) - -INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}) - -IF(HTTP_SERVER AND HTTP_CLIENT) +add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/gen/abstractstubserver.h + COMMAND jsonrpcstub ARGS ${CMAKE_CURRENT_SOURCE_DIR}/spec.json --cpp-server=AbstractStubServer --cpp-server-file=${CMAKE_BINARY_DIR}/gen/abstractstubserver.h + MAIN_DEPENDENCY spec.json + DEPENDS jsonrpcstub + COMMENT "Generating Server Stubfiles" + VERBATIM +) + +add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/gen/stubclient.h + COMMAND jsonrpcstub ARGS ${CMAKE_CURRENT_SOURCE_DIR}/spec.json --cpp-client=StubClient --cpp-client-file=${CMAKE_BINARY_DIR}/gen/stubclient.h + MAIN_DEPENDENCY spec.json + DEPENDS jsonrpcstub + COMMENT "Generating Client Stubfile" + VERBATIM +) + +add_custom_target(common_stubs + DEPENDS ${CMAKE_BINARY_DIR}/gen/abstractstubserver.h ${CMAKE_BINARY_DIR}/gen/stubclient.h +) + +add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/gen/xbmcremote.h + COMMAND jsonrpcstub ARGS ${CMAKE_CURRENT_SOURCE_DIR}/xbmc_remote.json --cpp-client=XbmcRemoteClient --cpp-client-file=${CMAKE_BINARY_DIR}/gen/xbmcremote.h + MAIN_DEPENDENCY xbmc_remote.json + DEPENDS jsonrpcstub + COMMENT "Generating Client XBMC Stubfile" + VERBATIM +) + +include_directories(..) +include_directories(${CMAKE_BINARY_DIR}) +include_directories(${JSONCPP_INCLUDE_DIRS}) +include_directories(${MHD_INCLUDE_DIRS}) + +if(UNIX) + if (UNIX_DOMAIN_SOCKET_SERVER AND UNIX_DOMAIN_SOCKET_CLIENT) + add_executable(unixdomainsocketserversample unixdomainsocketserver.cpp) + target_link_libraries(unixdomainsocketserversample jsonrpcserver) + + add_executable(unixdomainsocketclientsample unixdomainsocketclient.cpp) + target_link_libraries(unixdomainsocketclientsample jsonrpcclient) + endif (UNIX_DOMAIN_SOCKET_SERVER AND UNIX_DOMAIN_SOCKET_CLIENT) +endif(UNIX) + +if (TCP_SOCKET_SERVER AND TCP_SOCKET_CLIENT) + add_executable(tcpsocketclient tcpsocketclient.cpp) + target_link_libraries(tcpsocketclient jsonrpcclient) + + add_executable(tcpsocketserver tcpsocketserver.cpp) + target_link_libraries(tcpsocketserver jsonrpcserver) +endif (TCP_SOCKET_SERVER AND TCP_SOCKET_CLIENT) + +if(HTTP_SERVER) add_executable(simpleserversample simpleserver.cpp) target_link_libraries(simpleserversample jsonrpcserver) +endif() +if(HTTP_CLIENT) add_executable(simpleclientsample simpleclient.cpp) target_link_libraries(simpleclientsample jsonrpcclient) -ENDIF() +endif() -IF(COMPILE_STUBGEN AND HTTP_SERVER AND HTTP_CLIENT) - add_executable(stubclientsample stubclient.cpp stubclient.h) - target_link_libraries(stubclientsample jsonrpcclient) +if (COMPILE_STUBGEN) + if(HTTP_CLIENT) + add_executable(stubclientsample stubclient.cpp ${CMAKE_BINARY_DIR}/gen/stubclient.h) + target_link_libraries(stubclientsample jsonrpcclient) + add_executable(xbmcremote xbmcremote.cpp ${CMAKE_BINARY_DIR}/gen/xbmcremote.h) + target_link_libraries(xbmcremote jsonrpcclient) + endif() - add_executable(stubserversample stubserver.cpp abstractstubserver.h) - target_link_libraries(stubserversample jsonrpcserver) + if(HTTP_SERVER) + add_executable(stubserversample stubserver.cpp ${CMAKE_BINARY_DIR}/gen/abstractstubserver.h) + target_link_libraries(stubserversample jsonrpcserver) + endif() +endif() - add_executable(xbmcremote xbmcremote.cpp xbmcremote.h) - target_link_libraries(xbmcremote jsonrpcclient) -ENDIF() diff --git a/src/examples/index.html b/src/examples/index.html index 450527801e74066d96a9c1f378917d45582de56e..c235c9905880d266c2139a80331e0431766d24a9 100644 --- a/src/examples/index.html +++ b/src/examples/index.html @@ -2,7 +2,6 @@ <html> <head> <meta content="text/html;charset=utf-8" http-equiv="Content-Type"> -<meta content="utf-8" http-equiv="encoding"> <title>Title of the document</title> <script src="http://code.jquery.com/jquery-2.1.1.min.js" type="text/javascript"></script> <!-- diff --git a/src/examples/simpleserver.cpp b/src/examples/simpleserver.cpp index 555ca8b0835f84e0bc93a9e815d5b04e6aca48ea..ab758f138030d8ae64a1b24492c8fea6c6caf97b 100644 --- a/src/examples/simpleserver.cpp +++ b/src/examples/simpleserver.cpp @@ -10,6 +10,8 @@ #include <iostream> #include <jsonrpccpp/server.h> #include <jsonrpccpp/server/connectors/httpserver.h> +#include <jsonrpccpp/server/connectors/unixdomainsocketserver.h> + using namespace jsonrpc; diff --git a/src/examples/stubclient.cpp b/src/examples/stubclient.cpp index e0a99b094860e5c480a8e633d34c0259709f96c8..3b3d81515c940653210f09001eef9b4667b8a5f2 100644 --- a/src/examples/stubclient.cpp +++ b/src/examples/stubclient.cpp @@ -17,6 +17,26 @@ using namespace std; int main() { + + Json::Value a = 3; + Json::Value b = "3"; + + std::map<Json::Value, Json::Value> responses; + + responses[a] = b; + responses[b] = "asölfj"; + + cout << responses[b] << endl; + + if (a == b) + { + cout << a.toStyledString() << " == " << b.toStyledString() << endl; + } + else + { + cout << a.toStyledString() << " != " << b.toStyledString() << endl; + } + HttpClient httpclient("http://localhost:8383"); //StubClient c(httpclient, JSONRPC_CLIENT_V1); //json-rpc 1.0 StubClient c(httpclient, JSONRPC_CLIENT_V2); //json-rpc 2.0 diff --git a/src/examples/stubserver.cpp b/src/examples/stubserver.cpp index d5734bbaaf3760fe891ee1c57d732aeaf26a9bca..e4c37a23b69a3f87e5bb30009a5b9dc0389912d9 100644 --- a/src/examples/stubserver.cpp +++ b/src/examples/stubserver.cpp @@ -8,7 +8,7 @@ ************************************************************************/ #include <iostream> -#include "gen/abstractsubserver.h" +#include "gen/abstractstubserver.h" #include <jsonrpccpp/server/connectors/httpserver.h> #include <stdio.h> diff --git a/src/examples/tcpsocketclient.cpp b/src/examples/tcpsocketclient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98a4a3e0c373b1518798aadc5bbf08d53e5718af --- /dev/null +++ b/src/examples/tcpsocketclient.cpp @@ -0,0 +1,51 @@ +/** + * @file tcpsocketclient.cpp + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @brief tcpsocketclient.cpp + */ + +#include <jsonrpccpp/client.h> +#include <jsonrpccpp/client/connectors/tcpsocketclient.h> +#include <iostream> +#include <cstdlib> + +using namespace jsonrpc; +using namespace std; + +int main(int argc, char** argv) +{ + string host; + unsigned int port; + + if(argc == 3) { + host = string(argv[1]); + port = atoi(argv[2]); + } + else { + host = "127.0.0.1"; + port = 6543; + } + + + cout << "Params are :" << endl; + cout << "\t host: " << host << endl; + cout << "\t port: " << port << endl; + + TcpSocketClient client(host, port); + Client c(client); + + Json::Value params; + params["name"] = "Peter"; + + try + { + cout << c.CallMethod("sayHello", params) << endl; + } + catch (JsonRpcException& e) + { + cerr << e.what() << endl; + } + + +} diff --git a/src/examples/tcpsocketserver.cpp b/src/examples/tcpsocketserver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..25d1d54cb67b1093bedc20999c0b1730b058d330 --- /dev/null +++ b/src/examples/tcpsocketserver.cpp @@ -0,0 +1,82 @@ +/** + * @file unixdomainsocketserver.cpp + * @date 11.05.2015 + * @author Alexandre Poirot + * @brief unixdomainsocketserver.cpp + */ + +#include <stdio.h> +#include <string> +#include <iostream> +#include <jsonrpccpp/server.h> +#include <jsonrpccpp/server/connectors/tcpsocketserver.h> +#include <cstdlib> + + +using namespace jsonrpc; +using namespace std; + +class SampleServer : public AbstractServer<SampleServer> +{ + public: + SampleServer(TcpSocketServer &server) : + AbstractServer<SampleServer>(server) + { + this->bindAndAddMethod(Procedure("sayHello", PARAMS_BY_NAME, JSON_STRING, "name", JSON_STRING, NULL), &SampleServer::sayHello); + this->bindAndAddNotification(Procedure("notifyServer", PARAMS_BY_NAME, NULL), &SampleServer::notifyServer); + } + + //method + void sayHello(const Json::Value& request, Json::Value& response) + { + response = "Hello: " + request["name"].asString(); + } + + //notification + void notifyServer(const Json::Value& request) + { + (void)request; + cout << "server received some Notification" << endl; + } +}; + +int main(int argc, char** argv) +{ + try + { + string ip; + unsigned int port; + + if(argc == 3) + { + ip = string(argv[1]); + port = atoi(argv[2]); + } + else + { + ip = "127.0.0.1"; + port = 6543; + } + + cout << "Params are :" << endl; + cout << "\t ip: " << ip << endl; + cout << "\t port: " << port << endl; + + TcpSocketServer server(ip, port); + SampleServer serv(server); + if (serv.StartListening()) + { + cout << "Server started successfully" << endl; + getchar(); + serv.StopListening(); + } + else + { + cout << "Error starting Server" << endl; + } + } + catch (jsonrpc::JsonRpcException& e) + { + cerr << e.what() << endl; + } +} diff --git a/src/examples/unixdomainsocketclient.cpp b/src/examples/unixdomainsocketclient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80ac0f40bb35a43a708dee36b37997611c473e6d --- /dev/null +++ b/src/examples/unixdomainsocketclient.cpp @@ -0,0 +1,33 @@ +/** + * @file unixdomainsocketclient.cpp + * @date 11.05.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @brief unixdomainsocketclient.cpp + */ + +#include <jsonrpccpp/client.h> +#include <jsonrpccpp/client/connectors/unixdomainsocketclient.h> +#include <iostream> + +using namespace jsonrpc; +using namespace std; + +int main() +{ + UnixDomainSocketClient client("/tmp/unixdomainsocketexample"); + Client c(client); + + Json::Value params; + params["name"] = "Peter"; + + try + { + cout << c.CallMethod("sayHello", params) << endl; + } + catch (JsonRpcException& e) + { + cerr << e.what() << endl; + } + + +} diff --git a/src/examples/unixdomainsocketserver.cpp b/src/examples/unixdomainsocketserver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..04d694abe6aafeabf722c2cb8d709eee6565e244 --- /dev/null +++ b/src/examples/unixdomainsocketserver.cpp @@ -0,0 +1,63 @@ +/** + * @file unixdomainsocketserver.cpp + * @date 11.05.2015 + * @author Alexandre Poirot + * @brief unixdomainsocketserver.cpp + */ + +#include <stdio.h> +#include <string> +#include <iostream> +#include <jsonrpccpp/server.h> +#include <jsonrpccpp/server/connectors/unixdomainsocketserver.h> + + +using namespace jsonrpc; +using namespace std; + +class SampleServer : public AbstractServer<SampleServer> +{ + public: + SampleServer(UnixDomainSocketServer &server) : + AbstractServer<SampleServer>(server) + { + this->bindAndAddMethod(Procedure("sayHello", PARAMS_BY_NAME, JSON_STRING, "name", JSON_STRING, NULL), &SampleServer::sayHello); + this->bindAndAddNotification(Procedure("notifyServer", PARAMS_BY_NAME, NULL), &SampleServer::notifyServer); + } + + //method + void sayHello(const Json::Value& request, Json::Value& response) + { + response = "Hello: " + request["name"].asString(); + } + + //notification + void notifyServer(const Json::Value& request) + { + (void)request; + cout << "server received some Notification" << endl; + } +}; + +int main() +{ + try + { + UnixDomainSocketServer server("/tmp/unixdomainsocketexample"); + SampleServer serv(server); + if (serv.StartListening()) + { + cout << "Server started successfully" << endl; + getchar(); + serv.StopListening(); + } + else + { + cout << "Error starting Server" << endl; + } + } + catch (jsonrpc::JsonRpcException& e) + { + cerr << e.what() << endl; + } +} diff --git a/src/jsonrpccpp/CMakeLists.txt b/src/jsonrpccpp/CMakeLists.txt index 79c44096a59558b0972b0941b6081b40184da296..d82cc9aa6453c642bfc1d458c5c938d7d68efb0b 100644 --- a/src/jsonrpccpp/CMakeLists.txt +++ b/src/jsonrpccpp/CMakeLists.txt @@ -1,27 +1,30 @@ -find_package(JSONCPP REQUIRED) -find_package(Threads REQUIRED) - +# setup common headers and sources +file(GLOB jsonrpc_header *.h) +file(GLOB jsonrpc_header_common common/*.h) file(GLOB jsonrpc_source_common common/*.c*) -file(GLOB jsonrpc_source_client client/*.c*) -file(GLOB jsonrpc_source_server server/*.c*) -list(APPEND jsonrpc_source_server server/abstractserver.h) -file(GLOB jsonrpc_header_common common/*.h) -file(GLOB jsonrpc_header_client - client/batchcall.h - client/batchresponse.h - client/client.h - client/iclientconnector.h +# setup server headers and sources +file(GLOB jsonrpc_install_header_server + server/requesthandlerfactory.h + server/abstractserver.h + server/abstractserverconnector.h + server/iprocedureinvokationhandler.h + server/iclientconnectionhandler.h ) -file(GLOB jsonrpc_header_server - server/requesthandlerfactory.h - server/abstractserver.h - server/abstractserverconnector.h - server/iprocedureinvokationhandler.h - server/iclientconnectionhandler.h +file(GLOB jsonrpc_header_server server/*.h) +file(GLOB jsonrpc_source_server server/*.c*) + +# setup client headers and sources +file(GLOB jsonrpc_install_header_client + client/batchcall.h + client/batchresponse.h + client/client.h + client/iclientconnector.h ) -file(GLOB jsonrpc_header *.h) +file(GLOB jsonrpc_header_client client/*.h) +file(GLOB jsonrpc_source_client client/*.c*) +# setup connector variables defaults set(client_connector_source "") set(client_connector_header "") set(client_connector_libs "") @@ -29,78 +32,185 @@ set(server_connector_source "") set(server_connector_header "") set(server_connector_libs "") - -# configure a header file to pass some of the CMake settings -# to the source code -file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/gen/jsonrpccpp/common") -configure_file("${PROJECT_SOURCE_DIR}/src/jsonrpccpp/version.h.in" "${PROJECT_BINARY_DIR}/gen/jsonrpccpp/version.h") -configure_file("${PROJECT_SOURCE_DIR}/src/jsonrpccpp/common/jsonparser.h.in" "${PROJECT_BINARY_DIR}/gen/jsonrpccpp/common/jsonparser.h") - -install(FILES "${PROJECT_BINARY_DIR}/gen/jsonrpccpp/version.h" DESTINATION include/jsonrpccpp) +# setup sources for http connectors +if (HTTP_CLIENT) + list(APPEND client_connector_header "client/connectors/httpclient.h") + list(APPEND client_connector_source "client/connectors/httpclient.cpp") + list(APPEND client_connector_libs ${CURL_LIBRARIES}) + include_directories(${CURL_INCLUDE_DIRS}) +endif() + +if (HTTP_SERVER) + list(APPEND server_connector_header "server/connectors/httpserver.h") + list(APPEND server_connector_source "server/connectors/httpserver.cpp") + list(APPEND server_connector_libs ${CMAKE_THREAD_LIBS_INIT} ${MHD_LIBRARIES}) +endif() + +# setup sources for unix domain socket connectors +if (UNIX_DOMAIN_SOCKET_SERVER) + list(APPEND server_connector_header "server/connectors/unixdomainsocketserver.h") + list(APPEND server_connector_source "server/connectors/unixdomainsocketserver.cpp") + list(APPEND server_connector_libs ${CMAKE_THREAD_LIBS_INIT}) +endif() + +if (UNIX_DOMAIN_SOCKET_CLIENT) + list(APPEND client_connector_header "client/connectors/unixdomainsocketclient.h") + list(APPEND client_connector_source "client/connectors/unixdomainsocketclient.cpp") +endif() + +# setup sources for tcp socket connectors +if (TCP_SOCKET_SERVER) + list(APPEND server_connector_header "server/connectors/tcpsocketserver.h") + list(APPEND server_connector_source "server/connectors/tcpsocketserver.cpp") + if (WIN32) + list(APPEND server_connector_header "server/connectors/windowstcpsocketserver.h") + list(APPEND server_connector_source "server/connectors/windowstcpsocketserver.cpp") + list(APPEND server_connector_libs ws2_32) + endif() + if(UNIX) + list(APPEND server_connector_header "server/connectors/linuxtcpsocketserver.h") + list(APPEND server_connector_source "server/connectors/linuxtcpsocketserver.cpp") + endif() + list(APPEND server_connector_libs ${CMAKE_THREAD_LIBS_INIT}) +endif() + +if (TCP_SOCKET_CLIENT) + list(APPEND client_connector_header "client/connectors/tcpsocketclient.h") + list(APPEND client_connector_source "client/connectors/tcpsocketclient.cpp") + if (WIN32) + list(APPEND client_connector_header "client/connectors/windowstcpsocketclient.h") + list(APPEND client_connector_source "client/connectors/windowstcpsocketclient.cpp") + list(APPEND client_connector_libs ws2_32) + endif() + if(UNIX) + list(APPEND client_connector_header "client/connectors/linuxtcpsocketclient.h") + list(APPEND client_connector_source "client/connectors/linuxtcpsocketclient.cpp") + endif() + list(APPEND client_connector_libs ${CMAKE_THREAD_LIBS_INIT}) +endif() + +# configure a header file to pass some of the CMake settings to the source code +# TODO: move it to custom build step? +file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/gen/jsonrpccpp/common") +configure_file("${PROJECT_SOURCE_DIR}/src/jsonrpccpp/version.h.in" "${CMAKE_BINARY_DIR}/gen/jsonrpccpp/version.h") +configure_file("${PROJECT_SOURCE_DIR}/src/jsonrpccpp/common/jsonparser.h.in" "${CMAKE_BINARY_DIR}/gen/jsonrpccpp/common/jsonparser.h") + +install(FILES "${CMAKE_BINARY_DIR}/gen/jsonrpccpp/version.h" DESTINATION include/jsonrpccpp) install(FILES "${PROJECT_BINARY_DIR}/gen/jsonrpccpp/common/jsonparser.h" DESTINATION include/jsonrpccpp/common) -include_directories("${PROJECT_SOURCE_DIR}/src/") -include_directories("${PROJECT_BINARY_DIR}/gen/") -include_directories("${PROJECT_BINARY_DIR}/gen/jsonrpccpp/common") - -IF(HTTP_CLIENT) - find_package(CURL REQUIRED) - list(APPEND client_connector_header "client/connectors/httpclient.h") - list(APPEND client_connector_source "client/connectors/httpclient.cpp") - list(APPEND client_connector_libs ${CURL_LIBRARIES}) -ENDIF() - -IF(HTTP_SERVER) - message(STATUS "Activated libmicrohttpd HTTP Server") - find_package(MHD REQUIRED) - list(APPEND server_connector_header "server/connectors/httpserver.h") - list(APPEND server_connector_source "server/connectors/httpserver.cpp") - list(APPEND server_connector_libs ${CMAKE_THREAD_LIBS_INIT} ${MHD_LIBRARIES}) -ENDIF() - -add_library(jsonrpccommon SHARED ${jsonrpc_source_common} ${jsonrpc_header} ${jsonrpc_helper_source_common}) -add_library(jsonrpccommonStatic STATIC ${jsonrpc_source_common} ${jsonrpc_header} ${jsonrpc_helper_source_common}) -target_link_libraries(jsonrpccommon ${JSONCPP_LIBRARIES}) -target_link_libraries(jsonrpccommonStatic ${JSONCPP_LIBRARIES}) -set_target_properties(jsonrpccommonStatic PROPERTIES OUTPUT_NAME jsonrpccpp-common) -set_target_properties(jsonrpccommon PROPERTIES OUTPUT_NAME jsonrpccpp-common) - - -add_library(jsonrpcclient SHARED ${jsonrpc_source_client} ${jsonrpc_header} ${jsonrpc_header_client} ${client_connector_source}) -add_library(jsonrpcclientStatic STATIC ${jsonrpc_source_client} ${jsonrpc_header} ${jsonrpc_header_client} ${client_connector_source}) -target_link_libraries(jsonrpcclient jsonrpccommon ${client_connector_libs}) -target_link_libraries(jsonrpcclientStatic jsonrpccommonStatic ${client_connector_libs}) -set_target_properties(jsonrpcclientStatic PROPERTIES OUTPUT_NAME jsonrpccpp-client) -set_target_properties(jsonrpcclient PROPERTIES OUTPUT_NAME jsonrpccpp-client) - - -add_library(jsonrpcserver SHARED ${jsonrpc_source_server} ${jsonrpc_header} ${jsonrpc_header_server} ${server_connector_source}) -add_library(jsonrpcserverStatic STATIC ${jsonrpc_source_server} ${jsonrpc_header} ${jsonrpc_header_server} ${server_connector_source}) -target_link_libraries(jsonrpcserver jsonrpccommon ${server_connector_libs}) -target_link_libraries(jsonrpcserverStatic jsonrpccommonStatic ${server_connector_libs}) -set_target_properties(jsonrpcserverStatic PROPERTIES OUTPUT_NAME jsonrpccpp-server) -set_target_properties(jsonrpcserver PROPERTIES OUTPUT_NAME jsonrpccpp-server) - - +# include required directories +include_directories(..) +include_directories(${JSONCPP_INCLUDE_DIRS}) +include_directories(${MHD_INCLUDE_DIRS}) + +# setup shared common library +if (BUILD_SHARED_LIBS) + add_library(jsonrpccommon SHARED ${jsonrpc_source_common} ${jsonrpc_header} ${jsonrpc_helper_source_common}) + target_link_libraries(jsonrpccommon ${JSONCPP_LIBRARIES}) + set_target_properties(jsonrpccommon PROPERTIES OUTPUT_NAME jsonrpccpp-common) +endif() + +# setup static common library +if (BUILD_STATIC_LIBS OR MSVC) + add_library(jsonrpccommonStatic STATIC ${jsonrpc_source_common} ${jsonrpc_header} ${jsonrpc_helper_source_common}) + target_link_libraries(jsonrpccommonStatic ${JSONCPP_LIBRARIES}) + set_target_properties(jsonrpccommonStatic PROPERTIES OUTPUT_NAME jsonrpccpp-common) + + if (NOT BUILD_SHARED_LIBS) + add_library(jsonrpccommon ALIAS jsonrpccommonStatic) + endif() +endif() + +# setup shared client library +if (BUILD_SHARED_LIBS) + add_library(jsonrpcclient SHARED ${jsonrpc_source_client} ${jsonrpc_header} ${jsonrpc_header_client} ${client_connector_source}) + add_dependencies(jsonrpcclient jsonrpccommon) + target_link_libraries(jsonrpcclient jsonrpccommon ${client_connector_libs}) + set_target_properties(jsonrpcclient PROPERTIES OUTPUT_NAME jsonrpccpp-client) +endif() + +# setup static client library +if (BUILD_STATIC_LIBS OR MSVC) + add_library(jsonrpcclientStatic STATIC ${jsonrpc_source_client} ${jsonrpc_header} ${jsonrpc_header_client} ${client_connector_source}) + target_link_libraries(jsonrpcclientStatic jsonrpccommonStatic ${client_connector_libs}) + set_target_properties(jsonrpcclientStatic PROPERTIES OUTPUT_NAME jsonrpccpp-client) + + if (NOT BUILD_SHARED_LIBS) + add_library(jsonrpcclient ALIAS jsonrpcclientStatic) + endif() +endif() + +# setup shared server library +if (BUILD_SHARED_LIBS) + add_library(jsonrpcserver SHARED ${jsonrpc_source_server} ${jsonrpc_header} ${jsonrpc_header_server} ${server_connector_source}) + add_dependencies(jsonrpcserver jsonrpccommon) + target_link_libraries(jsonrpcserver jsonrpccommon ${server_connector_libs}) + set_target_properties(jsonrpcserver PROPERTIES OUTPUT_NAME jsonrpccpp-server) +endif() + +# setup static server library +if (BUILD_STATIC_LIBS OR MSVC) + add_library(jsonrpcserverStatic STATIC ${jsonrpc_source_server} ${jsonrpc_header} ${jsonrpc_header_server} ${server_connector_source}) + target_link_libraries(jsonrpcserverStatic jsonrpccommonStatic ${server_connector_libs}) + set_target_properties(jsonrpcserverStatic PROPERTIES OUTPUT_NAME jsonrpccpp-server) + + if (NOT BUILD_SHARED_LIBS) + add_library(jsonrpcserver ALIAS jsonrpcserverStatic) + endif() +endif() + +set(ALL_LIBS) + +if (BUILD_SHARED_LIBS OR NOT BUILD_STATIC_LIBS) + list(APPEND ALL_LIBS jsonrpccommon jsonrpcclient jsonrpcserver) +endif() + +if (BUILD_STATIC_LIBS OR MSVC) + list(APPEND ALL_LIBS jsonrpccommonStatic jsonrpcclientStatic jsonrpcserverStatic) +endif() + +# setup version set(VERSION_STRING ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}) -set_target_properties(jsonrpccommon jsonrpccommonStatic jsonrpcclient jsonrpcclientStatic jsonrpcserver jsonrpcserverStatic PROPERTIES VERSION "${VERSION_STRING}" SOVERSION "${SO_VERSION}") +set_target_properties( + ${ALL_LIBS} + PROPERTIES VERSION "${VERSION_STRING}" SOVERSION "${SO_VERSION}" +) +# install libraries install(FILES ${jsonrpc_header} DESTINATION include/jsonrpccpp) install(FILES ${jsonrpc_header_common} DESTINATION include/jsonrpccpp/common) install(FILES ${jsonrpc_helper_header_common} DESTINATION include/jsonrpccpp/common/helper) -install(FILES ${jsonrpc_header_client} DESTINATION include/jsonrpccpp/client) -install(FILES ${jsonrpc_header_server} DESTINATION include/jsonrpccpp/server) +install(FILES ${jsonrpc_install_header_client} DESTINATION include/jsonrpccpp/client) +install(FILES ${jsonrpc_install_header_server} DESTINATION include/jsonrpccpp/server) install(FILES ${client_connector_header} DESTINATION include/jsonrpccpp/client/connectors) install(FILES ${server_connector_header} DESTINATION include/jsonrpccpp/server/connectors) -IF(WIN32) - file(GLOB win32_libs ${CMAKE_SOURCE_DIR}/win32-deps/lib/*.dll) - file(COPY ${win32_libs} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) - install(FILES ${win32_libs} DESTINATION bin) - install(DIRECTORY ${CMAKE_SOURCE_DIR}/win32-deps/include DESTINATION .) -ENDIF() - -install(TARGETS jsonrpccommon jsonrpccommonStatic jsonrpcclient jsonrpcclientStatic jsonrpcserver jsonrpcserverStatic - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin) +if (WIN32) + file(GLOB win32_libs ${CMAKE_SOURCE_DIR}/win32-deps/lib/*.dll) + file(COPY ${win32_libs} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + install(FILES ${win32_libs} DESTINATION bin) + install(DIRECTORY ${CMAKE_SOURCE_DIR}/win32-deps/include DESTINATION .) +endif() + +install(TARGETS ${ALL_LIBS} + LIBRARY DESTINATION lib${LIB_SUFFIX}/${CMAKE_LIBRARY_PATH} + ARCHIVE DESTINATION lib${LIB_SUFFIX}/${CMAKE_LIBRARY_PATH} + RUNTIME DESTINATION bin +) + +#set pkg-config +get_filename_component(FULL_PATH_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} ABSOLUTE) +set(FULL_PATH_INCLUDEDIR "${FULL_PATH_INSTALL_PREFIX}/include") +set(FULL_PATH_LIBDIR "${FULL_PATH_INSTALL_PREFIX}/lib/${CMAKE_LIBRARY_PATH}") + +CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/cmake/libjsonrpccpp-client.pc.cmake ${CMAKE_BINARY_DIR}/libjsonrpccpp-client.pc) +CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/cmake/libjsonrpccpp-server.pc.cmake ${CMAKE_BINARY_DIR}/libjsonrpccpp-server.pc) +CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/cmake/libjsonrpccpp-common.pc.cmake ${CMAKE_BINARY_DIR}/libjsonrpccpp-common.pc) + +INSTALL(FILES + "${CMAKE_BINARY_DIR}/libjsonrpccpp-server.pc" + "${CMAKE_BINARY_DIR}/libjsonrpccpp-client.pc" + "${CMAKE_BINARY_DIR}/libjsonrpccpp-common.pc" + DESTINATION "lib${LIB_SUFFIX}/${CMAKE_LIBRARY_PATH}/pkgconfig") + + diff --git a/src/jsonrpccpp/client/batchresponse.cpp b/src/jsonrpccpp/client/batchresponse.cpp index 8628fd88e072d7011ea337dd3e20715284a2a78b..6e59d78f8f2217ce3ee6fbeab0a71ea4a7ff406e 100644 --- a/src/jsonrpccpp/client/batchresponse.cpp +++ b/src/jsonrpccpp/client/batchresponse.cpp @@ -18,7 +18,7 @@ BatchResponse::BatchResponse() { } -void BatchResponse::addResponse(int id, Json::Value response, bool isError) +void BatchResponse::addResponse(Json::Value &id, Json::Value response, bool isError) { if (isError) { errorResponses.push_back(id); @@ -26,14 +26,22 @@ void BatchResponse::addResponse(int id, Json::Value response, bool isError) responses[id] = response; } -Json::Value BatchResponse::getResult(int id) +Json::Value BatchResponse::getResult(Json::Value& id) { Json::Value result; getResult(id, result); return result; } -void BatchResponse::getResult(int id, Json::Value &result) +Json::Value BatchResponse::getResult(int id) +{ + Json::Value result; + Json::Value i = id; + getResult(i, result); + return result; +} + +void BatchResponse::getResult(Json::Value& id, Json::Value &result) { if (getErrorCode(id) == 0) result = responses[id]; @@ -41,7 +49,7 @@ void BatchResponse::getResult(int id, Json::Value &result) result = Json::nullValue; } -int BatchResponse::getErrorCode(int id) +int BatchResponse::getErrorCode(Json::Value& id) { if(std::find(errorResponses.begin(), errorResponses.end(), id) != errorResponses.end()) { @@ -50,7 +58,7 @@ int BatchResponse::getErrorCode(int id) return 0; } -string BatchResponse::getErrorMessage(int id) +string BatchResponse::getErrorMessage(Json::Value& id) { if(std::find(errorResponses.begin(), errorResponses.end(), id) != errorResponses.end()) { @@ -59,6 +67,12 @@ string BatchResponse::getErrorMessage(int id) return ""; } +string BatchResponse::getErrorMessage(int id) +{ + Json::Value i = id; + return getErrorMessage(i); +} + bool BatchResponse::hasErrors() { return !errorResponses.empty(); diff --git a/src/jsonrpccpp/client/batchresponse.h b/src/jsonrpccpp/client/batchresponse.h index 6480cce00eb29cc52921f0f6ee6f036a73606bb4..fa44be9a530d26608f03cb0f56cb387b87d3c383 100644 --- a/src/jsonrpccpp/client/batchresponse.h +++ b/src/jsonrpccpp/client/batchresponse.h @@ -29,7 +29,7 @@ namespace jsonrpc { * @param response * @param isError */ - void addResponse(int id, Json::Value response, bool isError = false); + void addResponse(Json::Value& id, Json::Value response, bool isError = false); /** * @brief getResult method gets the result for a given request id (returned by BatchCall::addCall. @@ -37,29 +37,33 @@ namespace jsonrpc { * @param id * @return */ + Json::Value getResult(Json::Value& id); + Json::Value getResult(int id); - void getResult(int id, Json::Value &result); + void getResult(Json::Value& id, Json::Value &result); /** * @brief getErrorCode method checks if for a given id, an error occurred in the batch request. * @param id */ - int getErrorCode(int id); + int getErrorCode(Json::Value& id); /** * @brief getErrorMessage method gets the corresponding error message. * @param id * @return the error message in case of an error, an empty string if no error was found for the provided id. */ + std::string getErrorMessage(Json::Value& id); + std::string getErrorMessage(int id); bool hasErrors(); private: - std::map<int, Json::Value> responses; - std::vector<int> errorResponses; + std::map<Json::Value, Json::Value> responses; + std::vector<Json::Value> errorResponses; }; diff --git a/src/jsonrpccpp/client/client.cpp b/src/jsonrpccpp/client/client.cpp index 0f09e64c26f4a8b1176f7fff175cda5a90cac243..7ce965873f6e7713c7b399718c4ade3dac635fd2 100644 --- a/src/jsonrpccpp/client/client.cpp +++ b/src/jsonrpccpp/client/client.cpp @@ -49,13 +49,13 @@ void Client::CallProcedures(const BatchCall &calls, BatchResponse &result) throw if (tmpresult[i].isObject()) { Json::Value singleResult; try { - int id = this->protocol->HandleResponse(tmpresult[i], singleResult); + Json::Value id = this->protocol->HandleResponse(tmpresult[i], singleResult); result.addResponse(id, singleResult, false); } catch (JsonRpcException& ex) { - int id = -1; - if(tmpresult[i].isMember("id") && tmpresult[i]["id"].isInt()) - id = tmpresult[i]["id"].asInt(); + Json::Value id = -1; + if(tmpresult[i].isMember("id")) + id = tmpresult[i]["id"]; result.addResponse(id, tmpresult[i]["error"], true); } } diff --git a/src/jsonrpccpp/client/connectors/httpclient.cpp b/src/jsonrpccpp/client/connectors/httpclient.cpp index f66e2ad4aa1a3ed368fe1726674fcebfcd70f936..58590f19aa10ffab7c7a65e969c0f8c036fff825 100644 --- a/src/jsonrpccpp/client/connectors/httpclient.cpp +++ b/src/jsonrpccpp/client/connectors/httpclient.cpp @@ -17,6 +17,15 @@ using namespace jsonrpc; +class curl_initializer { + public: + curl_initializer() {curl_global_init(CURL_GLOBAL_ALL);} + ~curl_initializer() {curl_global_cleanup();} +}; + +// See here: http://curl.haxx.se/libcurl/c/curl_global_init.html +static curl_initializer _curl_init = curl_initializer(); + /** * taken from http://stackoverflow.com/questions/2329571/c-libcurl-get-output-into-a-string */ @@ -48,11 +57,16 @@ HttpClient::HttpClient(const std::string& url) throw(JsonRpcException) : url(url) { this->timeout = 10000; + curl = curl_easy_init(); +} + +HttpClient::~HttpClient() +{ + curl_easy_cleanup(curl); } void HttpClient::SendRPCMessage(const std::string& message, std::string& result) throw (JsonRpcException) { - CURL* curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, this->url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc); @@ -89,7 +103,6 @@ void HttpClient::SendRPCMessage(const std::string& message, std::string& result) str << " -> Could not connect to " << this->url; else if(res == 28) str << " -> Operation timed out"; - curl_easy_cleanup(curl); throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, str.str()); } @@ -98,11 +111,8 @@ void HttpClient::SendRPCMessage(const std::string& message, std::string& result) if (http_code != 200) { - curl_easy_cleanup(curl); throw JsonRpcException(Errors::ERROR_RPC_INTERNAL_ERROR, result); } - - curl_easy_cleanup(curl); } void HttpClient::SetUrl(const std::string& url) diff --git a/src/jsonrpccpp/client/connectors/httpclient.h b/src/jsonrpccpp/client/connectors/httpclient.h index 6f87c61e56dd4466d777855c197dbab2d1b81fed..5e2ef2174015cafa5950bcb8dd72a2c3a42ff470 100644 --- a/src/jsonrpccpp/client/connectors/httpclient.h +++ b/src/jsonrpccpp/client/connectors/httpclient.h @@ -12,6 +12,7 @@ #include "../iclientconnector.h" #include <jsonrpccpp/common/exception.h> +#include <curl/curl.h> #include <map> namespace jsonrpc @@ -20,7 +21,7 @@ namespace jsonrpc { public: HttpClient(const std::string& url) throw (JsonRpcException); - + virtual ~HttpClient(); virtual void SendRPCMessage(const std::string& message, std::string& result) throw (JsonRpcException); void SetUrl(const std::string& url); @@ -37,6 +38,7 @@ namespace jsonrpc * @brief timeout for http request in milliseconds */ long timeout; + CURL* curl; }; } /* namespace jsonrpc */ diff --git a/src/jsonrpccpp/client/connectors/linuxtcpsocketclient.cpp b/src/jsonrpccpp/client/connectors/linuxtcpsocketclient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..631998dde062fff8ddc33781ed8f9caf7a041c91 --- /dev/null +++ b/src/jsonrpccpp/client/connectors/linuxtcpsocketclient.cpp @@ -0,0 +1,237 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file linuxtcpsocketclient.cpp + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#include "linuxtcpsocketclient.h" +#include <string.h> +#include <cstdio> +#include <cstdlib> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <iostream> +#include <errno.h> +#include <cstring> + +#define BUFFER_SIZE 64 +#ifndef DELIMITER_CHAR +#define DELIMITER_CHAR char(0x0A) +#endif //DELIMITER_CHAR + +using namespace jsonrpc; +using namespace std; + +LinuxTcpSocketClient::LinuxTcpSocketClient(const std::string& hostToConnect, const unsigned int &port) : + TcpSocketClientPrivate(), + hostToConnect(hostToConnect), + port(port) +{ +} + +LinuxTcpSocketClient::~LinuxTcpSocketClient() +{ +} + +void LinuxTcpSocketClient::SendRPCMessage(const std::string& message, std::string& result) throw (JsonRpcException) +{ + int socket_fd = this->Connect(); + char buffer[BUFFER_SIZE]; + + bool fullyWritten = false; + string toSend = message; + do + { + ssize_t byteWritten = send(socket_fd, toSend.c_str(), toSend.size(), 0); + if(byteWritten == -1) + { + string message = "send() failed"; + int err = errno; + switch(err) + { + case EACCES: + case EWOULDBLOCK: + case EBADF: + case ECONNRESET: + case EDESTADDRREQ: + case EFAULT: + case EINTR: + case EINVAL: + case EISCONN: + case EMSGSIZE: + case ENOBUFS: + case ENOMEM: + case ENOTCONN: + case ENOTSOCK: + case EOPNOTSUPP: + case EPIPE: + message = strerror(err); + break; + } + close(socket_fd); + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, message); + } + else if(static_cast<size_t>(byteWritten) < toSend.size()) + { + int len = toSend.size() - byteWritten; + toSend = toSend.substr(byteWritten + sizeof(char), len); + } + else + fullyWritten = true; + } while(!fullyWritten); + + do + { + int nbytes = recv(socket_fd, buffer, BUFFER_SIZE, 0); + if(nbytes == -1) + { + string message = "recv() failed"; + int err = errno; + switch(err) + { + case EWOULDBLOCK: + case EBADF: + case ECONNRESET: + case EFAULT: + case EINTR: + case EINVAL: + case ENOMEM: + case ENOTCONN: + case ENOTSOCK: + message = strerror(err); + break; + } + close(socket_fd); + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, message); + } + else + { + string tmp; + tmp.append(buffer, nbytes); + result.append(buffer,nbytes); + } + } while(result.find(DELIMITER_CHAR) == string::npos); + + close(socket_fd); +} + +int LinuxTcpSocketClient::Connect() throw (JsonRpcException) +{ + if(this->IsIpv4Address(this->hostToConnect)) + { + return this->Connect(this->hostToConnect, this->port); + } + else //We were given a hostname + { + struct addrinfo *result = NULL; + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + char port[6]; + snprintf(port, 6, "%d", this->port); + int retval = getaddrinfo(this->hostToConnect.c_str(), port, &hints, &result); + if(retval != 0) + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, "Could not resolve hostname."); + bool foundValidIp = false; + int socket_fd; + for(struct addrinfo *temp = result; (temp != NULL) && !foundValidIp; temp = temp->ai_next) + { + if(temp->ai_family == AF_INET) + { + try + { + sockaddr_in* sock = reinterpret_cast<sockaddr_in*>(temp->ai_addr); + socket_fd = this->Connect(inet_ntoa(sock->sin_addr), ntohs(sock->sin_port)); + foundValidIp = true; + } + catch(const JsonRpcException& e) + { + foundValidIp = false; + socket_fd = -1; + } + catch(void* p) + { + foundValidIp = false; + socket_fd = -1; + } + } + } + + if(!foundValidIp) + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, "Hostname resolved but connection was refused on the given port."); + + return socket_fd; + } +} + +int LinuxTcpSocketClient::Connect(const string& ip, const int& port) throw (JsonRpcException) +{ + sockaddr_in address; + int socket_fd; + socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd < 0) + { + string message = "socket() failed"; + int err = errno; + switch(err) + { + case EACCES: + case EAFNOSUPPORT: + case EINVAL: + case EMFILE: + case ENOBUFS: + case ENOMEM: + case EPROTONOSUPPORT: + message = strerror(err); + break; + } + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, message); + } + memset(&address, 0, sizeof(sockaddr_in)); + + address.sin_family = AF_INET; + inet_aton(ip.c_str(), &(address.sin_addr)); + address.sin_port = htons(port); + + if(connect(socket_fd, (struct sockaddr *) &address, sizeof(sockaddr_in)) != 0) + { + string message = "connect() failed"; + int err = errno; + switch(err) + { + case EACCES: + case EPERM: + case EADDRINUSE: + case EAFNOSUPPORT: + case EAGAIN: + case EALREADY: + case EBADF: + case ECONNREFUSED: + case EFAULT: + case EINPROGRESS: + case EINTR: + case EISCONN: + case ENETUNREACH: + case ENOTSOCK: + case ETIMEDOUT: + message = strerror(err); + break; + } + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, message); + } + return socket_fd; +} + +bool LinuxTcpSocketClient::IsIpv4Address(const std::string& ip) +{ + struct in_addr addr; + return (inet_aton(ip.c_str(), &addr) != 0); +} diff --git a/src/jsonrpccpp/client/connectors/linuxtcpsocketclient.h b/src/jsonrpccpp/client/connectors/linuxtcpsocketclient.h new file mode 100644 index 0000000000000000000000000000000000000000..5d05315fc6553cbb630ce4e733b3a909cf14ab85 --- /dev/null +++ b/src/jsonrpccpp/client/connectors/linuxtcpsocketclient.h @@ -0,0 +1,79 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file linuxtcpsocketclient.h + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#ifndef JSONRPC_CPP_LINUXTCPSOCKETCLIENT_H_ +#define JSONRPC_CPP_LINUXTCPSOCKETCLIENT_H_ + +#include <jsonrpccpp/common/exception.h> +#include <string> +#include "tcpsocketclientprivate.h" + +namespace jsonrpc +{ + /** + * This class is the Linux/UNIX implementation of TCPSocketClient. + * It uses the POSIX socket API to performs its job. + */ + class LinuxTcpSocketClient : public TcpSocketClientPrivate + { + public: + /** + * @brief LinuxTcpSocketClient, constructor of the Linux/UNIX implementation of class TcpSocketClient + * @param hostToConnect The hostname or the ipv4 address on which the client should try to connect + * @param port The port on which the client should try to connect + */ + LinuxTcpSocketClient(const std::string& hostToConnect, const unsigned int &port); + /** + * @brief ~LinuxTcpSocketClient, the destructor of LinuxTcpSocketClient + */ + virtual ~LinuxTcpSocketClient(); + /** + * @brief The real implementation of TcpSocketClient::SendRPCMessage method. + * @param message The message to send + * @param result The result of the call returned by the server + * @throw JsonRpcException Thrown when an issue is encountered with socket manipulation (see message of exception for more information about what happened). + */ + virtual void SendRPCMessage(const std::string& message, std::string& result) throw (JsonRpcException); + + private: + std::string hostToConnect; /*!< The hostname or the ipv4 address on which the client should try to connect*/ + unsigned int port; /*!< The port on which the client should try to connect*/ + /** + * @brief Connects to the host and port provided by constructor parameters. + * + * This method detects if the hostToConnect attribute is either an IPv4 or a hostname. + * On first case it tries to connect to the ip. + * On second case it tries to resolve hostname to an ip and tries to connect to it if resolve was successful. + * + * @returns A file descriptor to the successfully connected socket + * @throw JsonRpcException Thrown when an issue is encountered while trying to connect (see message of exception for more information about what happened). + */ + int Connect() throw (JsonRpcException); + /** + * @brief Connects to provided ip and port. + * + * This method tries to connect to the provided ip and port. + * + * @param ip The ipv4 address to connect to + * @param port The port to connect to + * @returns A file descriptor to the successfully connected socket + * @throw JsonRpcException Thrown when an issue is encountered while trying to connect (see message of exception for more information about what happened). + */ + int Connect(const std::string& ip, const int& port) throw (JsonRpcException); + /** + * @brief Check if provided ip is an ipv4 address. + * + * @param ip The ipv4 address to check + * @returns A boolean indicating if the provided ip is or is not an ipv4 address + */ + bool IsIpv4Address(const std::string& ip); + }; + +} /* namespace jsonrpc */ +#endif /* JSONRPC_CPP_LINUXTCPSOCKETCLIENT_H_ */ diff --git a/src/jsonrpccpp/client/connectors/tcpsocketclient.cpp b/src/jsonrpccpp/client/connectors/tcpsocketclient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..874e0faa7972c8734291c89164e37cade7a09f88 --- /dev/null +++ b/src/jsonrpccpp/client/connectors/tcpsocketclient.cpp @@ -0,0 +1,47 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file tcpsocketclient.cpp + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#include "tcpsocketclient.h" + +#ifdef __WIN32__ +#include "windowstcpsocketclient.h" +#elif __unix__ +#include "linuxtcpsocketclient.h" +#endif + +using namespace jsonrpc; +using namespace std; + +TcpSocketClient::TcpSocketClient(const std::string& ipToConnect, const unsigned int &port) +{ +#ifdef __WIN32__ + this->realSocket = new WindowsTcpSocketClient(ipToConnect, port); +#elif __unix__ + this->realSocket = new LinuxTcpSocketClient(ipToConnect, port); +#else + this->realSocket = NULL; +#endif +} + +TcpSocketClient::~TcpSocketClient() +{ + if(this->realSocket != NULL) + { + delete this->realSocket; + this->realSocket = NULL; + } +} + +void TcpSocketClient::SendRPCMessage(const std::string& message, std::string& result) throw (JsonRpcException) +{ + if(this->realSocket != NULL) + { + this->realSocket->SendRPCMessage(message, result); + } +} diff --git a/src/jsonrpccpp/client/connectors/tcpsocketclient.h b/src/jsonrpccpp/client/connectors/tcpsocketclient.h new file mode 100644 index 0000000000000000000000000000000000000000..66e80054fe365b0b670106624fdb4685e66c560a --- /dev/null +++ b/src/jsonrpccpp/client/connectors/tcpsocketclient.h @@ -0,0 +1,56 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file unixdomainsocketclient.h + * @date 11.05.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#ifndef JSONRPC_CPP_TCPSOCKETCLIENT_H_ +#define JSONRPC_CPP_TCPSOCKETCLIENT_H_ + +#include "../iclientconnector.h" +#include <jsonrpccpp/common/exception.h> +#include <string> +#include "tcpsocketclientprivate.h" + +namespace jsonrpc +{ + /** + * This class provides an embedded TCP Socket Client that sends Requests over a tcp socket and read result from same socket. + * It uses the delimiter character to distinct a full RPC Message over the tcp flow. This character is parametered on + * compilation time in implementation files. The default value for this delimiter is 0x0A a.k.a. "new line". + * This class hides OS specific features in real implementation of this client. Currently it has implementation for + * both Linux and Windows. + */ + class TcpSocketClient : public IClientConnector + { + public: + /** + * @brief TcpSocketClient, constructor for the included TcpSocketClient + * + * Instanciates the real implementation of TcpSocketClientPrivate depending on running OS. + * + * @param ipToConnect The ipv4 address on which the client should try to connect + * @param port The port on which the client should try to connect + */ + TcpSocketClient(const std::string& ipToConnect, const unsigned int &port); + /** + * @brief ~TcpSocketClient, the destructor of TcpSocketClient + */ + virtual ~TcpSocketClient(); + /** + * @brief The IClientConnector::SendRPCMessage method overload. + * @param message The message to send + * @param result The result of the call returned by the servsr + * @throw JsonRpcException Thrown when an issue is encounter with socket manipulation (see message of exception for more information about what happened). + */ + virtual void SendRPCMessage(const std::string& message, std::string& result) throw (JsonRpcException); + + private: + TcpSocketClientPrivate *realSocket; /*!< A pointer to the real implementation of this class depending of running OS*/ + }; + +} /* namespace jsonrpc */ +#endif /* JSONRPC_CPP_TCPSOCKETCLIENT_H_ */ diff --git a/src/jsonrpccpp/client/connectors/tcpsocketclientprivate.h b/src/jsonrpccpp/client/connectors/tcpsocketclientprivate.h new file mode 100644 index 0000000000000000000000000000000000000000..767eecfe12d9f4f17f24118ad44d3e449edb702a --- /dev/null +++ b/src/jsonrpccpp/client/connectors/tcpsocketclientprivate.h @@ -0,0 +1,26 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file tcpsocketclientprivate.h + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#ifndef JSONRPC_CPP_TCPSOCKETCLIENTPRIVATE_H_ +#define JSONRPC_CPP_TCPSOCKETCLIENTPRIVATE_H_ + +#include "../iclientconnector.h" +#include <jsonrpccpp/common/exception.h> + +namespace jsonrpc +{ + /** + * This class is an interface to the real implementation of TcpSocketClient. Kind of a strategy design pattern. + */ + class TcpSocketClientPrivate : public IClientConnector + { + }; + +} /* namespace jsonrpc */ +#endif /* JSONRPC_CPP_TCPSOCKETCLIENTPRIVATE_H_ */ diff --git a/src/jsonrpccpp/client/connectors/unixdomainsocketclient.cpp b/src/jsonrpccpp/client/connectors/unixdomainsocketclient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..585e88d85750cc86d9bb80832c686b15d881fe22 --- /dev/null +++ b/src/jsonrpccpp/client/connectors/unixdomainsocketclient.cpp @@ -0,0 +1,84 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file unixdomainsocketclient.cpp + * @date 11.05.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#include "unixdomainsocketclient.h" +#include <string> +#include <string.h> +#include <cstdlib> +#include <cstdio> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <iostream> + +#define BUFFER_SIZE 64 +#define PATH_MAX 108 +#ifndef DELIMITER_CHAR +#define DELIMITER_CHAR char(0x0A) +#endif //DELIMITER_CHAR + +using namespace jsonrpc; +using namespace std; + + UnixDomainSocketClient::UnixDomainSocketClient(const std::string& path) +: path(path) +{ +} + +UnixDomainSocketClient::~UnixDomainSocketClient() +{ +} + +void UnixDomainSocketClient::SendRPCMessage(const std::string& message, std::string& result) throw (JsonRpcException) +{ + sockaddr_un address; + int socket_fd, nbytes; + char buffer[BUFFER_SIZE]; + socket_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (socket_fd < 0) + { + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, "Could not created unix domain socket"); + } + + memset(&address, 0, sizeof(sockaddr_un)); + + address.sun_family = AF_UNIX; + snprintf(address.sun_path, PATH_MAX, "%s", this->path.c_str()); + + if(connect(socket_fd, (struct sockaddr *) &address, sizeof(sockaddr_un)) != 0) + { + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, "Could not connect to: " + this->path); + } + + bool fullyWritten = false; + string toSend = message; + do + { + ssize_t byteWritten = write(socket_fd, toSend.c_str(), toSend.size()); + if(static_cast<size_t>(byteWritten) < toSend.size()) + { + int len = toSend.size() - byteWritten; + toSend = toSend.substr(byteWritten + sizeof(char), len); + } + else + fullyWritten = true; + } while(!fullyWritten); + + do + { + nbytes = read(socket_fd, buffer, BUFFER_SIZE); + string tmp; + tmp.append(buffer, nbytes); + result.append(buffer,nbytes); + + } while(result.find(DELIMITER_CHAR) == string::npos); + + close(socket_fd); +} diff --git a/src/jsonrpccpp/client/connectors/unixdomainsocketclient.h b/src/jsonrpccpp/client/connectors/unixdomainsocketclient.h new file mode 100644 index 0000000000000000000000000000000000000000..78bfbe282381e2a7491fc8115e9ec54cff70dc61 --- /dev/null +++ b/src/jsonrpccpp/client/connectors/unixdomainsocketclient.h @@ -0,0 +1,30 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file unixdomainsocketclient.h + * @date 11.05.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#ifndef JSONRPC_CPP_UNIXDOMAINSOCKETCLIENT_H_ +#define JSONRPC_CPP_UNIXDOMAINSOCKETCLIENT_H_ + +#include "../iclientconnector.h" +#include <jsonrpccpp/common/exception.h> + +namespace jsonrpc +{ + class UnixDomainSocketClient : public IClientConnector + { + public: + UnixDomainSocketClient(const std::string& path); + virtual ~UnixDomainSocketClient(); + virtual void SendRPCMessage(const std::string& message, std::string& result) throw (JsonRpcException); + + private: + std::string path; + }; + +} /* namespace jsonrpc */ +#endif /* JSONRPC_CPP_HTTPCLIENT_H_ */ diff --git a/src/jsonrpccpp/client/connectors/windowstcpsocketclient.cpp b/src/jsonrpccpp/client/connectors/windowstcpsocketclient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ebdf6f3984528512f0dee56c8dd1224b2b4c613 --- /dev/null +++ b/src/jsonrpccpp/client/connectors/windowstcpsocketclient.cpp @@ -0,0 +1,290 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file windowstcpsocketclient.cpp + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#include "windowstcpsocketclient.h" +#include <string.h> +#include <cstdlib> +#include <iostream> +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x501 +#include <ws2tcpip.h> + +#define BUFFER_SIZE 64 +#ifndef DELIMITER_CHAR +#define DELIMITER_CHAR char(0x0A) +#endif //DELIMITER_CHAR + +using namespace jsonrpc; +using namespace std; + +WindowsTcpSocketClient::WindowsTcpSocketClient(const std::string& hostToConnect, const unsigned int &port) : + hostToConnect(hostToConnect), + port(port) +{ +} + +WindowsTcpSocketClient::~WindowsTcpSocketClient() +{ +} + +void WindowsTcpSocketClient::SendRPCMessage(const std::string& message, std::string& result) throw (JsonRpcException) +{ + SOCKET socket_fd = this->Connect(); + char buffer[BUFFER_SIZE]; + bool fullyWritten = false; + string toSend = message; + do + { + int byteWritten = send(socket_fd, toSend.c_str(), toSend.size(), 0); + if(byteWritten == -1) + { + string message = "send() failed"; + int err = WSAGetLastError(); + switch(err) + { + case WSANOTINITIALISED: + case WSAENETDOWN: + case WSAEACCES: + case WSAEINTR: + case WSAEINPROGRESS: + case WSAEFAULT: + case WSAENETRESET: + case WSAENOBUFS: + case WSAENOTCONN: + case WSAENOTSOCK: + case WSAEOPNOTSUPP: + case WSAESHUTDOWN: + case WSAEWOULDBLOCK: + case WSAEMSGSIZE: + case WSAEHOSTUNREACH: + case WSAEINVAL: + case WSAECONNABORTED: + case WSAECONNRESET: + case WSAETIMEDOUT: + message = GetErrorMessage(err); + break; + } + closesocket(socket_fd); + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, message); + } + else if(static_cast<unsigned int>(byteWritten) < toSend.size()) + { + int len = toSend.size() - byteWritten; + toSend = toSend.substr(byteWritten + sizeof(char), len); + } + else + fullyWritten = true; + } while(!fullyWritten); + + do + { + int nbytes = recv(socket_fd, buffer, BUFFER_SIZE, 0); + if(nbytes == -1) + { + string message = "recv() failed"; + int err = WSAGetLastError(); + switch(err) + { + case WSANOTINITIALISED: + case WSAENETDOWN: + case WSAEFAULT: + case WSAENOTCONN: + case WSAEINTR: + case WSAEINPROGRESS: + case WSAENETRESET: + case WSAENOTSOCK: + case WSAEOPNOTSUPP: + case WSAESHUTDOWN: + case WSAEWOULDBLOCK: + case WSAEMSGSIZE: + case WSAEINVAL: + case WSAECONNABORTED: + case WSAETIMEDOUT: + case WSAECONNRESET: + message = GetErrorMessage(err); + break; + } + closesocket(socket_fd); + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, message); + } + else + { + string tmp; + tmp.append(buffer, nbytes); + result.append(buffer,nbytes); + } + + } while(result.find(DELIMITER_CHAR) == string::npos); + + closesocket(socket_fd); +} + +string WindowsTcpSocketClient::GetErrorMessage(const int& e) +{ + LPVOID lpMsgBuf; + lpMsgBuf = (LPVOID)"Unknown error"; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, e, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, 0, NULL); + string message(static_cast<char*>(lpMsgBuf)); + LocalFree(lpMsgBuf); + return message; +} + +SOCKET WindowsTcpSocketClient::Connect() throw (JsonRpcException) +{ + if(this->IsIpv4Address(this->hostToConnect)) + { + return this->Connect(this->hostToConnect, this->port); + } + else //We were given a hostname + { + struct addrinfo *result = NULL; + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + char port[6]; + port = itoa(this->port, port, 10); + DWORD retval = getaddrinfo(this->hostToConnect.c_str(), port, &hints, &result); + if(retval != 0) + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, "Could not resolve hostname."); + + bool foundValidIp = false; + SOCKET socket_fd = INVALID_SOCKET; + for(struct addrinfo *temp = result; (temp != NULL) && !foundValidIp; temp = temp->ai_next) + { + if(temp->ai_family == AF_INET) + { + try + { + SOCKADDR_IN* sock = reinterpret_cast<SOCKADDR_IN*>(temp->ai_addr); + socket_fd = this->Connect(inet_ntoa(sock->sin_addr), ntohs(sock->sin_port)); + foundValidIp = true; + } + catch(const JsonRpcException& e) + { + foundValidIp = false; + socket_fd = INVALID_SOCKET; + } + catch(void* p) + { + foundValidIp = false; + socket_fd = INVALID_SOCKET; + } + } + } + + if(!foundValidIp) + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, "Hostname resolved but connection was refused on the given port."); + + return socket_fd; + } +} + +SOCKET WindowsTcpSocketClient::Connect(const string& ip, const int& port) throw (JsonRpcException) +{ + SOCKADDR_IN address; + SOCKET socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (socket_fd == INVALID_SOCKET) + { + string message = "socket() failed"; + int err = WSAGetLastError(); + switch(err) + { + case WSANOTINITIALISED: + case WSAENETDOWN: + case WSAEAFNOSUPPORT: + case WSAEINPROGRESS: + case WSAEMFILE: + case WSAEINVAL: + case WSAEINVALIDPROVIDER: + case WSAEINVALIDPROCTABLE: + case WSAENOBUFS: + case WSAEPROTONOSUPPORT: + case WSAEPROTOTYPE: + case WSAEPROVIDERFAILEDINIT: + case WSAESOCKTNOSUPPORT: + message = GetErrorMessage(err); + break; + } + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, message); + } + memset(&address, 0, sizeof(SOCKADDR_IN)); + + address.sin_family = AF_INET; + address.sin_addr.s_addr = inet_addr(ip.c_str()); + address.sin_port = htons(port); + if(connect(socket_fd, reinterpret_cast<SOCKADDR*>(&address), sizeof(SOCKADDR_IN)) != 0) + { + string message = "connect() failed"; + int err = WSAGetLastError(); + switch(err) + { + case WSANOTINITIALISED: + case WSAENETDOWN: + case WSAEADDRINUSE: + case WSAEINTR: + case WSAEINPROGRESS: + case WSAEALREADY: + case WSAEADDRNOTAVAIL: + case WSAEAFNOSUPPORT: + case WSAECONNREFUSED: + case WSAEFAULT: + case WSAEINVAL: + case WSAEISCONN: + case WSAENETUNREACH: + case WSAEHOSTUNREACH: + case WSAENOBUFS: + case WSAENOTSOCK: + case WSAETIMEDOUT: + case WSAEWOULDBLOCK: + case WSAEACCES: + message = GetErrorMessage(err); + break; + } + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, message); + } + return socket_fd; +} + +bool WindowsTcpSocketClient::IsIpv4Address(const std::string& ip) +{ + return (inet_addr(ip.c_str()) != INADDR_NONE); +} + +//This is inspired from SFML to manage Winsock initialization. Thanks to them! ( http://www.sfml-dev.org/ ). +struct ClientSocketInitializer +{ + ClientSocketInitializer() + + { + WSADATA init; + if(WSAStartup(MAKEWORD(2, 2), &init) != 0) + { + throw JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, "An issue occured while WSAStartup executed."); + } + } + + ~ClientSocketInitializer() + + { + if(WSACleanup() != 0) + { + cerr << "An issue occured while WSAClean executed." << endl; + } + } +}; + +struct ClientSocketInitializer clientGlobalInitializer; diff --git a/src/jsonrpccpp/client/connectors/windowstcpsocketclient.h b/src/jsonrpccpp/client/connectors/windowstcpsocketclient.h new file mode 100644 index 0000000000000000000000000000000000000000..a1da2e96fc603fbc950e2e4f3739b33350f475b2 --- /dev/null +++ b/src/jsonrpccpp/client/connectors/windowstcpsocketclient.h @@ -0,0 +1,86 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file windowstcpsocketclient.h + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#ifndef JSONRPC_CPP_WINDOWSTCPSOCKETCLIENT_H_ +#define JSONRPC_CPP_WINDOWSTCPSOCKETCLIENT_H_ + +#include <jsonrpccpp/common/exception.h> +#include <string> +#include "tcpsocketclientprivate.h" +#include <winsock2.h> + +namespace jsonrpc +{ + /** + * This class is the windows implementation of TCPSocketClient. + * It uses the Winsock2 API to performs its job. + */ + class WindowsTcpSocketClient : public TcpSocketClientPrivate + { + public: + /** + * @brief WindowsTcpSocketClient, constructor of the Windows implementation of class TcpSocketClient + * @param hostToConnect The hostname or the ipv4 address on which the client should try to connect + * @param port The port on which the client should try to connect + */ + WindowsTcpSocketClient(const std::string& hostToConnect, const unsigned int &port); + /** + * @brief ~WindowsTcpSocketClient, the destructor of WindowsTcpSocketClient + */ + virtual ~WindowsTcpSocketClient(); + /** + * @brief The real implementation of TcpSocketClient::SendRPCMessage method. + * @param message The message to send + * @param result The result of the call returned by the server + * @throw JsonRpcException Thrown when an issue is encounter with socket manipulation (see message of exception for more information about what happened). + */ + virtual void SendRPCMessage(const std::string& message, std::string& result) throw (JsonRpcException); + + private: + std::string hostToConnect; /*!< The hostname or the ipv4 address on which the client should try to connect*/ + unsigned int port; /*!< The port on which the client should try to connect*/ + /** + * @brief A method to produce human readable messages from Winsock2 error values. + * @param e A Winsock2 error value + * @return The message matching the error value + */ + static std::string GetErrorMessage(const int &e); + /** + * @brief Connects to the host and port provided by constructor parameters. + * + * This method detects if the hostToConnect attribute is either an IPv4 or a hostname. + * On first case it tries to connect to the ip. + * On second case it tries to resolve hostname to an ip and tries to connect to it if resolve was successful. + * + * @returns A file descriptor to the successfully connected socket + * @throw JsonRpcException Thrown when an issue is encountered while trying to connect (see message of exception for more information about what happened). + */ + SOCKET Connect() throw (JsonRpcException); + /** + * @brief Connects to provided ip and port. + * + * This method tries to connect to the provided ip and port. + * + * @param ip The ipv4 address to connect to + * @param port The port to connect to + * @returns A file descriptor to the successfully connected socket + * @throw JsonRpcException Thrown when an issue is encountered while trying to connect (see message of exception for more information about what happened). + */ + SOCKET Connect(const std::string& ip, const int& port) throw (JsonRpcException); + /** + * @brief Check if provided ip is an ipv4 address. + * + * @param ip The ipv4 address to check + * @returns A boolean indicating if the provided ip is or is not an ipv4 address + */ + bool IsIpv4Address(const std::string& ip); + }; + +} /* namespace jsonrpc */ +#endif /* JSONRPC_CPP_WINDOWSTCPSOCKETCLIENT_H_ */ diff --git a/src/jsonrpccpp/client/rpcprotocolclient.cpp b/src/jsonrpccpp/client/rpcprotocolclient.cpp index 97c1224e3dff478b02f61311e4ae5ed8d8f39c1a..8f95c67fdb2f525cf560df30b7dc6d5ddfe491e0 100644 --- a/src/jsonrpccpp/client/rpcprotocolclient.cpp +++ b/src/jsonrpccpp/client/rpcprotocolclient.cpp @@ -21,13 +21,14 @@ const std::string RpcProtocolClient::KEY_RESULT = "result"; const std::string RpcProtocolClient::KEY_ERROR = "error"; const std::string RpcProtocolClient::KEY_ERROR_CODE = "code"; const std::string RpcProtocolClient::KEY_ERROR_MESSAGE = "message"; +const std::string RpcProtocolClient::KEY_ERROR_DATA = "data"; RpcProtocolClient::RpcProtocolClient(clientVersion_t version) : version(version) { } -void RpcProtocolClient::BuildRequest (const std::string &method, const Json::Value ¶meter, std::string &result, bool isNotification) +void RpcProtocolClient::BuildRequest(const std::string &method, const Json::Value ¶meter, std::string &result, bool isNotification) { Json::Value request; Json::FastWriter writer; @@ -35,7 +36,7 @@ void RpcProtocolClient::BuildRequest (const std::string &method, result = writer.write(request); } -void RpcProtocolClient::HandleResponse (const std::string &response, Json::Value& result) throw(JsonRpcException) +void RpcProtocolClient::HandleResponse(const std::string &response, Json::Value& result) throw(JsonRpcException) { Json::Reader reader; Json::Value value; @@ -49,7 +50,7 @@ void RpcProtocolClient::HandleResponse (const std::string &response } } -int RpcProtocolClient::HandleResponse(const Json::Value &value, Json::Value &result) throw(JsonRpcException) +Json::Value RpcProtocolClient::HandleResponse(const Json::Value &value, Json::Value &result) throw(JsonRpcException) { if(this->ValidateResponse(value)) { @@ -66,10 +67,10 @@ int RpcProtocolClient::HandleResponse(const Json::Value &value, Json::Value &res { throw JsonRpcException(Errors::ERROR_CLIENT_INVALID_RESPONSE, " " + value.toStyledString()); } - return value[KEY_ID].asInt(); + return value[KEY_ID]; } -void RpcProtocolClient::BuildRequest (int id, const std::string &method, const Json::Value ¶meter, Json::Value &result, bool isNotification) +void RpcProtocolClient::BuildRequest(int id, const std::string &method, const Json::Value ¶meter, Json::Value &result, bool isNotification) { if (this->version == JSONRPC_CLIENT_V2) result[KEY_PROTOCOL_VERSION] = "2.0"; @@ -85,8 +86,20 @@ void RpcProtocolClient::BuildRequest (int id, const std::string & void RpcProtocolClient::throwErrorException(const Json::Value &response) { if (response[KEY_ERROR].isMember(KEY_ERROR_MESSAGE) && response[KEY_ERROR][KEY_ERROR_MESSAGE].isString()) - throw JsonRpcException(response[KEY_ERROR][KEY_ERROR_CODE].asInt(), response[KEY_ERROR][KEY_ERROR_MESSAGE].asString()); - throw JsonRpcException(response[KEY_ERROR][KEY_ERROR_CODE].asInt()); + { + if (response[KEY_ERROR].isMember(KEY_ERROR_DATA)) + { + throw JsonRpcException(response[KEY_ERROR][KEY_ERROR_CODE].asInt(), response[KEY_ERROR][KEY_ERROR_MESSAGE].asString(), response[KEY_ERROR][KEY_ERROR_DATA]); + } + else + { + throw JsonRpcException(response[KEY_ERROR][KEY_ERROR_CODE].asInt(), response[KEY_ERROR][KEY_ERROR_MESSAGE].asString()); + } + } + else + { + throw JsonRpcException(response[KEY_ERROR][KEY_ERROR_CODE].asInt()); + } } bool RpcProtocolClient::ValidateResponse(const Json::Value& response) @@ -100,7 +113,7 @@ bool RpcProtocolClient::ValidateResponse(const Json::Value& response) return false; if(!response[KEY_RESULT].isNull() && !response[KEY_ERROR].isNull()) return false; - if (!response[KEY_ERROR].isNull() && !(response[KEY_ERROR].isObject() && response[KEY_ERROR].isMember(KEY_ERROR_CODE) && response[KEY_ERROR][KEY_ERROR_CODE].isInt())) + if (!response[KEY_ERROR].isNull() && !(response[KEY_ERROR].isObject() && response[KEY_ERROR].isMember(KEY_ERROR_CODE) && response[KEY_ERROR][KEY_ERROR_CODE].isIntegral())) return false; } else if (this->version == JSONRPC_CLIENT_V2) @@ -111,7 +124,7 @@ bool RpcProtocolClient::ValidateResponse(const Json::Value& response) return false; if (!response.isMember(KEY_RESULT) && !response.isMember(KEY_ERROR)) return false; - if (response.isMember(KEY_ERROR) && !(response[KEY_ERROR].isObject() && response[KEY_ERROR].isMember(KEY_ERROR_CODE) && response[KEY_ERROR][KEY_ERROR_CODE].isInt())) + if (response.isMember(KEY_ERROR) && !(response[KEY_ERROR].isObject() && response[KEY_ERROR].isMember(KEY_ERROR_CODE) && response[KEY_ERROR][KEY_ERROR_CODE].isIntegral())) return false; } diff --git a/src/jsonrpccpp/client/rpcprotocolclient.h b/src/jsonrpccpp/client/rpcprotocolclient.h index 91fd9eae8f412a3d644e8e7f10a019c7b6e6cf8b..aa5104bedb4aff0fd4d780e3f89500beb0ac24df 100644 --- a/src/jsonrpccpp/client/rpcprotocolclient.h +++ b/src/jsonrpccpp/client/rpcprotocolclient.h @@ -58,7 +58,7 @@ namespace jsonrpc { * @param result * @return response id */ - int HandleResponse(const Json::Value &response, Json::Value &result) throw (JsonRpcException); + Json::Value HandleResponse(const Json::Value &response, Json::Value &result) throw (JsonRpcException); static const std::string KEY_PROTOCOL_VERSION; static const std::string KEY_PROCEDURE_NAME; @@ -69,6 +69,7 @@ namespace jsonrpc { static const std::string KEY_ERROR; static const std::string KEY_ERROR_CODE; static const std::string KEY_ERROR_MESSAGE; + static const std::string KEY_ERROR_DATA; private: clientVersion_t version; diff --git a/src/jsonrpccpp/common/exception.cpp b/src/jsonrpccpp/common/exception.cpp index 4d7e70a3d524daf225aa28a57370ace0ada5fd37..73b735a4d0cbd726abc3f05e382557004dd57865 100644 --- a/src/jsonrpccpp/common/exception.cpp +++ b/src/jsonrpccpp/common/exception.cpp @@ -28,6 +28,17 @@ JsonRpcException::JsonRpcException(int code, const std::string& message) : this->setWhatMessage(); } +JsonRpcException::JsonRpcException(int code, const std::string &message, const Json::Value &data) : + code(code), + message(Errors::GetErrorMessage(code)), + data(data) +{ + if (this->message != "") + this->message = this->message + ": "; + this->message = this->message + message; + this->setWhatMessage(); +} + JsonRpcException::JsonRpcException(const std::string& message) : code(0), message(message) @@ -49,6 +60,11 @@ const std::string& JsonRpcException::GetMessage() const return message; } +const Json::Value& JsonRpcException::GetData() const +{ + return data; +} + const char* JsonRpcException::what() const throw () { return this->whatString.c_str(); @@ -60,6 +76,8 @@ void JsonRpcException::setWhatMessage() { std::stringstream ss; ss << "Exception " << this->code << " : " << this->message; + if (data != Json::nullValue) + ss << ", data: " << data.toStyledString(); this->whatString = ss.str(); } else diff --git a/src/jsonrpccpp/common/exception.h b/src/jsonrpccpp/common/exception.h index d3ad913187cbebbd6b8818357b165273bf159139..3d5a3b0944c0aca9fcf427d51a6459f9ccf310bd 100644 --- a/src/jsonrpccpp/common/exception.h +++ b/src/jsonrpccpp/common/exception.h @@ -22,16 +22,15 @@ namespace jsonrpc { public: JsonRpcException(int code); - JsonRpcException(int code, const std::string& message); - + JsonRpcException(int code, const std::string& message, const Json::Value &data); JsonRpcException(const std::string& message); virtual ~JsonRpcException() throw (); int GetCode() const; - const std::string& GetMessage() const; + const Json::Value& GetData() const; virtual const char* what() const throw (); @@ -39,7 +38,7 @@ namespace jsonrpc int code; std::string message; std::string whatString; - + Json::Value data; void setWhatMessage(); }; diff --git a/src/jsonrpccpp/common/procedure.cpp b/src/jsonrpccpp/common/procedure.cpp index 0d49ef17f6f625ef9ebaffba70dfe33c13bfb8fe..0d59c5176e0f0d40326d7e785d82a001fb0f5ea9 100644 --- a/src/jsonrpccpp/common/procedure.cpp +++ b/src/jsonrpccpp/common/procedure.cpp @@ -166,7 +166,7 @@ bool Procedure::ValidateSingleParameter (jsontype_t expectedType, const ok = false; break; case JSON_INTEGER: - if (!value.isInt()) + if (!value.isIntegral()) ok = false; break; case JSON_REAL: diff --git a/src/jsonrpccpp/server/abstractprotocolhandler.cpp b/src/jsonrpccpp/server/abstractprotocolhandler.cpp index 617403cd5b6aad628eedad6747624b970e74e012..23df5a7e72027ab3b511dee8535a0ff16d077820 100644 --- a/src/jsonrpccpp/server/abstractprotocolhandler.cpp +++ b/src/jsonrpccpp/server/abstractprotocolhandler.cpp @@ -63,7 +63,7 @@ void AbstractProtocolHandler::ProcessRequest(const Json::Value &request, Json::V else { handler.HandleNotificationCall(method, request[KEY_REQUEST_PARAMETERS]); - response = Json::Value::null; + response = Json::nullValue; } } diff --git a/src/jsonrpccpp/server/connectors/httpserver.cpp b/src/jsonrpccpp/server/connectors/httpserver.cpp index bb494c4507c327619e5390090c4bcb7a75234f2c..5ec15a26ecf2588f3b7c4ac9d727dc546c7fbafd 100644 --- a/src/jsonrpccpp/server/connectors/httpserver.cpp +++ b/src/jsonrpccpp/server/connectors/httpserver.cpp @@ -88,7 +88,7 @@ bool HttpServer::StopListening() bool HttpServer::SendResponse(const string& response, void* addInfo) { struct mhd_coninfo* client_connection = static_cast<struct mhd_coninfo*>(addInfo); - struct MHD_Response *result = MHD_create_response_from_data(response.size(),(void *) response.c_str(), 0, 1); + struct MHD_Response *result = MHD_create_response_from_buffer(response.size(),(void *) response.c_str(), MHD_RESPMEM_MUST_COPY); MHD_add_response_header(result, "Content-Type", "application/json"); MHD_add_response_header(result, "Access-Control-Allow-Origin", "*"); @@ -101,7 +101,7 @@ bool HttpServer::SendResponse(const string& response, void* addInfo) bool HttpServer::SendOptionsResponse(void* addInfo) { struct mhd_coninfo* client_connection = static_cast<struct mhd_coninfo*>(addInfo); - struct MHD_Response *result = MHD_create_response_from_data(0, NULL, 0, 1); + struct MHD_Response *result = MHD_create_response_from_buffer(0, NULL, MHD_RESPMEM_MUST_COPY); MHD_add_response_header(result, "Allow", "POST, OPTIONS"); MHD_add_response_header(result, "Access-Control-Allow-Origin", "*"); @@ -167,6 +167,7 @@ int HttpServer::callback(void *cls, MHD_Connection *connection, const char *url, client_connection->server->SendResponse("Not allowed HTTP Method", client_connection); } delete client_connection; + *con_cls = NULL; return MHD_YES; } diff --git a/src/jsonrpccpp/server/connectors/linuxtcpsocketserver.cpp b/src/jsonrpccpp/server/connectors/linuxtcpsocketserver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d25edc0497b6c59b16fb638451fb6eb643410a93 --- /dev/null +++ b/src/jsonrpccpp/server/connectors/linuxtcpsocketserver.cpp @@ -0,0 +1,263 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file linuxtcpsocketserver.cpp + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#include "linuxtcpsocketserver.h" + +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> + +#include <sstream> +#include <iostream> +#include <string> + +#include <jsonrpccpp/common/specificationparser.h> + +#include <errno.h> + +using namespace jsonrpc; +using namespace std; + +#define BUFFER_SIZE 64 +#ifndef DELIMITER_CHAR +#define DELIMITER_CHAR char(0x0A) +#endif //DELIMITER_CHAR + +LinuxTcpSocketServer::LinuxTcpSocketServer(const std::string& ipToBind, const unsigned int &port) : + AbstractServerConnector(), + running(false), + ipToBind(ipToBind), + port(port) +{ +} + +bool LinuxTcpSocketServer::StartListening() +{ + if(!this->running) + { + //Create and bind socket here. + //Then launch the listenning loop. + this->socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if(this->socket_fd < 0) + { + return false; + } + + fcntl(this->socket_fd, F_SETFL, FNDELAY); + int reuseaddr = 1; + setsockopt(this->socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)); + + /* start with a clean address structure */ + memset(&(this->address), 0, sizeof(struct sockaddr_in)); + + this->address.sin_family = AF_INET; + inet_aton(this->ipToBind.c_str(), &(this->address.sin_addr)); + this->address.sin_port = htons(this->port); + + if(bind(this->socket_fd, reinterpret_cast<struct sockaddr *>(&(this->address)), sizeof(struct sockaddr_in)) != 0) + { + return false; + } + + if(listen(this->socket_fd, 5) != 0) + { + return false; + } + //Launch listening loop there + this->running = true; + int ret = pthread_create(&(this->listenning_thread), NULL, LinuxTcpSocketServer::LaunchLoop, this); + if(ret != 0) + { + pthread_detach(this->listenning_thread); + shutdown(this->socket_fd, 2); + close(this->socket_fd); + } + this->running = static_cast<bool>(ret==0); + return this->running; + } + else + { + return false; + } +} + +bool LinuxTcpSocketServer::StopListening() +{ + if(this->running) + { + this->running = false; + pthread_join(this->listenning_thread, NULL); + shutdown(this->socket_fd, 2); + close(this->socket_fd); + return !(this->running); + } + else + { + return false; + } +} + +bool LinuxTcpSocketServer::SendResponse(const string& response, void* addInfo) +{ + bool result = false; + int connection_fd = reinterpret_cast<intptr_t>(addInfo); + + string temp = response; + if(temp.find(DELIMITER_CHAR) == string::npos) + { + temp.append(1, DELIMITER_CHAR); + } + if(DELIMITER_CHAR != '\n') + { + char eot = DELIMITER_CHAR; + string toSend = temp.substr(0, toSend.find_last_of('\n')); + toSend += eot; + result = this->WriteToSocket(connection_fd, toSend); + } + else + { + result = this->WriteToSocket(connection_fd, temp); + } + CleanClose(connection_fd); + return result; +} + +void* LinuxTcpSocketServer::LaunchLoop(void *p_data) +{ + pthread_detach(pthread_self()); + LinuxTcpSocketServer *instance = reinterpret_cast<LinuxTcpSocketServer*>(p_data);; + instance->ListenLoop(); + return NULL; +} + +void LinuxTcpSocketServer::ListenLoop() +{ + int connection_fd = 0; + struct sockaddr_in connection_address; + memset(&connection_address, 0, sizeof(struct sockaddr_in)); + socklen_t address_length = sizeof(connection_address); + while(this->running) + { + if((connection_fd = accept(this->socket_fd, reinterpret_cast<struct sockaddr *>(&(connection_address)), &address_length)) > 0) + { + pthread_t client_thread; + struct GenerateResponseParameters *params = new struct GenerateResponseParameters(); + params->instance = this; + params->connection_fd = connection_fd; + int ret = pthread_create(&client_thread, NULL, LinuxTcpSocketServer::GenerateResponse, params); + if(ret != 0) + { + pthread_detach(client_thread); + delete params; + params = NULL; + CleanClose(connection_fd); + } + } + else + { + usleep(2500); + } + } +} + +void* LinuxTcpSocketServer::GenerateResponse(void *p_data) +{ + pthread_detach(pthread_self()); + struct GenerateResponseParameters* params = reinterpret_cast<struct GenerateResponseParameters*>(p_data); + LinuxTcpSocketServer *instance = params->instance; + int connection_fd = params->connection_fd; + delete params; + params = NULL; + int nbytes; + char buffer[BUFFER_SIZE]; + string request; + do + { //The client sends its json formatted request and a delimiter request. + nbytes = recv(connection_fd, buffer, BUFFER_SIZE, 0); + if(nbytes == -1) + { + instance->CleanClose(connection_fd); + return NULL; + } + else + { + request.append(buffer,nbytes); + } + } while(request.find(DELIMITER_CHAR) == string::npos); + instance->OnRequest(request, reinterpret_cast<void*>(connection_fd)); + return NULL; +} + + +bool LinuxTcpSocketServer::WriteToSocket(const int& fd, const string& toWrite) +{ + bool fullyWritten = false; + bool errorOccured = false; + string toSend = toWrite; + do + { + ssize_t byteWritten = send(fd, toSend.c_str(), toSend.size(), 0); + if(byteWritten < 0) + { + errorOccured = true; + CleanClose(fd); + } + else if(static_cast<size_t>(byteWritten) < toSend.size()) + { + int len = toSend.size() - byteWritten; + toSend = toSend.substr(byteWritten + sizeof(char), len); + } + else + fullyWritten = true; + } while(!fullyWritten && !errorOccured); + + return fullyWritten && !errorOccured; +} + +bool LinuxTcpSocketServer::WaitClientClose(const int& fd, const int &timeout) +{ + bool ret = false; + int i = 0; + while((recv(fd, NULL, 0, 0) != 0) && i < timeout) + { + usleep(1); + ++i; + ret = true; + } + + return ret; +} + +int LinuxTcpSocketServer::CloseByReset(const int& fd) +{ + struct linger so_linger; + so_linger.l_onoff = 1; + so_linger.l_linger = 0; + + int ret = setsockopt(fd, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger)); + if(ret != 0) + return ret; + + return close(fd); +} + +int LinuxTcpSocketServer::CleanClose(const int& fd) +{ + if(WaitClientClose(fd)) + { + return close(fd); + } + else + { + return CloseByReset(fd); + } +} diff --git a/src/jsonrpccpp/server/connectors/linuxtcpsocketserver.h b/src/jsonrpccpp/server/connectors/linuxtcpsocketserver.h new file mode 100644 index 0000000000000000000000000000000000000000..d9461d0bc84ebede490b8aea7f7dc903b45355b2 --- /dev/null +++ b/src/jsonrpccpp/server/connectors/linuxtcpsocketserver.h @@ -0,0 +1,144 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file linuxtcpsocketserver.h + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#ifndef JSONRPC_CPP_LINUXTCPSOCKETSERVERCONNECTOR_H_ +#define JSONRPC_CPP_LINUXTCPSOCKETSERVERCONNECTOR_H_ + +#include <stdarg.h> +#include <stdint.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <pthread.h> + +#include "../abstractserverconnector.h" + +namespace jsonrpc +{ + /** + * This class is the Linux/UNIX implementation of TCPSocketServer. + * It uses the POSIX socket API and POSIX thread API to performs its job. + * Each client request is handled in a new thread. + */ + class LinuxTcpSocketServer: public AbstractServerConnector + { + public: + /** + * @brief LinuxTcpSocketServer, constructor of the Linux/UNIX implementation of class TcpSocketServer + * @param ipToBind The ipv4 address on which the server should bind and listen + * @param port The port on which the server should bind and listen + */ + LinuxTcpSocketServer(const std::string& ipToBind, const unsigned int &port); + /** + * @brief The real implementation TcpSocketServer::StartListening method. + * + * This method launches the listening loop that will handle client connections. + * The return value depends on the current listening states : + * - not listening and no error come up while bind and listen returns true + * - not listening but error happen on bind or listen returns false + * - is called while listening returns false + * + * @return A boolean that indicates the success or the failure of the operation. + */ + bool StartListening(); + /** + * @brief The real implementation TcpSocketServer::StopListening method. + * + * This method stops the listening loop that will handle client connections. + * The return value depends on the current listening states : + * - listening and successfuly stops the listen loop returns true + * - is called while not listening returns false + * + * @return A boolean that indicates the success or the failure of the operation. + */ + bool StopListening(); + + /** + * @brief The real implementation TcpSocketServer::SendResponse method. + * + * This method sends the result of the RPC Call over the tcp socket that the client has used to perform its request. + * @param response The response to send to the client + * @param addInfo Additionnal parameters (mainly client socket file descriptor) + * @return A boolean that indicates the success or the failure of the operation. + */ + bool SendResponse(const std::string& response, void* addInfo = NULL); + + private: + bool running; /*!< A boolean that is used to know the listening state*/ + std::string ipToBind; /*!< The ipv4 address on which the server should bind and listen*/ + unsigned int port; /*!< The port on which the server should bind and listen*/ + int socket_fd; /*!< The file descriptior of the listening socket*/ + struct sockaddr_in address; /*!< The listening socket*/ + + pthread_t listenning_thread; /*!< The identifier of the listen loop thread*/ + + /** + * @brief The static method that is used as listening thread entry point + * @param p_data The parameters for the thread entry point method + */ + static void* LaunchLoop(void *p_data); + /** + * @brief The method that launches the listenning loop + */ + void ListenLoop(); + struct GenerateResponseParameters + { + LinuxTcpSocketServer *instance; + int connection_fd; + }; /*!< The structure used to give parameters to the Response generating method*/ + /** + * @brief The static method that is used as client request handling entry point + * @param p_data The parameters for the thread entry point method + */ + static void* GenerateResponse(void *p_data); + /** + * @brief A method that write a message to socket + * + * Tries to send the full message. + * @param fd The file descriptor of the socket message should be sent + * @param toSend The message to send over socket + * @returns A boolean indicating the success or the failure of the operation + */ + bool WriteToSocket(const int& fd, const std::string& toSend); + /** + * @brief A method that wait for the client to close the tcp session + * + * This method wait for the client to close the tcp session in order to avoid the server to enter in TIME_WAIT status. + * Entering in TIME_WAIT status with too many clients may occur in a DOS attack + * since server will not be able to use a new socket when a new client connects. + * @param fd The file descriptor of the socket that should be closed by the client + * @param timeout The maximum time the server will wait for the client to close the tcp session in microseconds. + * @returns A boolean indicating the success or the failure of the operation + */ + bool WaitClientClose(const int& fd, const int &timeout = 100000); + /** + * @brief A method that close a socket by reseting it + * + * This method reset the tcp session in order to avoid enter in TIME_WAIT state. + * @param fd The file descriptor of the socket that should be reset + * @returns The return value of POSIX close() method + */ + int CloseByReset(const int& fd); + /** + * @brief A method that cleanly close a socket by avoid TIME_WAIT state + * + * This method uses WaitClientClose and ClodeByReset to clenly close a tcp session with a client + * (avoiding TIME_WAIT to avoid DOS attacks). + * @param fd The file descriptor of the socket that should be cleanly closed + * @returns The return value of POSIX close() method + */ + int CleanClose(const int& fd); + }; + +} /* namespace jsonrpc */ +#endif /* JSONRPC_CPP_LINUXTCPSOCKETSERVERCONNECTOR_H_ */ + diff --git a/src/jsonrpccpp/server/connectors/tcpsocketserver.cpp b/src/jsonrpccpp/server/connectors/tcpsocketserver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e6c23c79f78c8c2f7ecb649e4d00c5ba1b9f8b8f --- /dev/null +++ b/src/jsonrpccpp/server/connectors/tcpsocketserver.cpp @@ -0,0 +1,67 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file tcpsocketserver.cpp + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#include "tcpsocketserver.h" +#ifdef __WIN32__ +#include "windowstcpsocketserver.h" +#elif __unix__ +#include "linuxtcpsocketserver.h" +#endif +#include <string> + +using namespace jsonrpc; +using namespace std; + +TcpSocketServer::TcpSocketServer(const std::string& ipToBind, const unsigned int &port) : + AbstractServerConnector() +{ +#ifdef __WIN32__ + this->realSocket = new WindowsTcpSocketServer(ipToBind, port); +#elif __unix__ + this->realSocket = new LinuxTcpSocketServer(ipToBind, port); +#else + this->realSocket = NULL; +#endif +} + +TcpSocketServer::~TcpSocketServer() +{ + if(this->realSocket != NULL) + { + delete this->realSocket; + this->realSocket = NULL; + } +} + +bool TcpSocketServer::StartListening() +{ + if(this->realSocket != NULL) + { + this->realSocket->SetHandler(this->GetHandler()); + return this->realSocket->StartListening(); + } + else + return false; +} + +bool TcpSocketServer::StopListening() +{ + if(this->realSocket != NULL) + return this->realSocket->StopListening(); + else + return false; +} + +bool TcpSocketServer::SendResponse(const string& response, void* addInfo) +{ + if(this->realSocket != NULL) + return this->realSocket->SendResponse(response, addInfo); + else + return false; +} diff --git a/src/jsonrpccpp/server/connectors/tcpsocketserver.h b/src/jsonrpccpp/server/connectors/tcpsocketserver.h new file mode 100644 index 0000000000000000000000000000000000000000..2c9c69f7e92461f2bbd04ef3bb24447a167bab1f --- /dev/null +++ b/src/jsonrpccpp/server/connectors/tcpsocketserver.h @@ -0,0 +1,80 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file tcpsocketserver.h + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#ifndef JSONRPC_CPP_TCPSOCKETSERVERCONNECTOR_H_ +#define JSONRPC_CPP_TCPSOCKETSERVERCONNECTOR_H_ + +#include "../abstractserverconnector.h" + +namespace jsonrpc +{ + /** + * This class provides an embedded TCP Socket Server that handle incoming Requests and send result over same socket. + * It uses the delimiter character to distinct a full RPC Message over the tcp flow. This character is parametered on + * compilation time in implementation files. The default value for this delimiter is 0x0A a.k.a. "new line". + * This class hides OS specific features in real implementation of this server. Currently it has implementation for + * both Linux and Windows. + */ + class TcpSocketServer: public AbstractServerConnector + { + public: + /** + * @brief TcpSocketServer, constructor for the included TcpSocketServer + * + * Instanciates the real implementation of TcpSocketServerPrivate depending on running OS. + * + * @param ipToBind The ipv4 address on which the server should bind and listen + * @param port The port on which the server should bind and listen + */ + TcpSocketServer(const std::string& ipToBind, const unsigned int &port); + /** + * @brief ~TcpSocketServer, the destructor of TcpSocketServer + */ + ~TcpSocketServer(); + /** + * @brief The AbstractServerConnector::StartListening method overload. + * + * This method launches the listening loop that will handle client connections. + * The return value depends on the current listening states : + * - not listening and no error come up while bind and listen returns true + * - not listening but error happen on bind or listen returns false + * - is called while listening returns false + * + * @return A boolean that indicates the success or the failure of the operation. + */ + bool StartListening(); + /** + * @brief The AbstractServerConnector::StopListening method overload. + * + * This method stops the listening loop that will handle client connections. + * The return value depends on the current listening states : + * - listening and successfuly stops the listen loop returns true + * - is called while not listening returns false + * + * @return A boolean that indicates the success or the failure of the operation. + */ + bool StopListening(); + + /** + * @brief The AbstractServerConnector::SendResponse method overload. + * + * This method sends the result of the RPC Call over the tcp socket that the client has used to perform its request. + * @param response The response to send to the client + * @param addInfo Additionnal parameters (mainly client socket file descriptor) + * @return A boolean that indicates the success or the failure of the operation. + */ + bool SendResponse(const std::string& response, void* addInfo = NULL); + + private: + AbstractServerConnector *realSocket; /*!< A pointer to the real implementation of this class depending of running OS*/ + }; + +} /* namespace jsonrpc */ +#endif /* JSONRPC_CPP_TCPSOCKETSERVERCONNECTOR_H_ */ + diff --git a/src/jsonrpccpp/server/connectors/unixdomainsocketserver.cpp b/src/jsonrpccpp/server/connectors/unixdomainsocketserver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9fca57b6b212619eded01567d94f4f9071ab9fb5 --- /dev/null +++ b/src/jsonrpccpp/server/connectors/unixdomainsocketserver.cpp @@ -0,0 +1,207 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file unixdomainsocketserver.cpp + * @date 07.05.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#include "unixdomainsocketserver.h" +#include <cstdlib> +#include <sstream> +#include <iostream> +#include <sys/types.h> +#include <jsonrpccpp/common/specificationparser.h> +#include <cstdio> +#include <fcntl.h> +#include <unistd.h> +#include <string> + +using namespace jsonrpc; +using namespace std; + +#define BUFFER_SIZE 1024 +#define PATH_MAX 108 +#ifndef DELIMITER_CHAR +#define DELIMITER_CHAR char(0x0A) +#endif + +UnixDomainSocketServer::UnixDomainSocketServer(const string &socket_path) : + running(false), + socket_path(socket_path.substr(0, PATH_MAX)) +{ +} + +bool UnixDomainSocketServer::StartListening() +{ + if(!this->running) + { + //Create and bind socket here. + //Then launch the listenning loop. + if (access(this->socket_path.c_str(), F_OK) != -1) + return false; + + this->socket_fd = socket(AF_UNIX, SOCK_STREAM, 0); + + if(this->socket_fd < 0) + { + return false; + } + + unlink(this->socket_path.c_str()); + + fcntl(this->socket_fd, F_SETFL, FNDELAY); + + /* start with a clean address structure */ + memset(&(this->address), 0, sizeof(struct sockaddr_un)); + + this->address.sun_family = AF_UNIX; + snprintf(this->address.sun_path, PATH_MAX, "%s", this->socket_path.c_str()); + + if(bind(this->socket_fd, reinterpret_cast<struct sockaddr *>(&(this->address)), sizeof(struct sockaddr_un)) != 0) + { + return false; + } + + if(listen(this->socket_fd, 5) != 0) + { + return false; + } + + //Launch listening loop there + this->running = true; + int ret = pthread_create(&(this->listenning_thread), NULL, UnixDomainSocketServer::LaunchLoop, this); + if(ret != 0) + { + pthread_detach(this->listenning_thread); + } + this->running = static_cast<bool>(ret==0); + + return this->running; + } + else + { + return false; + } +} + +bool UnixDomainSocketServer::StopListening() +{ + if(this->running) + { + this->running = false; + pthread_join(this->listenning_thread, NULL); + close(this->socket_fd); + unlink(this->socket_path.c_str()); + return !(this->running); + } + else + { + return false; + } +} + +bool UnixDomainSocketServer::SendResponse(const string& response, void* addInfo) +{ + bool result = false; + int connection_fd = reinterpret_cast<intptr_t>(addInfo); + + string temp = response; + if(temp.find(DELIMITER_CHAR) == string::npos) + { + temp.append(1, DELIMITER_CHAR); + } + if(DELIMITER_CHAR != '\n') + { + char eot = DELIMITER_CHAR; + string toSend = temp.substr(0, toSend.find_last_of('\n')); + toSend += eot; + result = this->WriteToSocket(connection_fd, toSend); + } + else + { + result = this->WriteToSocket(connection_fd, temp); + } + close(connection_fd); + return result; +} + +void* UnixDomainSocketServer::LaunchLoop(void *p_data) +{ + pthread_detach(pthread_self()); + UnixDomainSocketServer *instance = reinterpret_cast<UnixDomainSocketServer*>(p_data);; + instance->ListenLoop(); + return NULL; +} + +void UnixDomainSocketServer::ListenLoop() +{ + int connection_fd; + socklen_t address_length = sizeof(this->address); + while(this->running) + { + if((connection_fd = accept(this->socket_fd, reinterpret_cast<struct sockaddr *>(&(this->address)), &address_length)) > 0) + { + pthread_t client_thread; + struct ClientConnection *params = new struct ClientConnection(); + params->instance = this; + params->connection_fd = connection_fd; + int ret = pthread_create(&client_thread, NULL, UnixDomainSocketServer::GenerateResponse, params); + if(ret != 0) + { + pthread_detach(client_thread); + delete params; + params = NULL; + } + } + else + { + usleep(25000); + } + } +} + +void* UnixDomainSocketServer::GenerateResponse(void *p_data) +{ + pthread_detach(pthread_self()); + struct ClientConnection* params = reinterpret_cast<struct ClientConnection*>(p_data); + UnixDomainSocketServer *instance = params->instance; + int connection_fd = params->connection_fd; + delete params; + params = NULL; + int nbytes; + char buffer[BUFFER_SIZE]; + string request; + do + { //The client sends its json formatted request and a delimiter request. + nbytes = read(connection_fd, buffer, BUFFER_SIZE); + request.append(buffer,nbytes); + } while(request.find(DELIMITER_CHAR) == string::npos); + + instance->OnRequest(request, reinterpret_cast<void*>(connection_fd)); + return NULL; +} + + +bool UnixDomainSocketServer::WriteToSocket(int fd, const string& toWrite) +{ + bool fullyWritten = false; + bool errorOccured = false; + string toSend = toWrite; + do + { + ssize_t byteWritten = write(fd, toSend.c_str(), toSend.size()); + if(byteWritten < 0) + errorOccured = true; + else if(byteWritten < static_cast<ssize_t>(toSend.size())) + { + int len = toSend.size() - byteWritten; + toSend = toSend.substr(byteWritten + sizeof(char), len); + } + else + fullyWritten = true; + } while(!fullyWritten && !errorOccured); + + return fullyWritten && !errorOccured; +} diff --git a/src/jsonrpccpp/server/connectors/unixdomainsocketserver.h b/src/jsonrpccpp/server/connectors/unixdomainsocketserver.h new file mode 100644 index 0000000000000000000000000000000000000000..2d2072b03b9cd4e4a8249537f5deca096cc6a813 --- /dev/null +++ b/src/jsonrpccpp/server/connectors/unixdomainsocketserver.h @@ -0,0 +1,64 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file unixdomainsocketserver.h + * @date 07.05.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#ifndef JSONRPC_CPP_UNIXDOMAINSOCKETSERVERCONNECTOR_H_ +#define JSONRPC_CPP_UNIXDOMAINSOCKETSERVERCONNECTOR_H_ + +#include <stdarg.h> +#include <stdint.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <pthread.h> + +#include "../abstractserverconnector.h" + +namespace jsonrpc +{ + /** + * This class provides an embedded Unix Domain Socket Server,to handle incoming Requests. + */ + class UnixDomainSocketServer: public AbstractServerConnector + { + public: + /** + * @brief UnixDomainSocketServer, constructor for the included UnixDomainSocketServer + * @param socket_path, a string containing the path to the unix socket + */ + UnixDomainSocketServer(const std::string& socket_path); + + virtual bool StartListening(); + virtual bool StopListening(); + + bool virtual SendResponse(const std::string& response, void* addInfo = NULL); + + private: + bool running; + std::string socket_path; + int socket_fd; + struct sockaddr_un address; + + pthread_t listenning_thread; + + static void* LaunchLoop(void *p_data); + void ListenLoop(); + struct ClientConnection + { + UnixDomainSocketServer *instance; + int connection_fd; + }; + static void* GenerateResponse(void *p_data); + bool WriteToSocket(int fd, const std::string& toSend); + }; + +} /* namespace jsonrpc */ +#endif /* JSONRPC_CPP_HTTPSERVERCONNECTOR_H_ */ + diff --git a/src/jsonrpccpp/server/connectors/windowstcpsocketserver.cpp b/src/jsonrpccpp/server/connectors/windowstcpsocketserver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95dcbc2d1c22094653f2c78436c8b9138ceeda23 --- /dev/null +++ b/src/jsonrpccpp/server/connectors/windowstcpsocketserver.cpp @@ -0,0 +1,292 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file windowstcpsocketserver.cpp + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#include "windowstcpsocketserver.h" + +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <windows.h> + +#include <sstream> +#include <iostream> +#include <string> + +#include <jsonrpccpp/common/specificationparser.h> + +using namespace jsonrpc; +using namespace std; + +#define BUFFER_SIZE 64 +#ifndef DELIMITER_CHAR +#define DELIMITER_CHAR char(0x0A) +#endif //DELIMITER_CHAR + +WindowsTcpSocketServer::WindowsTcpSocketServer(const std::string& ipToBind, const unsigned int &port) : + AbstractServerConnector(), + ipToBind(ipToBind), + port(port), + running(false) +{ +} + +WindowsTcpSocketServer::~WindowsTcpSocketServer() +{ +} + +bool WindowsTcpSocketServer::StartListening() +{ + if(!this->running) + { + //Create and bind socket here. + //Then launch the listenning loop. + this->socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if(this->socket_fd < 0) + { + return false; + } + unsigned long nonBlocking = 1; + ioctlsocket(this->socket_fd, FIONBIO, &nonBlocking); //Set non blocking + int reuseaddr = 1; + setsockopt(this->socket_fd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&reuseaddr), sizeof(reuseaddr)); + + /* start with a clean address structure */ + memset(&(this->address), 0, sizeof(SOCKADDR_IN)); + + this->address.sin_family = AF_INET; + this->address.sin_addr.s_addr = inet_addr(this->ipToBind.c_str()); + this->address.sin_port = htons(this->port); + + if(bind(this->socket_fd, reinterpret_cast<SOCKADDR*>(&(this->address)), sizeof(SOCKADDR_IN)) != 0) + { + return false; + } + + if(listen(this->socket_fd, 5) != 0) + { + return false; + } + //Launch listening loop there + this->running = true; + HANDLE ret = CreateThread(NULL, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(&(WindowsTcpSocketServer::LaunchLoop)), reinterpret_cast<LPVOID>(this), 0, &(this->listenning_thread)); + if(ret == NULL) + { + ExitProcess(3); + } + else + { + CloseHandle(ret); + } + this->running = static_cast<bool>(ret!=NULL); + return this->running; + } + else + { + return false; + } + +} + +bool WindowsTcpSocketServer::StopListening() +{ + if(this->running) + { + this->running = false; + WaitForSingleObject(OpenThread(THREAD_ALL_ACCESS, FALSE,this->listenning_thread), INFINITE); + closesocket(this->socket_fd); + return !(this->running); + } + else + { + return false; + } +} + +bool WindowsTcpSocketServer::SendResponse(const string& response, void* addInfo) +{ + bool result = false; + int connection_fd = reinterpret_cast<intptr_t>(addInfo); + + string temp = response; + if(temp.find(DELIMITER_CHAR) == string::npos) + { + temp.append(1, DELIMITER_CHAR); + } + if(DELIMITER_CHAR != '\n') + { + char eot = DELIMITER_CHAR; + string toSend = temp.substr(0, toSend.find_last_of('\n')); + toSend += eot; + result = this->WriteToSocket(connection_fd, toSend); + } + else + { + result = this->WriteToSocket(connection_fd, temp); + } + CleanClose(connection_fd); + return result; +} + +DWORD WINAPI WindowsTcpSocketServer::LaunchLoop(LPVOID lp_data) +{ + WindowsTcpSocketServer *instance = reinterpret_cast<WindowsTcpSocketServer*>(lp_data);; + instance->ListenLoop(); + CloseHandle(GetCurrentThread()); + return 0; //DO NOT USE ExitThread function here! ExitThread does not call destructors for allocated objects and therefore it would lead to a memory leak. +} + +void WindowsTcpSocketServer::ListenLoop() +{ + while(this->running) + { + SOCKET connection_fd = INVALID_SOCKET; + SOCKADDR_IN connection_address; + memset(&connection_address, 0, sizeof(SOCKADDR_IN)); + int address_length = sizeof(connection_address); + if((connection_fd = accept(this->socket_fd, reinterpret_cast<SOCKADDR*>(&connection_address), &address_length)) != INVALID_SOCKET) + { + unsigned long nonBlocking = 0; + ioctlsocket(connection_fd, FIONBIO, &nonBlocking); //Set blocking + DWORD client_thread; + struct GenerateResponseParameters *params = new struct GenerateResponseParameters(); + params->instance = this; + params->connection_fd = connection_fd; + HANDLE ret = CreateThread(NULL, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(&(WindowsTcpSocketServer::GenerateResponse)), reinterpret_cast<LPVOID>(params), 0, &client_thread); + if(ret == NULL) + { + delete params; + params = NULL; + CleanClose(connection_fd); + } + else + { + CloseHandle(ret); + } + } + else + { + Sleep(2.5); + } + } +} + +DWORD WINAPI WindowsTcpSocketServer::GenerateResponse(LPVOID lp_data) +{ + struct GenerateResponseParameters* params = reinterpret_cast<struct GenerateResponseParameters*>(lp_data); + WindowsTcpSocketServer *instance = params->instance; + int connection_fd = params->connection_fd; + delete params; + params = NULL; + int nbytes = 0; + char buffer[BUFFER_SIZE]; + memset(&buffer, 0, BUFFER_SIZE); + string request = ""; + do + { //The client sends its json formatted request and a delimiter request. + nbytes = recv(connection_fd, buffer, BUFFER_SIZE, 0); + if(nbytes == -1) + { + instance->CleanClose(connection_fd); + } + else + { + request.append(buffer,nbytes); + } + } while(request.find(DELIMITER_CHAR) == string::npos); + instance->OnRequest(request, reinterpret_cast<void*>(connection_fd)); + CloseHandle(GetCurrentThread()); + return 0; //DO NOT USE ExitThread function here! ExitThread does not call destructors for allocated objects and therefore it would lead to a memory leak. +} + +bool WindowsTcpSocketServer::WriteToSocket(const SOCKET& fd, const string& toWrite) +{ + bool fullyWritten = false; + bool errorOccured = false; + string toSend = toWrite; + do + { + ssize_t byteWritten = send(fd, toSend.c_str(), toSend.size(), 0); + if(byteWritten < 0) + { + errorOccured = true; + CleanClose(fd); + } + else if(byteWritten < toSend.size()) + { + int len = toSend.size() - byteWritten; + toSend = toSend.substr(byteWritten + sizeof(char), len); + } + else + fullyWritten = true; + } while(!fullyWritten && !errorOccured); + + return fullyWritten && !errorOccured; +} + +bool WindowsTcpSocketServer::WaitClientClose(const SOCKET& fd, const int &timeout) +{ + bool ret = false; + int i = 0; + while((recv(fd, NULL, 0, 0) != 0) && i < timeout) + { + Sleep(1); + ++i; + ret = true; + } + + return ret; +} + +int WindowsTcpSocketServer::CloseByReset(const SOCKET& fd) +{ + struct linger so_linger; + so_linger.l_onoff = 1; + so_linger.l_linger = 0; + + int ret = setsockopt(fd, SOL_SOCKET, SO_LINGER, reinterpret_cast<char*>(&so_linger), sizeof(so_linger)); + if(ret != 0) + return ret; + + return closesocket(fd); +} + +int WindowsTcpSocketServer::CleanClose(const SOCKET& fd) +{ + if(WaitClientClose(fd)) + { + return closesocket(fd); + } + else + { + return CloseByReset(fd); + } +} + +//This is inspired from SFML to manage Winsock initialization. Thanks to them! ( http://www.sfml-dev.org/ ). +struct ServerSocketInitializer +{ + ServerSocketInitializer() + { + WSADATA init; + if(WSAStartup(MAKEWORD(2, 2), &init) != 0) + { + JsonRpcException(Errors::ERROR_CLIENT_CONNECTOR, "An issue occured while WSAStartup executed."); + } + } + + ~ServerSocketInitializer() + { + if(WSACleanup() != 0) + { + cerr << "An issue occured while WSAClean executed." << endl; + } + } +}; + +struct ServerSocketInitializer serverGlobalInitializer; diff --git a/src/jsonrpccpp/server/connectors/windowstcpsocketserver.h b/src/jsonrpccpp/server/connectors/windowstcpsocketserver.h new file mode 100644 index 0000000000000000000000000000000000000000..88f0e80e963f8e5943869d4e379b5f2d00bfc96b --- /dev/null +++ b/src/jsonrpccpp/server/connectors/windowstcpsocketserver.h @@ -0,0 +1,142 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file windowstcpsocketserver.h + * @date 17.07.2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#ifndef JSONRPC_CPP_WINDOWSTCPSOCKETSERVERCONNECTOR_H_ +#define JSONRPC_CPP_WINDOWSTCPSOCKETSERVERCONNECTOR_H_ + +#include <stdarg.h> +#include <stdint.h> +#include <winsock2.h> + +#include "../abstractserverconnector.h" + +namespace jsonrpc +{ + /** + * This class is the Windows implementation of TCPSocketServer. + * It uses the Winsock2 socket API and Windows thread API to performs its job. + * Each client request is handled in a new thread. + */ + class WindowsTcpSocketServer: public AbstractServerConnector + { + public: + /** + * @brief WindowsTcpSocketServer, constructor of the Windows implementation of class TcpSocketServer + * @param ipToBind The ipv4 address on which the server should bind and listen + * @param port The port on which the server should bind and listen + */ + WindowsTcpSocketServer(const std::string& ipToBind, const unsigned int &port); + /** + * @brief ~WindowsTcpSocketServer, the destructor of WindowsTcpSocketServer + */ + ~WindowsTcpSocketServer(); + /** + * @brief The real implementation TcpSocketServer::StartListening method. + * + * This method launches the listening loop that will handle client connections. + * The return value depends on the current listening states : + * - not listening and no error come up while bind and listen returns true + * - not listening but error happen on bind or listen returns false + * - is called while listening returns false + * + * @return A boolean that indicates the success or the failure of the operation. + */ + bool StartListening(); + /** + * @brief The real implementation TcpSocketServer::StopListening method. + * + * This method stops the listening loop that will handle client connections. + * The return value depends on the current listening states : + * - listening and successfuly stops the listen loop returns true + * - is called while not listening returns false + * + * @return A boolean that indicates the success or the failure of the operation. + */ + bool StopListening(); + + /** + * @brief The real implementation TcpSocketServer::SendResponse method. + * + * This method sends the result of the RPC Call over the tcp socket that the client has used to perform its request. + * @param response The response to send to the client + * @param addInfo Additionnal parameters (mainly client socket file descriptor) + * @return A boolean that indicates the success or the failure of the operation. + */ + bool SendResponse(const std::string& response, void* addInfo = NULL); + + private: + bool running; /*!< A boolean that is used to know the listening state*/ + std::string ipToBind; /*!< The ipv4 address on which the server should bind and listen*/ + unsigned int port; /*!< The port on which the server should bind and listen*/ + SOCKET socket_fd; /*!< The file descriptior of the listening socket*/ + SOCKADDR_IN address; /*!< The listening socket*/ + + DWORD listenning_thread; /*!< The identifier of the listen loop thread*/ + + /** + * @brief The static method that is used as listening thread entry point + * @param lp_data The parameters for the thread entry point method + */ + static DWORD WINAPI LaunchLoop(LPVOID lp_data); + /** + * @brief The method that launches the listenning loop + */ + void ListenLoop(); + struct GenerateResponseParameters + { + WindowsTcpSocketServer *instance; + SOCKET connection_fd; + }; /*!< The structure used to give parameters to the Response generating method*/ + /** + * @brief The static method that is used as client request handling entry point + * @param lp_data The parameters for the thread entry point method + */ + static DWORD WINAPI GenerateResponse(LPVOID lp_data); + /** + * @brief A method that write a message to socket + * + * Tries to send the full message. + * @param fd The file descriptor of the socket message should be sent + * @param toSend The message to send over socket + * @returns A boolean indicating the success or the failure of the operation + */ + bool WriteToSocket(const SOCKET& fd, const std::string& toSend); + /** + * @brief A method that wait for the client to close the tcp session + * + * This method wait for the client to close the tcp session in order to avoid the server to enter in TIME_WAIT status. + * Entering in TIME_WAIT status with too many clients may occur in a DOS attack + * since server will not be able to use a new socket when a new client connects. + * @param fd The file descriptor of the socket that should be closed by the client + * @param timeout The maximum time the server will wait for the client to close the tcp session in milliseconds. + * @returns A boolean indicating the success or the failure of the operation + */ + bool WaitClientClose(const SOCKET& fd, const int &timeout = 100); + /** + * @brief A method that close a socket by reseting it + * + * This method reset the tcp session in order to avoid enter in TIME_WAIT state. + * @param fd The file descriptor of the socket that should be reset + * @returns The return value of POSIX close() method + */ + int CloseByReset(const SOCKET& fd); + /** + * @brief A method that cleanly close a socket by avoid TIME_WAIT state + * + * This method uses WaitClientClose and ClodeByReset to clenly close a tcp session with a client + * (avoiding TIME_WAIT to avoid DOS attacks). + * @param fd The file descriptor of the socket that should be cleanly closed + * @returns The return value of POSIX close() method + */ + int CleanClose(const SOCKET& fd); + }; + +} /* namespace jsonrpc */ +#endif /* JSONRPC_CPP_WINDOWSTCPSOCKETSERVERCONNECTOR_H_ */ + diff --git a/src/jsonrpccpp/server/rpcprotocolserverv1.cpp b/src/jsonrpccpp/server/rpcprotocolserverv1.cpp index 302f67472a996967e9c0c917a65f38a391a1cc32..b1818925ff1a0ee90b2eb06db6f2b1a2dc397a0e 100644 --- a/src/jsonrpccpp/server/rpcprotocolserverv1.cpp +++ b/src/jsonrpccpp/server/rpcprotocolserverv1.cpp @@ -31,7 +31,7 @@ void RpcProtocolServerV1::HandleJsonRequest(const Json::Value &req, Json::Value } catch (const JsonRpcException & exc) { - this->WrapError(req, exc.GetCode(), exc.GetMessage(), response); + this->WrapException(req, exc, response); } } else @@ -80,6 +80,12 @@ void RpcProtocolServerV1::WrapError(const Json::Value &request, int code, const } } +void RpcProtocolServerV1::WrapException(const Json::Value &request, const JsonRpcException &exception, Json::Value &result) +{ + this->WrapError(request, exception.GetCode(), exception.GetMessage(), result); + result["error"]["data"] = exception.GetData(); +} + procedure_t RpcProtocolServerV1::GetRequestType(const Json::Value &request) { if (request[KEY_REQUEST_ID] == Json::nullValue) diff --git a/src/jsonrpccpp/server/rpcprotocolserverv1.h b/src/jsonrpccpp/server/rpcprotocolserverv1.h index 07318d1a129e16f37cbfed5958ea62db749fe359..0e3d2e7859ff31588595f383431ad3ac2c388153 100644 --- a/src/jsonrpccpp/server/rpcprotocolserverv1.h +++ b/src/jsonrpccpp/server/rpcprotocolserverv1.h @@ -10,6 +10,7 @@ #ifndef JSONRPC_CPP_RPCPROTOCOLSERVERV1_H #define JSONRPC_CPP_RPCPROTOCOLSERVERV1_H +#include <jsonrpccpp/common/exception.h> #include "abstractprotocolhandler.h" namespace jsonrpc { @@ -23,6 +24,7 @@ namespace jsonrpc { void HandleJsonRequest(const Json::Value &request, Json::Value &response); void WrapResult(const Json::Value& request, Json::Value& response, Json::Value& retValue); void WrapError(const Json::Value& request, int code, const std::string &message, Json::Value& result); + void WrapException(const Json::Value& request, const JsonRpcException& exception, Json::Value& result); procedure_t GetRequestType(const Json::Value& request); }; diff --git a/src/jsonrpccpp/server/rpcprotocolserverv2.cpp b/src/jsonrpccpp/server/rpcprotocolserverv2.cpp index b4c191c1c30adbb2cb6c4b3014ddecfe328d50e0..2ab631c13dde35638ef5552770385dd71d6cb45f 100644 --- a/src/jsonrpccpp/server/rpcprotocolserverv2.cpp +++ b/src/jsonrpccpp/server/rpcprotocolserverv2.cpp @@ -46,7 +46,7 @@ void RpcProtocolServerV2::HandleSingleRequest (const Json::Value &req, Json::Val } catch (const JsonRpcException & exc) { - this->WrapError(req, exc.GetCode(), exc.GetMessage(), response); + this->WrapException(req, exc, response); } } else @@ -77,9 +77,9 @@ bool RpcProtocolServerV2::ValidateRequestFields(const Json::Value &request) return false; if (!(request.isMember(KEY_REQUEST_VERSION) && request[KEY_REQUEST_VERSION].isString() && request[KEY_REQUEST_VERSION].asString() == JSON_RPC_VERSION2)) return false; - if (request.isMember(KEY_REQUEST_ID) && !(request[KEY_REQUEST_ID].isInt() || request[KEY_REQUEST_ID].isString() || request[KEY_REQUEST_ID].isNull())) + if (request.isMember(KEY_REQUEST_ID) && !(request[KEY_REQUEST_ID].isIntegral() || request[KEY_REQUEST_ID].isString() || request[KEY_REQUEST_ID].isNull())) return false; - if (request.isMember(KEY_REQUEST_PARAMETERS) && !(request[KEY_REQUEST_PARAMETERS].isObject() || request[KEY_REQUEST_PARAMETERS].isArray() || request[KEY_REQUEST_ID].isNull())) + if (request.isMember(KEY_REQUEST_PARAMETERS) && !(request[KEY_REQUEST_PARAMETERS].isObject() || request[KEY_REQUEST_PARAMETERS].isArray() || request[KEY_REQUEST_PARAMETERS].isNull())) return false; return true; } @@ -97,7 +97,7 @@ void RpcProtocolServerV2::WrapError(const Json::Value &request, int code, const result["error"]["code"] = code; result["error"]["message"] = message; - if(request.isObject() && request.isMember("id") && (request["id"].isNull() || request["id"].isInt() || request["id"].isUInt() || request["id"].isString())) + if(request.isObject() && request.isMember("id") && (request["id"].isNull() || request["id"].isIntegral() || request["id"].isString())) { result["id"] = request["id"]; } @@ -107,6 +107,12 @@ void RpcProtocolServerV2::WrapError(const Json::Value &request, int code, const } } +void RpcProtocolServerV2::WrapException(const Json::Value &request, const JsonRpcException &exception, Json::Value &result) +{ + this->WrapError(request, exception.GetCode(), exception.GetMessage(), result); + result["error"]["data"] = exception.GetData(); +} + procedure_t RpcProtocolServerV2::GetRequestType(const Json::Value &request) { if (request.isMember(KEY_REQUEST_ID)) diff --git a/src/jsonrpccpp/server/rpcprotocolserverv2.h b/src/jsonrpccpp/server/rpcprotocolserverv2.h index 861cf8bd456e2e563fe291f4a8ce40e72dc67e5b..6cdaaaeaef86ad2312b0ed00289bae99fabfbaf6 100644 --- a/src/jsonrpccpp/server/rpcprotocolserverv2.h +++ b/src/jsonrpccpp/server/rpcprotocolserverv2.h @@ -14,7 +14,7 @@ #include <vector> #include <map> -#include <jsonrpccpp/common/specificationparser.h> +#include <jsonrpccpp/common/exception.h> #include "abstractprotocolhandler.h" @@ -32,6 +32,7 @@ namespace jsonrpc bool ValidateRequestFields(const Json::Value &val); void WrapResult(const Json::Value& request, Json::Value& response, Json::Value& retValue); void WrapError(const Json::Value& request, int code, const std::string &message, Json::Value& result); + void WrapException(const Json::Value& request, const JsonRpcException &exception, Json::Value& result); procedure_t GetRequestType(const Json::Value& request); private: diff --git a/src/stubgenerator/CMakeLists.txt b/src/stubgenerator/CMakeLists.txt index cef5e3310f6af18e6dc394708b2ba0e80454b136..f9dbe4c44a18e9b2c98bd51d1bdf354422038d6d 100644 --- a/src/stubgenerator/CMakeLists.txt +++ b/src/stubgenerator/CMakeLists.txt @@ -1,30 +1,72 @@ file(GLOB_RECURSE jsonrpcstub_source *.cpp) -file(GLOB_RECURSE libstubgen_source *.cpp) -list(REMOVE_ITEM libstubgen_source "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") +file(GLOB_RECURSE jsonrpcstub_header *.h) +list(REMOVE_ITEM jsonrpcstub_source "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") -find_package(Argtable REQUIRED) +include_directories(..) +include_directories(${JSONCPP_INCLUDE_DIRS}) +include_directories(${ARGTABLE_INCLUDE_DIRS}) -IF(COMPILE_TESTS) - add_library(stubgen STATIC ${libstubgen_source}) - target_link_libraries(stubgen jsonrpccommon ${ARGTABLE_LIBRARIES}) -ENDIF() +set(ALL_LIBS) -add_executable(jsonrpcstub ${jsonrpcstub_source}) -target_link_libraries(jsonrpcstub jsonrpccommon ${ARGTABLE_LIBRARIES}) + +if (BUILD_SHARED_LIBS) + add_library(libjsonrpcstub SHARED ${jsonrpcstub_source} ${jsonrpcstub_header} ${jsonrpc_helper_source_common}) + target_link_libraries(libjsonrpcstub jsonrpccommon ${JSONCPP_LIBRARIES} ${ARGTABLE_LIBRARIES}) + set_target_properties(libjsonrpcstub PROPERTIES OUTPUT_NAME jsonrpccpp-stub) + list(APPEND ALL_LIBS libjsonrpcstub) +endif() + +# setup static common library +if (BUILD_STATIC_LIBS) + add_library(libjsonrpcstubStatic STATIC ${jsonrpcstub_source} ${jsonrpcstub_header} ${jsonrpc_helper_source_common}) + target_link_libraries(libjsonrpcstubStatic jsonrpccommonStatic ${JSONCPP_LIBRARIES} ${ARGTABLE_LIBRARIES}) + set_target_properties(libjsonrpcstubStatic PROPERTIES OUTPUT_NAME jsonrpccpp-stub) + + if (NOT BUILD_SHARED_LIBS) + add_library(libjsonrpcstub ALIAS libjsonrpcstubStatic) + endif() + + list(APPEND ALL_LIBS libjsonrpcstubStatic) +endif() + +set(VERSION_STRING ${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}) +set_target_properties( + ${ALL_LIBS} + PROPERTIES VERSION "${VERSION_STRING}" SOVERSION "${SO_VERSION}" +) + + +add_executable(jsonrpcstub main.cpp) +target_link_libraries(jsonrpcstub jsonrpccommon libjsonrpcstub ) #Generate manpage -IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - configure_file("${CMAKE_SOURCE_DIR}/doc/manpage.in" "${CMAKE_BINARY_DIR}/manpage" @ONLY) - add_custom_command(OUTPUT jsonrpcstub.1.gz - COMMAND gzip -c "${CMAKE_BINARY_DIR}/manpage" > ${CMAKE_BINARY_DIR}/jsonrpcstub.1.gz - COMMENT "Generating man pages" - VERBATIM) - - add_custom_target(manpage ALL DEPENDS jsonrpcstub.1.gz) - install(FILES ${CMAKE_BINARY_DIR}/jsonrpcstub.1.gz DESTINATION share/man/man1/) - add_dependencies(jsonrpcstub manpage) -ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - -install(TARGETS jsonrpcstub LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin) +if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + configure_file("${CMAKE_SOURCE_DIR}/doc/manpage.in" "${CMAKE_BINARY_DIR}/manpage" @ONLY) + add_custom_command(OUTPUT jsonrpcstub.1.gz + COMMAND gzip -c "${CMAKE_BINARY_DIR}/manpage" > ${CMAKE_BINARY_DIR}/jsonrpcstub.1.gz + COMMENT "Generating man pages" + VERBATIM + ) + + add_custom_target(manpage ALL DEPENDS jsonrpcstub.1.gz) + install(FILES ${CMAKE_BINARY_DIR}/jsonrpcstub.1.gz DESTINATION share/man/man1/) + add_dependencies(jsonrpcstub manpage) + +endif() + +CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/cmake/libjsonrpccpp-stub.pc.cmake ${CMAKE_BINARY_DIR}/libjsonrpccpp-stub.pc) + +INSTALL(FILES + "${CMAKE_BINARY_DIR}/libjsonrpccpp-stub.pc" + DESTINATION "lib/${CMAKE_LIBRARY_PATH}/pkgconfig") + +install(DIRECTORY ${CMAKE_SOURCE_DIR}/src/stubgenerator/ + DESTINATION include/jsonrpccpp/stubgen + FILES_MATCHING PATTERN "*.h") + +install(TARGETS ${ALL_LIBS} jsonrpcstub + LIBRARY DESTINATION lib${LIB_SUFFIX}/${CMAKE_LIBRARY_PATH} + ARCHIVE DESTINATION lib${LIB_SUFFIX}/${CMAKE_LIBRARY_PATH} + RUNTIME DESTINATION bin +) + diff --git a/src/stubgenerator/client/cppclientstubgenerator.h b/src/stubgenerator/client/cppclientstubgenerator.h index 2dc60353d255f35aab99933818ff80937c5d4d23..7900eb0fce95d3677ad2233ef4c9ec28d47b219c 100755 --- a/src/stubgenerator/client/cppclientstubgenerator.h +++ b/src/stubgenerator/client/cppclientstubgenerator.h @@ -25,7 +25,6 @@ namespace jsonrpc virtual void generateStub(); - private: void generateMethod(Procedure& proc); void generateAssignments(Procedure& proc); void generateProcCall(Procedure &proc); diff --git a/src/stubgenerator/client/jsclientstubgenerator.cpp b/src/stubgenerator/client/jsclientstubgenerator.cpp index 7807b9251562dc7dacb3ceb72a49ca118f899e30..9304438255abd55cde05268d4f394eb12fd7f108 100644 --- a/src/stubgenerator/client/jsclientstubgenerator.cpp +++ b/src/stubgenerator/client/jsclientstubgenerator.cpp @@ -23,7 +23,9 @@ using namespace std; request.id = id++;\n\ request.jsonrpc = \"2.0\";\n\ request.method = method;\n\ - request.params = params\n\ + if (params !== null) {\n\ + request.params = params;\n\ + }\n\ JSON.stringify(request);\n\ \n\ $.ajax({\n\ diff --git a/src/stubgenerator/helper/cpphelper.cpp b/src/stubgenerator/helper/cpphelper.cpp index 916ad5eb8ee20233193faefb922deb6b1b3cc02b..020062edabdb40f2d3d7e5ec936a2e1b00fb5356 100755 --- a/src/stubgenerator/helper/cpphelper.cpp +++ b/src/stubgenerator/helper/cpphelper.cpp @@ -219,7 +219,7 @@ string CPPHelper::isCppConversion (jsontype_t type) result = ".isBool()"; break; case JSON_INTEGER: - result = ".isInt()"; + result = ".isIntegral()"; break; case JSON_REAL: result = ".isDouble()"; diff --git a/src/stubgenerator/main.cpp b/src/stubgenerator/main.cpp index e40afc8d24ab8f3ff37793fd091e20a51ff436b7..4cd94f5c5279636bdf79c825daeec76a6ca02e40 100644 --- a/src/stubgenerator/main.cpp +++ b/src/stubgenerator/main.cpp @@ -20,7 +20,7 @@ int main(int argc, char** argv) vector<StubGenerator*> stubgens; vector<Procedure> procedures; - bool result = StubGeneratorFactory::createStubGenerators(argc, argv, procedures, stubgens); + bool result = StubGeneratorFactory::createStubGenerators(argc, argv, procedures, stubgens, stdout, stderr); for (unsigned int i=0; i < stubgens.size(); ++i) { diff --git a/src/stubgenerator/server/cppserverstubgenerator.cpp b/src/stubgenerator/server/cppserverstubgenerator.cpp index 8b699aeab8fd9ab73e18bd41b40cc844b971cab1..52e928530d64bcf9cc3aaffedfc3af28259a75d3 100755 --- a/src/stubgenerator/server/cppserverstubgenerator.cpp +++ b/src/stubgenerator/server/cppserverstubgenerator.cpp @@ -14,8 +14,8 @@ #include <sstream> #include <algorithm> -#define TEMPLATE_CPPSERVER_METHODBINDING "this->bindAndAddMethod(jsonrpc::Procedure(\"<procedurename>\", <paramtype>, <returntype>, <parameterlist> NULL), &<stubname>::<procedurename>I);" -#define TEMPLATE_CPPSERVER_NOTIFICATIONBINDING "this->bindAndAddNotification(jsonrpc::Procedure(\"<procedurename>\", <paramtype>, <parameterlist> NULL), &<stubname>::<procedurename>I);" +#define TEMPLATE_CPPSERVER_METHODBINDING "this->bindAndAddMethod(jsonrpc::Procedure(\"<rawprocedurename>\", <paramtype>, <returntype>, <parameterlist> NULL), &<stubname>::<procedurename>I);" +#define TEMPLATE_CPPSERVER_NOTIFICATIONBINDING "this->bindAndAddNotification(jsonrpc::Procedure(\"<rawprocedurename>\", <paramtype>, <parameterlist> NULL), &<stubname>::<procedurename>I);" #define TEMPLATE_CPPSERVER_SIGCLASS "class <stubname> : public jsonrpc::AbstractServer<<stubname>>" #define TEMPLATE_CPPSERVER_SIGCONSTRUCTOR "<stubname>(jsonrpc::AbstractServerConnector &conn, jsonrpc::serverVersion_t type = jsonrpc::JSONRPC_SERVER_V2) : jsonrpc::AbstractServer<<stubname>>(conn, type)" @@ -91,6 +91,7 @@ void CPPServerStubGenerator::generateBindings() { tmp = TEMPLATE_CPPSERVER_NOTIFICATIONBINDING; } + replaceAll2(tmp, "<rawprocedurename>", proc.GetProcedureName()); replaceAll2(tmp, "<procedurename>", CPPHelper::normalizeString(proc.GetProcedureName())); replaceAll2(tmp, "<returntype>", CPPHelper::toString(proc.GetReturnType())); replaceAll2(tmp, "<parameterlist>", generateBindingParameterlist(proc)); @@ -116,9 +117,9 @@ void CPPServerStubGenerator::generateProcedureDefinitions() { Procedure &proc = *it; if(proc.GetProcedureType() == RPC_METHOD) - this->writeLine(replaceAll(TEMPLATE_CPPSERVER_SIGMETHOD, "<procedurename>", proc.GetProcedureName())); + this->writeLine(replaceAll(TEMPLATE_CPPSERVER_SIGMETHOD, "<procedurename>", CPPHelper::normalizeString(proc.GetProcedureName()))); else - this->writeLine(replaceAll(TEMPLATE_CPPSERVER_SIGNOTIFICATION, "<procedurename>", proc.GetProcedureName())); + this->writeLine(replaceAll(TEMPLATE_CPPSERVER_SIGNOTIFICATION, "<procedurename>", CPPHelper::normalizeString(proc.GetProcedureName()))); this->writeLine("{"); this->increaseIndentation(); @@ -150,7 +151,7 @@ void CPPServerStubGenerator::generateAbstractDefinitions() returntype = CPPHelper::toCppReturntype(proc.GetReturnType()); } replaceAll2(tmp, "<returntype>", returntype); - replaceAll2(tmp, "<procedurename>", proc.GetProcedureName()); + replaceAll2(tmp, "<procedurename>", CPPHelper::normalizeString(proc.GetProcedureName())); replaceAll2(tmp, "<parameterlist>", CPPHelper::generateParameterDeclarationList(proc)); this->writeLine(tmp); } diff --git a/src/stubgenerator/server/cppserverstubgenerator.h b/src/stubgenerator/server/cppserverstubgenerator.h index bac2d52e2b82929c56f816e187405af7642a3826..1351155c4feee8c8c0e69ef309716c520a17b593 100755 --- a/src/stubgenerator/server/cppserverstubgenerator.h +++ b/src/stubgenerator/server/cppserverstubgenerator.h @@ -23,7 +23,6 @@ namespace jsonrpc virtual void generateStub(); - private: void generateBindings(); void generateProcedureDefinitions(); void generateAbstractDefinitions(); diff --git a/src/stubgenerator/stubgeneratorfactory.cpp b/src/stubgenerator/stubgeneratorfactory.cpp index afda86de2b0b88b4e8e8db231ebe99ece052fe27..7d6e0f16e6d239547f86dd2ba43b165a2e94c889 100644 --- a/src/stubgenerator/stubgeneratorfactory.cpp +++ b/src/stubgenerator/stubgeneratorfactory.cpp @@ -9,6 +9,7 @@ #include "stubgeneratorfactory.h" #include <jsonrpccpp/common/specificationparser.h> +#include <jsonrpccpp/version.h> #include <iostream> #include <argtable2.h> #include "helper/cpphelper.h" @@ -19,10 +20,11 @@ using namespace jsonrpc; using namespace std; -bool StubGeneratorFactory::createStubGenerators(int argc, char **argv, vector<Procedure> &procedures, vector<StubGenerator*> &stubgenerators) +bool StubGeneratorFactory::createStubGenerators(int argc, char **argv, vector<Procedure> &procedures, vector<StubGenerator*> &stubgenerators, FILE *stdout, FILE *stderr) { struct arg_file *inputfile = arg_file0(NULL, NULL, "<specfile>", "path of input specification file"); struct arg_lit *help = arg_lit0("h","help", "print this help and exit"); + struct arg_lit *version = arg_lit0(NULL,"version", "print version and exit"); struct arg_lit *verbose = arg_lit0("v","verbose", "print more information about what is happening"); struct arg_str *cppserver = arg_str0(NULL, "cpp-server", "<namespace::classname>", "name of the C++ server stub class"); struct arg_str *cppserverfile = arg_str0(NULL, "cpp-server-file", "<filename.h>", "name of the C++ server stub file"); @@ -33,7 +35,7 @@ bool StubGeneratorFactory::createStubGenerators(int argc, char **argv, vector<Pr struct arg_end *end = arg_end(20); - void* argtable[] = {inputfile, help, verbose, cppserver, cppserverfile, cppclient, cppclientfile, jsclient, jsclientfile,end}; + void* argtable[] = {inputfile, help, version, verbose, cppserver, cppserverfile, cppclient, cppclientfile, jsclient, jsclientfile,end}; if (arg_parse(argc,argv,argtable) > 0) { @@ -44,15 +46,22 @@ bool StubGeneratorFactory::createStubGenerators(int argc, char **argv, vector<Pr if (help->count > 0) { - cout << "Usage: " << argv[0] << " "; cout.flush(); + fprintf(stdout, "Usage: %s ", argv[0]); arg_print_syntax(stdout,argtable,"\n"); cout << endl; arg_print_glossary_gnu(stdout, argtable); arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0])); return true; } + if (version->count > 0) + { + fprintf(stdout, "jsonrpcstub version %d.%d.%d\n", JSONRPC_CPP_MAJOR_VERSION, JSONRPC_CPP_MINOR_VERSION, JSONRPC_CPP_PATCH_VERSION); + arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0])); + return true; + } + if (inputfile->count == 0) { - cerr << "Invalid arguments: specfile must be provided." << endl; + fprintf(stderr, "Invalid arguments: specfile must be provided.\n"); arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0])); return false; } @@ -61,15 +70,19 @@ bool StubGeneratorFactory::createStubGenerators(int argc, char **argv, vector<Pr procedures = SpecificationParser::GetProceduresFromFile(inputfile->filename[0]); if (verbose->count > 0) { - cout << "Found " << procedures.size() << " procedures in " << inputfile->filename[0] << endl; + fprintf(stdout, "Found %zu procedures in %s\n", procedures.size(), inputfile->filename[0]); for (unsigned int i = 0; i < procedures.size(); ++i) { if (procedures.at(i).GetProcedureType() == RPC_METHOD) - cout << "\t[Method] "; + { + fprintf(stdout, "\t[Method] "); + } else - cout << "\t[Notification] "; - cout << procedures.at(i).GetProcedureName() << endl; + { + fprintf(stdout, "\t[Notification] "); + } + fprintf(stdout, "%s\n", procedures.at(i).GetProcedureName().c_str()); } - cout << endl; + fprintf(stdout, "\n"); } if (cppserver->count > 0) @@ -80,7 +93,7 @@ bool StubGeneratorFactory::createStubGenerators(int argc, char **argv, vector<Pr else filename = CPPHelper::class2Filename(cppserver->sval[0]); if (verbose->count > 0) - cout << "Generating C++ Serverstub to: " << filename << endl; + fprintf(stdout, "Generating C++ Serverstub to: %s\n", filename.c_str()); stubgenerators.push_back(new CPPServerStubGenerator(cppserver->sval[0], procedures, filename)); } @@ -92,7 +105,7 @@ bool StubGeneratorFactory::createStubGenerators(int argc, char **argv, vector<Pr else filename = CPPHelper::class2Filename(cppclient->sval[0]); if (verbose->count > 0) - cout << "Generating C++ Clientstub to: " << filename << endl; + fprintf(stdout, "Generating C++ Clientstub to: %s\n", filename.c_str()); stubgenerators.push_back(new CPPClientStubGenerator(cppclient->sval[0], procedures, filename)); } @@ -105,13 +118,13 @@ bool StubGeneratorFactory::createStubGenerators(int argc, char **argv, vector<Pr filename = JSClientStubGenerator::class2Filename(jsclient->sval[0]); if (verbose->count > 0) - cout << "Generating JavaScript Clientstub to: " << filename << endl; + fprintf(stdout, "Generating JavaScript Clientstub to: %s\n", filename.c_str()); stubgenerators.push_back(new JSClientStubGenerator(jsclient->sval[0], procedures, filename)); } } catch (const JsonRpcException &ex) { - cerr << ex.what() << endl; + fprintf(stderr, "%s\n", ex.what()); arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0])); return false; } diff --git a/src/stubgenerator/stubgeneratorfactory.h b/src/stubgenerator/stubgeneratorfactory.h index 94b2b701532e18e65a1aa9093e2cde23c7395d55..90d8eac01b9bc418b56a9276f3dab9c7f19bc652 100644 --- a/src/stubgenerator/stubgeneratorfactory.h +++ b/src/stubgenerator/stubgeneratorfactory.h @@ -18,7 +18,7 @@ namespace jsonrpc { class StubGeneratorFactory { public: - static bool createStubGenerators(int argc, char** argv, std::vector<Procedure> &procedures, std::vector<StubGenerator*> &stubgenerators); + static bool createStubGenerators(int argc, char** argv, std::vector<Procedure> &procedures, std::vector<StubGenerator*> &stubgenerators, FILE* stdout, FILE* stderr); static void deleteStubGenerators(std::vector<StubGenerator*> &stubgenerators); }; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 6459e3d28eab359026838a38ba5771c43379eff7..9438134f4c19fc4d2781285d13a3ad395477ff5a 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,57 +1,93 @@ -message(STATUS "Found Bosst Unit Suite -> Enabling test cases") set(CTEST_OUTPUT_ON_FAILURE TRUE) - file(GLOB_RECURSE test_source *.cpp) -file(GLOB test_specs *.json) -file(COPY ${CMAKE_SOURCE_DIR}/src/examples/server.key ${CMAKE_SOURCE_DIR}/src/examples/server.pem DESTINATION ${CMAKE_BINARY_DIR}) -file(COPY ${CMAKE_SOURCE_DIR}/src/examples/server.key ${CMAKE_SOURCE_DIR}/src/examples/server.pem DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) -file(COPY ${test_specs} DESTINATION ${CMAKE_BINARY_DIR}) -file(COPY ${test_specs} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +include_directories(..) +include_directories(${CMAKE_BINARY_DIR}) +include_directories(${JSONCPP_INCLUDE_DIRS}) -set(testlibs ${Boost_LIBRARIES} jsonrpccommon jsonrpcclient jsonrpcserver) -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src) +add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/gen/abstractstubserver.h + COMMAND jsonrpcstub ARGS ${CMAKE_CURRENT_SOURCE_DIR}/spec.json --cpp-server=AbstractStubServer --cpp-server-file=${CMAKE_BINARY_DIR}/gen/abstractstubserver.h + MAIN_DEPENDENCY spec.json + DEPENDS jsonrpcstub + COMMENT "Generating Server Stubfiles" + VERBATIM +) -#add_definitions(-DBOOST_TEST_DYN_LINK) +add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/gen/stubclient.h + COMMAND jsonrpcstub ARGS ${CMAKE_CURRENT_SOURCE_DIR}/spec.json --cpp-client=StubClient --cpp-client-file=${CMAKE_BINARY_DIR}/gen/stubclient.h + MAIN_DEPENDENCY spec.json + DEPENDS jsonrpcstub + COMMENT "Generating Client Stubfile" + VERBATIM +) -IF(HTTP_CLIENT AND HTTP_SERVER) - add_definitions(-DHTTP_TESTING) -ENDIF() -IF(COMPILE_STUBGEN) - add_definitions(-DSTUBGEN_TESTING) -ENDIF() +if(HTTP_CLIENT AND HTTP_SERVER) + add_definitions(-DHTTP_TESTING) + file(COPY ${CMAKE_SOURCE_DIR}/src/examples/server.key ${CMAKE_SOURCE_DIR}/src/examples/server.pem DESTINATION ${CMAKE_BINARY_DIR}) + file(COPY ${CMAKE_SOURCE_DIR}/src/examples/server.key ${CMAKE_SOURCE_DIR}/src/examples/server.pem DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +else() + list(REMOVE_ITEM test_source "${CMAKE_CURRENT_SOURCE_DIR}/testhttpserver.cpp") +endif() -IF(HTTP_CLIENT AND HTTP_SERVER AND COMPILE_STUBGEN) - add_definitions(-DINTEGRATION_TESTING) - INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}) -ENDIF() +if(UNIX_DOMAIN_SOCKET_SERVER AND UNIX_DOMAIN_SOCKET_CLIENT) + add_definitions(-DUNIXDOMAINSOCKET_TESTING) +endif() -IF(WIN32) - INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR}) - LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) -ENDIF() +if(TCP_SOCKET_SERVER AND TCP_SOCKET_CLIENT) + add_definitions(-DTCPSOCKET_TESTING) +endif() +if(COMPILE_STUBGEN) + add_definitions(-DSTUBGEN_TESTING) + file(GLOB test_specs *.json) + file(COPY ${test_specs} DESTINATION ${CMAKE_BINARY_DIR}) + file(COPY ${test_specs} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + list(APPEND test_source "${CMAKE_BINARY_DIR}/gen/abstractstubserver.h") + list(APPEND test_source "${CMAKE_BINARY_DIR}/gen/stubclient.h") +endif() add_executable(unit_testsuite ${test_source}) -target_link_libraries(unit_testsuite ${testlibs}) -IF(COMPILE_STUBGEN) - target_link_libraries(unit_testsuite stubgen) -ENDIF() - -ADD_TEST(client ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite --run_test=client) -ADD_TEST(server ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite --run_test=server) -ADD_TEST(NAME common WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite --run_test=common) -IF(HTTP_CLIENT AND HTTP_SERVER) - ADD_TEST(NAME connector_http WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite --run_test=connector_http) -ENDIF() -IF(COMPILE_STUBGEN) - ADD_TEST(NAME stubgen WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite --run_test=stubgenerator) -ENDIF() -IF(HTTP_CLIENT AND HTTP_SERVER AND COMPILE_STUBGEN) - ADD_TEST(NAME integration WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite --run_test=integration) - -ENDIF() - -ADD_TEST(NAME all WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite) +target_link_libraries(unit_testsuite jsonrpccommon) +target_link_libraries(unit_testsuite jsonrpcserver) +target_link_libraries(unit_testsuite jsonrpcclient) + +if (NOT CATCH_FOUND) + # let's wait for catch files to be downloaded + add_dependencies(unit_testsuite catch) +endif() + +if(COMPILE_STUBGEN) + target_link_libraries(unit_testsuite libjsonrpcstub) + add_dependencies(unit_testsuite libjsonrpcstub) +endif() + +add_test(client ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite "[client]") +add_test(server ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite "[server]") +add_test(NAME common WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite "[common]") + +if(HTTP_CLIENT AND HTTP_SERVER) + add_test(NAME connector_http WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite "[connector_http]") +endif() + +if (UNIX_DOMAIN_SOCKET_CLIENT AND UNIX_DOMAIN_SOCKET_SERVER) + add_test(NAME connector_unixdomainsocket WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite "[connector_unixdomainsocket]") +endif() + +if (TCP_SOCKET_CLIENT AND TCP_SOCKET_SERVER) + add_test(NAME connector_tcpsocket WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite "[connector_tcpsocket]") +endif() + +if(COMPILE_STUBGEN) + add_test(NAME stubgen WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite "[stubgenerator]") +endif() + +if(HTTP_CLIENT AND HTTP_SERVER AND COMPILE_STUBGEN) + add_test(NAME integration WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite "[integration]") +endif() + +add_test(NAME all WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unit_testsuite) + diff --git a/src/test/checkexception.h b/src/test/checkexception.h new file mode 100644 index 0000000000000000000000000000000000000000..77a7b1a2f37b0188cee8974ebbe1e47410fae510 --- /dev/null +++ b/src/test/checkexception.h @@ -0,0 +1,15 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file checkexception.h + * @date 6/7/2015 + * @author Peter Spiess-Knafl <dev@spiessknafl.at> + * @license See attached LICENSE.txt + ************************************************************************/ + +#ifndef CHECKEXCEPTION_H +#define CHECKEXCEPTION_H + +#define CHECK_EXCEPTION_TYPE(throwCode, exceptionType, expression) {bool thrown = false; try {throwCode;} catch(exceptionType &ex) { CHECK(expression(ex)); thrown = true; } CHECK(thrown);} + +#endif // CHECKEXCEPTION_H diff --git a/src/test/main.cpp b/src/test/main.cpp index fdf4b6b1e7f5355f5095c0195c476f18422754a4..f8270db6bc8f5c64b4dedb1a85c5d96b8f61355e 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -7,7 +7,5 @@ * @license See attached LICENSE.txt ************************************************************************/ -#define BOOST_TEST_MODULE "libjson-rpc-cpp test suite" -#define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MAIN -#include <boost/test/unit_test.hpp> +#define CATCH_CONFIG_MAIN +#include <catch.hpp> diff --git a/src/test/mockclientconnectionhandler.cpp b/src/test/mockclientconnectionhandler.cpp index c904d26a00e2433e1c57dd66c3c39baf920aa07a..8afe8b2133e4ac2068ab465b447709bc52c2ce2a 100644 --- a/src/test/mockclientconnectionhandler.cpp +++ b/src/test/mockclientconnectionhandler.cpp @@ -8,7 +8,12 @@ ************************************************************************/ #include "mockclientconnectionhandler.h" +#if _MSC_VER +#include <chrono> +#include <thread> +#else #include <unistd.h> +#endif using namespace std; using namespace jsonrpc; @@ -23,7 +28,11 @@ MockClientConnectionHandler::MockClientConnectionHandler() : void MockClientConnectionHandler::HandleRequest(const std::string &request, std::string &retValue) { +#if _MSC_VER + std::this_thread::sleep_for(std::chrono::microseconds(timeout*1000)); +#else usleep(timeout*1000); +#endif this->request = request; retValue = response; } diff --git a/src/test/spec.json b/src/test/spec.json new file mode 100644 index 0000000000000000000000000000000000000000..2eaa32e47c175cb5c085b34e159094feadd18041 --- /dev/null +++ b/src/test/spec.json @@ -0,0 +1,51 @@ +[ + { + "name": "sayHello", + "params": { + "name": "Peter" + }, + "returns": "Hello Peter" + }, + { + "name": "notifyServer" + }, + { + "name": "addNumbers", + "params": [ + 3, + 4 + ], + "returns": 7 + }, + { + "name": "addNumbers2", + "params": [ + 3.2, + 4.1 + ], + "returns": 7.5 + }, + { + "name": "isEqual", + "params": [ + "string1", + "string2" + ], + "returns": false + }, + { + "name": "buildObject", + "params": [ + "peter", + 1990 + ], + "returns": { + "name": "peter", + "year": 1990 + } + }, + { + "name" : "methodWithoutParameters", + "returns": "String" + } +] diff --git a/src/test/test_client.cpp b/src/test/test_client.cpp index 6626deb159db64890f2f804a6baf717a8d1494a2..0676825ad8a04b8996321aec182c56c90a2ee09e 100644 --- a/src/test/test_client.cpp +++ b/src/test/test_client.cpp @@ -7,168 +7,183 @@ * @license See attached LICENSE.txt ************************************************************************/ -#include <boost/test/unit_test.hpp> +#include <catch.hpp> #include <jsonrpccpp/client.h> #include "mockclientconnector.h" +#include "checkexception.h" + +#define TEST_MODULE "[client]" using namespace jsonrpc; using namespace std; -bool check_exception1(JsonRpcException const&ex) -{ - return ex.GetCode() == Errors::ERROR_RPC_JSON_PARSE_ERROR; -} - -bool check_exception2(JsonRpcException const&ex) -{ - return ex.GetCode() == Errors::ERROR_CLIENT_INVALID_RESPONSE; -} - -bool check_exception3(JsonRpcException const&ex) -{ - return ex.GetCode() == Errors::ERROR_RPC_INVALID_REQUEST; -} - -BOOST_AUTO_TEST_SUITE(client) - -struct F { - MockClientConnector c; - Client client; - Json::Value params; - - F() : client(c, JSONRPC_CLIENT_V2) +namespace testclient { + bool check_exception1(JsonRpcException const&ex) { + return ex.GetCode() == Errors::ERROR_RPC_JSON_PARSE_ERROR; } -}; -struct F1 { - MockClientConnector c; - Client client; - Json::Value params; + bool check_exception2(JsonRpcException const&ex) + { + return ex.GetCode() == Errors::ERROR_CLIENT_INVALID_RESPONSE; + } - F1() : client(c, JSONRPC_CLIENT_V1) + bool check_exception3(JsonRpcException const&ex) { + return ex.GetCode() == Errors::ERROR_RPC_INVALID_REQUEST && ex.GetData().size() == 2; } -}; + struct F { + MockClientConnector c; + Client client; + Json::Value params; + + F() : client(c, JSONRPC_CLIENT_V2) + { + } + }; + + struct F1 { + MockClientConnector c; + Client client; + Json::Value params; + + F1() : client(c, JSONRPC_CLIENT_V1) + { + } + }; +} +using namespace testclient; + +TEST_CASE_METHOD(F, "test_client_id", TEST_MODULE) +{ + params.append(33); + c.SetResponse("{\"jsonrpc\":\"2.0\", \"id\": \"1\", \"result\": 23}"); + Json::Value response = client.CallMethod("abcd", params); + CHECK(response.asInt() == 23); -BOOST_FIXTURE_TEST_CASE(test_client_v2_method_success, F) + c.SetResponse("{\"jsonrpc\":\"2.0\", \"id\": 1, \"result\": 24}"); + response = client.CallMethod("abcd", params); + CHECK(response.asInt() == 24); +} + +TEST_CASE_METHOD(F, "test_client_v2_method_success", TEST_MODULE) { params.append(23); c.SetResponse("{\"jsonrpc\":\"2.0\", \"id\": 1, \"result\": 23}"); Json::Value response = client.CallMethod("abcd", params); Json::Value v = c.GetJsonRequest(); - BOOST_CHECK_EQUAL(v["method"].asString(), "abcd"); - BOOST_CHECK_EQUAL(v["params"][0].asInt(), 23); - BOOST_CHECK_EQUAL(v["jsonrpc"].asString(), "2.0"); - BOOST_CHECK_EQUAL(v["id"].asInt(), 1); + CHECK(v["method"].asString() == "abcd"); + CHECK(v["params"][0].asInt() == 23); + CHECK(v["jsonrpc"].asString() == "2.0"); + CHECK(v["id"].asInt() == 1); } -BOOST_FIXTURE_TEST_CASE(test_client_v2_notification_success, F) +TEST_CASE_METHOD(F, "test_client_v2_notification_success", TEST_MODULE) { params.append(23); client.CallNotification("abcd", params); Json::Value v = c.GetJsonRequest(); - BOOST_CHECK_EQUAL(v["method"].asString(), "abcd"); - BOOST_CHECK_EQUAL(v["params"][0].asInt(), 23); - BOOST_CHECK_EQUAL(v["jsonrpc"].asString(), "2.0"); - BOOST_CHECK_EQUAL(v.isMember("id"), false); + CHECK(v["method"].asString() == "abcd"); + CHECK(v["params"][0].asInt() == 23); + CHECK(v["jsonrpc"].asString() == "2.0"); + CHECK(v.isMember("id") == false); } -BOOST_FIXTURE_TEST_CASE(test_client_v2_errorresponse, F) +TEST_CASE_METHOD(F, "test_client_v2_errorresponse", TEST_MODULE) { - c.SetResponse("{\"jsonrpc\":\"2.0\", \"error\": {\"code\": -32600, \"message\": \"Invalid Request\"}, \"id\": null}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception3); + c.SetResponse("{\"jsonrpc\":\"2.0\", \"error\": {\"code\": -32600, \"message\": \"Invalid Request\", \"data\": [1,2]}, \"id\": null}"); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception3); } -BOOST_FIXTURE_TEST_CASE(test_client_v2_invalidjson, F) +TEST_CASE_METHOD(F, "test_client_v2_invalidjson", TEST_MODULE) { c.SetResponse("{\"method\":234"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception1); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception1); } -BOOST_FIXTURE_TEST_CASE(test_client_v2_invalidresponse, F) +TEST_CASE_METHOD(F, "test_client_v2_invalidresponse", TEST_MODULE) { c.SetResponse("{\"jsonrpc\":\"2.0\", \"id\": 1, \"resulto\": 23}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{\"jsonrpc\":\"2.0\", \"id2\": 1, \"result\": 23}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{\"jsonrpc\":\"1.0\", \"id\": 1, \"result\": 23}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{\"id\": 1, \"result\": 23}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{\"jsonrpc\":\"2.0\", \"id\": 1, \"result\": 23, \"error\": {}}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{\"jsonrpc\":\"2.0\", \"id\": 1, \"error\": {}}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{\"jsonrpc\":\"2.0\", \"result\": 23}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("[]"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("23"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); } -BOOST_FIXTURE_TEST_CASE(test_client_v2_batchcall_success, F) +TEST_CASE_METHOD(F, "test_client_v2_batchcall_success", TEST_MODULE) { BatchCall bc; - BOOST_CHECK_EQUAL(bc.addCall("abc", Json::nullValue, false),1); - BOOST_CHECK_EQUAL(bc.addCall("def", Json::nullValue, true), -1); - BOOST_CHECK_EQUAL(bc.addCall("abc", Json::nullValue, false),2); + CHECK(bc.addCall("abc", Json::nullValue, false) == 1); + CHECK(bc.addCall("def", Json::nullValue, true) == -1); + CHECK(bc.addCall("abc", Json::nullValue, false) == 2); c.SetResponse("[{\"jsonrpc\":\"2.0\", \"id\": 1, \"result\": 23},{\"jsonrpc\":\"2.0\", \"id\": 2, \"result\": 24}]"); BatchResponse response = client.CallProcedures(bc); - BOOST_CHECK_EQUAL(response.hasErrors(), false); - BOOST_CHECK_EQUAL(response.getResult(1).asInt(), 23); - BOOST_CHECK_EQUAL(response.getResult(2).asInt(), 24); - BOOST_CHECK_EQUAL(response.getResult(3).isNull(),true); + CHECK(response.hasErrors() == false); + CHECK(response.getResult(1).asInt() == 23); + CHECK(response.getResult(2).asInt() == 24); + CHECK(response.getResult(3).isNull() == true); Json::Value request = c.GetJsonRequest(); - BOOST_CHECK_EQUAL(request.size(), 3); - BOOST_CHECK_EQUAL(request[0]["method"].asString(), "abc"); - BOOST_CHECK_EQUAL(request[0]["id"].asInt(), 1); - BOOST_CHECK_EQUAL(request[1]["method"].asString(), "def"); - BOOST_CHECK_EQUAL(request[1]["id"].isNull(), true); - BOOST_CHECK_EQUAL(request[2]["id"].asInt(), 2); + CHECK(request.size() == 3); + CHECK(request[0]["method"].asString() == "abc"); + CHECK(request[0]["id"].asInt() == 1); + CHECK(request[1]["method"].asString() == "def"); + CHECK(request[1]["id"].isNull() == true); + CHECK(request[2]["id"].asInt() == 2); bc.toString(false); } -BOOST_FIXTURE_TEST_CASE(test_client_v2_batchcall_error, F) +TEST_CASE_METHOD(F, "test_client_v2_batchcall_error", TEST_MODULE) { BatchCall bc; - BOOST_CHECK_EQUAL(bc.addCall("abc", Json::nullValue, false),1); - BOOST_CHECK_EQUAL(bc.addCall("def", Json::nullValue, false),2); - BOOST_CHECK_EQUAL(bc.addCall("abc", Json::nullValue, false),3); + CHECK(bc.addCall("abc", Json::nullValue, false) == 1); + CHECK(bc.addCall("def", Json::nullValue, false) == 2); + CHECK(bc.addCall("abc", Json::nullValue, false) == 3); c.SetResponse("[{\"jsonrpc\":\"2.0\", \"id\": 1, \"result\": 23},{\"jsonrpc\":\"2.0\", \"id\": 2, \"error\": {\"code\": -32001, \"message\": \"error1\"}},{\"jsonrpc\":\"2.0\", \"id\": null, \"error\": {\"code\": -32002, \"message\": \"error2\"}}]"); BatchResponse response = client.CallProcedures(bc); - BOOST_CHECK_EQUAL(response.hasErrors(), true); - BOOST_CHECK_EQUAL(response.getResult(1).asInt(), 23); - BOOST_CHECK_EQUAL(response.getResult(2).isNull(), true); - BOOST_CHECK_EQUAL(response.getResult(3).isNull(),true); - BOOST_CHECK_EQUAL(response.getErrorMessage(2), "error1"); - BOOST_CHECK_EQUAL(response.getErrorMessage(3), ""); + CHECK(response.hasErrors() == true); + CHECK(response.getResult(1).asInt() == 23); + CHECK(response.getResult(2).isNull() == true); + CHECK(response.getResult(3).isNull() == true); + CHECK(response.getErrorMessage(2) == "error1"); + CHECK(response.getErrorMessage(3) == ""); c.SetResponse("{}"); - BOOST_CHECK_EXCEPTION(client.CallProcedures(bc), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallProcedures(bc), JsonRpcException, check_exception2); c.SetResponse("[1,2,3]"); - BOOST_CHECK_EXCEPTION(client.CallProcedures(bc), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallProcedures(bc), JsonRpcException, check_exception2); c.SetResponse("[[],[],[]]"); - BOOST_CHECK_EXCEPTION(client.CallProcedures(bc), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallProcedures(bc), JsonRpcException, check_exception2); } -BOOST_FIXTURE_TEST_CASE(test_client_v1_method_success, F1) +TEST_CASE_METHOD(F1, "test_client_v1_method_success", TEST_MODULE) { params.append(23); c.SetResponse("{\"id\": 1, \"result\": 23, \"error\": null}"); @@ -176,15 +191,15 @@ BOOST_FIXTURE_TEST_CASE(test_client_v1_method_success, F1) Json::Value response = client.CallMethod("abcd", params); Json::Value v = c.GetJsonRequest(); - BOOST_CHECK_EQUAL(v["method"].asString(), "abcd"); - BOOST_CHECK_EQUAL(v["params"][0].asInt(), 23); - BOOST_CHECK_EQUAL(v.isMember("jsonrpc"), false); - BOOST_CHECK_EQUAL(v["id"].asInt(), 1); + CHECK(v["method"].asString() == "abcd"); + CHECK(v["params"][0].asInt() == 23); + CHECK(v.isMember("jsonrpc") == false); + CHECK(v["id"].asInt() == 1); - BOOST_CHECK_EQUAL(response.asInt(),23); + CHECK(response.asInt() == 23); } -BOOST_FIXTURE_TEST_CASE(test_client_v1_notification_success, F1) +TEST_CASE_METHOD(F1, "test_client_v1_notification_success", TEST_MODULE) { params.append(23); @@ -192,41 +207,39 @@ BOOST_FIXTURE_TEST_CASE(test_client_v1_notification_success, F1) Json::Value v = c.GetJsonRequest(); - BOOST_CHECK_EQUAL(v["method"].asString(), "abcd"); - BOOST_CHECK_EQUAL(v["params"][0].asInt(), 23); - BOOST_CHECK_EQUAL(v.isMember("id"), true); - BOOST_CHECK_EQUAL(v["id"], Json::nullValue); + CHECK(v["method"].asString() == "abcd"); + CHECK(v["params"][0].asInt() == 23); + CHECK(v.isMember("id") == true); + CHECK(v["id"] == Json::nullValue); } -BOOST_FIXTURE_TEST_CASE(test_client_v1_errorresponse, F1) +TEST_CASE_METHOD(F1, "test_client_v1_errorresponse", TEST_MODULE) { - c.SetResponse("{\"result\": null, \"error\": {\"code\": -32600, \"message\": \"Invalid Request\"}, \"id\": null}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception3); + c.SetResponse("{\"result\": null, \"error\": {\"code\": -32600, \"message\": \"Invalid Request\", \"data\": [1,2]}, \"id\": null}"); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception3); - c.SetResponse("{\"result\": null, \"error\": {\"code\": -32600}, \"id\": null}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception3); + c.SetResponse("{\"result\": null, \"error\": {\"code\": -32600, \"message\": \"Invalid Request\", \"data\": [1,2]}, \"id\": null}"); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception3); } -BOOST_FIXTURE_TEST_CASE(test_client_v1_invalidresponse, F1) +TEST_CASE_METHOD(F1, "test_client_v1_invalidresponse", TEST_MODULE) { c.SetResponse("{\"id\": 1, \"resulto\": 23, \"error\": null}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{\"id\": 1, \"result\": 23}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{\"id\": 1, \"error\": null}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{\"id\": 1}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{\"id\": 1, \"result\": 23, \"error\": {}}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{\"id\": 1, \"result\": null, \"error\": {}}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("{}"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("[]"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); c.SetResponse("23"); - BOOST_CHECK_EXCEPTION(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client.CallMethod("abcd", Json::nullValue), JsonRpcException, check_exception2); } - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_common.cpp b/src/test/test_common.cpp index 3c24c8f4d17ed22488a3dbc297dc3cab03579670..03de32dbaf507ec5c66cd4aee3135aecf3dc4f56 100644 --- a/src/test/test_common.cpp +++ b/src/test/test_common.cpp @@ -7,18 +7,34 @@ * @license See attached LICENSE.txt ************************************************************************/ -#include <boost/test/unit_test.hpp> +#include <catch.hpp> #include <jsonrpccpp/common/procedure.h> #include <jsonrpccpp/common/exception.h> #include <jsonrpccpp/common/specificationparser.h> #include <jsonrpccpp/common/specificationwriter.h> +#include "checkexception.h" + +#define TEST_MODULE "[common]" using namespace jsonrpc; using namespace std; -BOOST_AUTO_TEST_SUITE(common) +namespace testcommon { + bool check_exception1(JsonRpcException const & ex) + { + return ex.GetCode() == Errors::ERROR_RPC_JSON_PARSE_ERROR; + } + + bool check_exception2(JsonRpcException const & ex) + { + return ex.GetCode() == Errors::ERROR_SERVER_PROCEDURE_SPECIFICATION_SYNTAX; + } +} + + +using namespace testcommon; -BOOST_AUTO_TEST_CASE(test_procedure_parametervalidation) +TEST_CASE("test_procedure_parametervalidation", TEST_MODULE) { Procedure proc1("someprocedure", PARAMS_BY_NAME, JSON_BOOLEAN, "name", JSON_STRING, "ssnr", JSON_INTEGER, NULL); @@ -26,19 +42,19 @@ BOOST_AUTO_TEST_CASE(test_procedure_parametervalidation) Json::Value param1; param1["name"] = "Peter"; param1["ssnr"] = 4711; - BOOST_CHECK_EQUAL(proc1.ValidateNamedParameters(param1), true); + CHECK(proc1.ValidateNamedParameters(param1) == true); //Expected to fail validation Json::Value param2; param2.append("Peter"); param2.append(4711); - BOOST_CHECK_EQUAL(proc1.ValidateNamedParameters(param2), false); + CHECK(proc1.ValidateNamedParameters(param2) == false); //Expected to fail validation Json::Value param3; param3.append(4711); param3.append("Peter"); - BOOST_CHECK_EQUAL(proc1.ValidateNamedParameters(param3), false); + CHECK(proc1.ValidateNamedParameters(param3) == false); Procedure proc2("someprocedure", PARAMS_BY_NAME, JSON_BOOLEAN, "bool", JSON_BOOLEAN, "object", JSON_OBJECT, "array", JSON_ARRAY, "real", JSON_REAL, "int", JSON_INTEGER, NULL); Json::Value param4; @@ -50,92 +66,91 @@ BOOST_AUTO_TEST_CASE(test_procedure_parametervalidation) param4["real"] = 0.332; param4["int"] = 3; - BOOST_CHECK_EQUAL(proc2.ValidateNamedParameters(param4), true); + CHECK(proc2.ValidateNamedParameters(param4) == true); param4["bool"] = "String"; - BOOST_CHECK_EQUAL(proc2.ValidateNamedParameters(param4), false); + CHECK(proc2.ValidateNamedParameters(param4) == false); param4["bool"] = true; param4["object"] = "String"; - BOOST_CHECK_EQUAL(proc2.ValidateNamedParameters(param4), false); + CHECK(proc2.ValidateNamedParameters(param4) == false); param4["object"] = param1; param4["real"] = "String"; - BOOST_CHECK_EQUAL(proc2.ValidateNamedParameters(param4), false); + CHECK(proc2.ValidateNamedParameters(param4) == false); param4["real"] = 0.322; param4["array"] = "String"; - BOOST_CHECK_EQUAL(proc2.ValidateNamedParameters(param4), false); + CHECK(proc2.ValidateNamedParameters(param4) == false); param4["array"] = array; param4["int"] = "String"; - BOOST_CHECK_EQUAL(proc2.ValidateNamedParameters(param4), false); + CHECK(proc2.ValidateNamedParameters(param4) == false); } -BOOST_AUTO_TEST_CASE(test_exception) +TEST_CASE("test_exception", TEST_MODULE) { JsonRpcException ex(Errors::ERROR_CLIENT_CONNECTOR); - BOOST_CHECK_EQUAL(ex.what(), "Exception -32003 : Client connector error"); - BOOST_CHECK_EQUAL(ex.GetMessage(), "Client connector error"); - BOOST_CHECK_EQUAL(ex.GetCode(), -32003); + CHECK(string(ex.what()) == "Exception -32003 : Client connector error"); + CHECK(string(ex.GetMessage()) == "Client connector error"); + CHECK(ex.GetCode() == -32003); JsonRpcException ex2(Errors::ERROR_CLIENT_CONNECTOR, "addInfo"); - BOOST_CHECK_EQUAL(ex2.what(), "Exception -32003 : Client connector error: addInfo"); + CHECK(string(ex2.what()) == "Exception -32003 : Client connector error: addInfo"); JsonRpcException ex3("addInfo"); - BOOST_CHECK_EQUAL(ex3.what(), "addInfo"); - BOOST_CHECK_EQUAL(ex3.GetMessage(), "addInfo"); - BOOST_CHECK_EQUAL(ex3.GetCode(), 0); -} + CHECK(string(ex3.what()) == "addInfo"); + CHECK(ex3.GetMessage() == "addInfo"); + CHECK(ex3.GetCode() == 0); + + Json::Value data; + data.append(13); + data.append(41); + JsonRpcException ex4(Errors::ERROR_RPC_INTERNAL_ERROR, "internal error", data); + CHECK(ex4.GetData().size() == 2); + CHECK(ex4.GetData()[0].asInt() == 13); + CHECK(ex4.GetData()[1].asInt() == 41); -bool check_exception1(JsonRpcException const & ex) -{ - return ex.GetCode() == Errors::ERROR_RPC_JSON_PARSE_ERROR; } -bool check_exception2(JsonRpcException const & ex) +TEST_CASE("test_specificationparser_errors", TEST_MODULE) { - return ex.GetCode() == Errors::ERROR_SERVER_PROCEDURE_SPECIFICATION_SYNTAX; + CHECK_EXCEPTION_TYPE(SpecificationParser::GetProceduresFromFile("testspec1.json"), JsonRpcException, check_exception1); + CHECK_EXCEPTION_TYPE(SpecificationParser::GetProceduresFromFile("testspec2.json"), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(SpecificationParser::GetProceduresFromFile("testspec3.json"), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(SpecificationParser::GetProceduresFromFile("testspec4.json"), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(SpecificationParser::GetProceduresFromString("{}"), JsonRpcException, check_exception2); + + CHECK_EXCEPTION_TYPE(SpecificationParser::GetProceduresFromString("[{\"name\":\"proc1\"},{\"name\":\"proc1\"}]"), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(SpecificationParser::GetProceduresFromString("[{\"name\":\"proc1\", \"params\": {\"param1\": null}}]"), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(SpecificationParser::GetProceduresFromString("[{\"name\":\"proc1\", \"params\": 23}]"), JsonRpcException, check_exception2); } -BOOST_AUTO_TEST_CASE(test_specificationparser_errors) -{ - BOOST_CHECK_EXCEPTION(SpecificationParser::GetProceduresFromFile("testspec1.json"), JsonRpcException, check_exception1); - BOOST_CHECK_EXCEPTION(SpecificationParser::GetProceduresFromFile("testspec2.json"), JsonRpcException, check_exception2); - BOOST_CHECK_EXCEPTION(SpecificationParser::GetProceduresFromFile("testspec3.json"), JsonRpcException, check_exception2); - BOOST_CHECK_EXCEPTION(SpecificationParser::GetProceduresFromFile("testspec4.json"), JsonRpcException, check_exception2); - BOOST_CHECK_EXCEPTION(SpecificationParser::GetProceduresFromString("{}"), JsonRpcException, check_exception2); - - BOOST_CHECK_EXCEPTION(SpecificationParser::GetProceduresFromString("[{\"name\":\"proc1\"},{\"name\":\"proc1\"}]"), JsonRpcException, check_exception2); - BOOST_CHECK_EXCEPTION(SpecificationParser::GetProceduresFromString("[{\"name\":\"proc1\", \"params\": {\"param1\": null}}]"), JsonRpcException, check_exception2); - BOOST_CHECK_EXCEPTION(SpecificationParser::GetProceduresFromString("[{\"name\":\"proc1\", \"params\": 23}]"), JsonRpcException, check_exception2); -} - -BOOST_AUTO_TEST_CASE(test_specificationparser_success) +TEST_CASE("test_specificationparser_success", TEST_MODULE) { std::vector<Procedure> procs = SpecificationParser::GetProceduresFromFile("testspec5.json"); - BOOST_REQUIRE_EQUAL(procs.size(), 4); + REQUIRE(procs.size() == 4); - BOOST_CHECK_EQUAL(procs[0].GetProcedureName(), "testmethod"); - BOOST_CHECK_EQUAL(procs[0].GetReturnType(), JSON_STRING); - BOOST_CHECK_EQUAL(procs[0].GetProcedureType(), RPC_METHOD); - BOOST_CHECK_EQUAL(procs[0].GetParameterDeclarationType(), PARAMS_BY_NAME); + CHECK(procs[0].GetProcedureName() == "testmethod"); + CHECK(procs[0].GetReturnType() == JSON_STRING); + CHECK(procs[0].GetProcedureType() == RPC_METHOD); + CHECK(procs[0].GetParameterDeclarationType() == PARAMS_BY_NAME); - BOOST_CHECK_EQUAL(procs[2].GetProcedureName(), "testmethod2"); - BOOST_CHECK_EQUAL(procs[2].GetReturnType(), JSON_REAL); - BOOST_CHECK_EQUAL(procs[2].GetProcedureType(), RPC_METHOD); - BOOST_CHECK_EQUAL(procs[2].GetParameterDeclarationType(), PARAMS_BY_NAME); + CHECK(procs[2].GetProcedureName() == "testmethod2"); + CHECK(procs[2].GetReturnType() == JSON_REAL); + CHECK(procs[2].GetProcedureType() == RPC_METHOD); + CHECK(procs[2].GetParameterDeclarationType() == PARAMS_BY_NAME); - BOOST_CHECK_EQUAL(procs[1].GetProcedureName(), "testnotification"); - BOOST_CHECK_EQUAL(procs[1].GetProcedureType(), RPC_NOTIFICATION); - BOOST_CHECK_EQUAL(procs[1].GetParameterDeclarationType(), PARAMS_BY_NAME); + CHECK(procs[1].GetProcedureName() == "testnotification"); + CHECK(procs[1].GetProcedureType() == RPC_NOTIFICATION); + CHECK(procs[1].GetParameterDeclarationType() == PARAMS_BY_NAME); - BOOST_CHECK_EQUAL(procs[3].GetProcedureName(), "testnotification2"); - BOOST_CHECK_EQUAL(procs[3].GetProcedureType(), RPC_NOTIFICATION); - BOOST_CHECK_EQUAL(procs[3].GetParameterDeclarationType(), PARAMS_BY_NAME); + CHECK(procs[3].GetProcedureName() == "testnotification2"); + CHECK(procs[3].GetProcedureType() == RPC_NOTIFICATION); + CHECK(procs[3].GetParameterDeclarationType() == PARAMS_BY_NAME); } -BOOST_AUTO_TEST_CASE(test_specificationwriter) +TEST_CASE("test_specificationwriter", TEST_MODULE) { vector<Procedure> procedures; @@ -149,38 +164,36 @@ BOOST_AUTO_TEST_CASE(test_specificationwriter) Json::Value result = SpecificationWriter::toJsonValue(procedures); - BOOST_REQUIRE_EQUAL(result.isArray(), true); - BOOST_REQUIRE_EQUAL(result.size(), procedures.size()); + REQUIRE(result.isArray() == true); + REQUIRE(result.size() == procedures.size()); - BOOST_CHECK_EQUAL(result[0]["name"].asString(), "testmethod1"); - BOOST_CHECK_EQUAL(result[1]["name"].asString(), "testmethod2"); - BOOST_CHECK_EQUAL(result[2]["name"].asString(), "testnotification1"); - BOOST_CHECK_EQUAL(result[3]["name"].asString(), "testnotification2"); - BOOST_CHECK_EQUAL(result[4]["name"].asString(), "testnotification3"); + CHECK(result[0]["name"].asString() == "testmethod1"); + CHECK(result[1]["name"].asString() == "testmethod2"); + CHECK(result[2]["name"].asString() == "testnotification1"); + CHECK(result[3]["name"].asString() == "testnotification2"); + CHECK(result[4]["name"].asString() == "testnotification3"); - BOOST_REQUIRE_EQUAL(result[0]["params"].isObject(), true); - BOOST_CHECK_EQUAL(result[0]["params"]["param1"].isInt(), true); - BOOST_CHECK_EQUAL(result[0]["params"]["param2"].isDouble(), true); + REQUIRE(result[0]["params"].isObject() == true); + CHECK(result[0]["params"]["param1"].isIntegral() == true); + CHECK(result[0]["params"]["param2"].isDouble() == true); - BOOST_REQUIRE_EQUAL(result[1]["params"].isArray(), true); - BOOST_CHECK_EQUAL(result[1]["params"][0].isObject(), true); - BOOST_CHECK_EQUAL(result[1]["params"][1].isArray(), true); + REQUIRE(result[1]["params"].isArray() == true); + CHECK(result[1]["params"][0].isObject() == true); + CHECK(result[1]["params"][1].isArray() == true); - BOOST_REQUIRE_EQUAL(result[2]["params"].isObject(), true); - BOOST_CHECK_EQUAL(result[2]["params"]["param1"].isBool(), true); - BOOST_CHECK_EQUAL(result[2]["params"]["param2"].isString(), true); + REQUIRE(result[2]["params"].isObject() == true); + CHECK(result[2]["params"]["param1"].isBool() == true); + CHECK(result[2]["params"]["param2"].isString() == true); - BOOST_REQUIRE_EQUAL(result[3]["params"].isArray(), true); - BOOST_CHECK_EQUAL(result[3]["params"][0].isInt(), true); - BOOST_CHECK_EQUAL(result[3]["params"][1].isString(), true); + REQUIRE(result[3]["params"].isArray() == true); + CHECK(result[3]["params"][0].isIntegral() == true); + CHECK(result[3]["params"][1].isString() == true); - BOOST_CHECK_EQUAL(result[4].isMember("params"), false); + CHECK(result[4].isMember("params") == false); - BOOST_CHECK_EQUAL(result[0]["returns"].isInt(), true); - BOOST_CHECK_EQUAL(result[1]["returns"].isInt(), true); + CHECK(result[0]["returns"].isIntegral() == true); + CHECK(result[1]["returns"].isIntegral() == true); - BOOST_CHECK_EQUAL(SpecificationWriter::toFile("testspec.json", procedures), true); - BOOST_CHECK_EQUAL(SpecificationWriter::toFile("/a/b/c/testspec.json", procedures), false); + CHECK(SpecificationWriter::toFile("testspec.json", procedures) == true); + CHECK(SpecificationWriter::toFile("/a/b/c/testspec.json", procedures) == false); } - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_connector_http.cpp b/src/test/test_connector_http.cpp index 44b18944ec3e72b4d984cef7048c927151b62566..1100a2207a673df85ad4e95b6d66586ee6c8be9b 100644 --- a/src/test/test_connector_http.cpp +++ b/src/test/test_connector_http.cpp @@ -8,14 +8,14 @@ ************************************************************************/ #ifdef HTTP_TESTING -#include <boost/test/unit_test.hpp> - +#include <catch.hpp> #include <jsonrpccpp/server/connectors/httpserver.h> #include <jsonrpccpp/client/connectors/httpclient.h> #include <curl/curl.h> #include "mockclientconnectionhandler.h" #include "testhttpserver.h" +#include "checkexception.h" using namespace jsonrpc; using namespace std; @@ -23,126 +23,138 @@ using namespace std; #define TEST_PORT 8383 #define CLIENT_URL "http://localhost:8383" -BOOST_AUTO_TEST_SUITE(connector_http) - -struct F { - HttpServer server; - HttpClient client; - MockClientConnectionHandler handler; +#define TEST_MODULE "[connector_http]" - F() : - server(TEST_PORT), - client(CLIENT_URL) +namespace testhttpserver +{ + struct F { + HttpServer server; + HttpClient client; + MockClientConnectionHandler handler; + + F() : + server(TEST_PORT), + client(CLIENT_URL) + { + server.SetHandler(&handler); + server.StartListening(); + } + ~F() + { + server.StopListening(); + } + }; + + bool check_exception1(JsonRpcException const&ex) { - server.SetHandler(&handler); - server.StartListening(); + return ex.GetCode() == Errors::ERROR_CLIENT_CONNECTOR; } - ~F() + + bool check_exception2(JsonRpcException const&ex) { - server.StopListening(); + return ex.GetCode() == Errors::ERROR_RPC_INTERNAL_ERROR; } -}; - -bool check_exception1(JsonRpcException const&ex) -{ - return ex.GetCode() == Errors::ERROR_CLIENT_CONNECTOR; } +using namespace testhttpserver; -bool check_exception2(JsonRpcException const&ex) -{ - return ex.GetCode() == Errors::ERROR_RPC_INTERNAL_ERROR; -} - -BOOST_FIXTURE_TEST_CASE(test_http_success, F) +TEST_CASE_METHOD(F, "test_http_success", TEST_MODULE) { handler.response = "exampleresponse"; string result; client.SendRPCMessage("examplerequest", result); - BOOST_CHECK_EQUAL(handler.request, "examplerequest"); - BOOST_CHECK_EQUAL(result, "exampleresponse"); + CHECK(handler.request == "examplerequest"); + CHECK(result == "exampleresponse"); +} + +TEST_CASE("test_http_client_error", TEST_MODULE) +{ + HttpClient client("http://someinvalidurl/asdf"); + string result; + CHECK_EXCEPTION_TYPE(client.SendRPCMessage("asdfasfwer", result), JsonRpcException, check_exception1); } #ifndef WIN32 -BOOST_AUTO_TEST_CASE(test_http_server_multiplestart) +TEST_CASE("test_http_server_multiplestart", TEST_MODULE) { HttpServer server(TEST_PORT); - BOOST_CHECK_EQUAL(server.StartListening(), true); + CHECK(server.StartListening() == true); HttpServer server2(TEST_PORT); - BOOST_CHECK_EQUAL(server2.StartListening(), false); + CHECK(server2.StartListening() == false); - BOOST_CHECK_EQUAL(server.StopListening(), true); + CHECK(server.StopListening() == true); } #endif -BOOST_FIXTURE_TEST_CASE(test_http_client_timeout, F) +TEST_CASE_METHOD(F, "test_http_client_timeout", TEST_MODULE) { handler.timeout = 20; client.SetTimeout(10); string result; - BOOST_CHECK_EXCEPTION(client.SendRPCMessage("Test", result), JsonRpcException, check_exception1); + CHECK_EXCEPTION_TYPE(client.SendRPCMessage("Test", result), JsonRpcException, check_exception1); handler.timeout = 0; client.SetTimeout(10000); handler.response = "asdf"; client.SendRPCMessage("", result); - BOOST_CHECK_EQUAL(result, "asdf"); + CHECK(result == "asdf"); server.StopListening(); - BOOST_CHECK_EXCEPTION(client.SendRPCMessage("Test", result), JsonRpcException, check_exception1); + CHECK_EXCEPTION_TYPE(client.SendRPCMessage("Test", result), JsonRpcException, check_exception1); } -BOOST_AUTO_TEST_CASE(test_http_client_headers) +TEST_CASE("test_http_client_headers", TEST_MODULE) { TestHttpServer server(TEST_PORT); HttpClient client(CLIENT_URL); - BOOST_REQUIRE_EQUAL(server.StartListening(),true); + + REQUIRE(server.StartListening() == true); client.AddHeader("X-Auth", "1234"); server.SetResponse("asdf"); string result; client.SendRPCMessage("", result); - BOOST_CHECK_EQUAL(result, "asdf"); - BOOST_CHECK_EQUAL(server.GetHeader("X-Auth"), "1234"); + CHECK(result == "asdf"); + CHECK(server.GetHeader("X-Auth") == "1234"); client.RemoveHeader("X-Auth"); client.SendRPCMessage("", result); - BOOST_CHECK_EQUAL(server.GetHeader("X-Auth"), ""); + CHECK(server.GetHeader("X-Auth") == ""); server.StopListening(); } -BOOST_FIXTURE_TEST_CASE(test_http_get,F) +TEST_CASE_METHOD(F, "test_http_get", TEST_MODULE) { CURL* curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, CLIENT_URL); curl_easy_setopt(curl, CURLOPT_NOBODY, 1); CURLcode code = curl_easy_perform(curl); - BOOST_REQUIRE_EQUAL(code, CURLE_OK); + REQUIRE(code == CURLE_OK); long http_code = 0; curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code); - BOOST_CHECK_EQUAL(http_code, 405); + CHECK(http_code == 405); curl_easy_cleanup(curl); } -BOOST_FIXTURE_TEST_CASE(test_http_get_options, F) +TEST_CASE_METHOD(F, "test_http_get_options", TEST_MODULE) { CURL* curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, CLIENT_URL); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "OPTIONS"); CURLcode code = curl_easy_perform(curl); - BOOST_REQUIRE_EQUAL(code, CURLE_OK); + REQUIRE(code == CURLE_OK); long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); - BOOST_CHECK_EQUAL(http_code, 200); // No error when server asked for OPTIONS. + CHECK(http_code == 200); // No error when server asked for OPTIONS. curl_easy_cleanup(curl); } -BOOST_AUTO_TEST_CASE(test_http_server_endpoints) +TEST_CASE("test_http_server_endpoints", TEST_MODULE) { MockClientConnectionHandler handler1; MockClientConnectionHandler handler2; @@ -154,32 +166,36 @@ BOOST_AUTO_TEST_CASE(test_http_server_endpoints) server.SetUrlHandler("/handler1", &handler1); server.SetUrlHandler("/handler2", &handler2); - BOOST_REQUIRE_EQUAL(server.StartListening(), true); + REQUIRE(server.StartListening() == true); HttpClient client1("http://localhost:8383/handler1"); HttpClient client2("http://localhost:8383/handler2"); HttpClient client3("http://localhost:8383/handler3"); string response; client1.SendRPCMessage("test", response); - BOOST_CHECK_EQUAL(response, "response1"); + CHECK(response == "response1"); client2.SendRPCMessage("test", response); - BOOST_CHECK_EQUAL(response, "response2"); + CHECK(response == "response2"); - BOOST_CHECK_EXCEPTION(client3.SendRPCMessage("test", response), JsonRpcException, check_exception2); + CHECK_EXCEPTION_TYPE(client3.SendRPCMessage("test", response), JsonRpcException, check_exception2); client3.SetUrl("http://localhost:8383/handler2"); client3.SendRPCMessage("test", response); - BOOST_CHECK_EQUAL(response, "response2"); + CHECK(response == "response2"); server.StopListening(); } -BOOST_FIXTURE_TEST_CASE(test_http_server_longpost, F) + +TEST_CASE_METHOD(F, "test_http_server_longpost", TEST_MODULE) { int mb = 5; unsigned long size = mb * 1024*1024; char* str = (char*) malloc(size * sizeof(char)); - BOOST_REQUIRE(str != NULL); + if (str == NULL) + { + FAIL("Could not allocate enough memory for test"); + } for (unsigned long i=0; i < size; i++) { str[i] = (char)('a'+(i%26)); @@ -191,24 +207,21 @@ BOOST_FIXTURE_TEST_CASE(test_http_server_longpost, F) client.SetTimeout(-1); client.SendRPCMessage(str, response); - BOOST_CHECK_EQUAL(handler.request, str); - BOOST_CHECK_EQUAL(response, handler.response); - BOOST_CHECK_EQUAL(response.size(), size-1); + CHECK(handler.request == str); + CHECK(response == handler.response); + CHECK(response.size() == size-1); free(str); } -BOOST_AUTO_TEST_CASE(test_http_server_ssl) +TEST_CASE("test_http_server_ssl", TEST_MODULE) { HttpServer server(TEST_PORT, "/a/b/c", "/d/e/f"); - BOOST_CHECK_EQUAL(server.StartListening(), false); + CHECK(server.StartListening() == false); HttpServer server2(TEST_PORT, "server.pem", "server.key"); - BOOST_CHECK_EQUAL(server2.StartListening(), true); + CHECK(server2.StartListening() == true); server2.StopListening(); } -BOOST_AUTO_TEST_SUITE_END() - - #endif diff --git a/src/test/test_connector_tcpsocket.cpp b/src/test/test_connector_tcpsocket.cpp new file mode 100644 index 0000000000000000000000000000000000000000..920077bf1e51c327de34f9d283646829f58fde8a --- /dev/null +++ b/src/test/test_connector_tcpsocket.cpp @@ -0,0 +1,94 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file test_connector_tcpsocket.cpp + * @date 27/07/2015 + * @author Alexandre Poirot <alexandre.poirot@legrand.fr> + * @license See attached LICENSE.txt + ************************************************************************/ + +#ifdef TCPSOCKET_TESTING +#include <catch.hpp> +#include <jsonrpccpp/server/connectors/tcpsocketserver.h> +#include <jsonrpccpp/client/connectors/tcpsocketclient.h> +#include "mockclientconnectionhandler.h" + +#include "checkexception.h" + +using namespace jsonrpc; +using namespace std; + +#ifndef DELIMITER_CHAR + #define DELIMITER_CHAR char(0x0A) +#endif + +#define TEST_MODULE "[connector_tcpsocket]" + +#define IP "127.0.0.1" +#define PORT 50000 + +namespace testtcpsocketserver +{ + struct F { + TcpSocketServer server; + TcpSocketClient client; + MockClientConnectionHandler handler; + + F() : + server(IP, PORT), + client(IP, PORT) + { + server.SetHandler(&handler); + REQUIRE(server.StartListening()); + } + ~F() + { + server.StopListening(); + } + }; + + bool check_exception1(JsonRpcException const&ex) + { + return ex.GetCode() == Errors::ERROR_CLIENT_CONNECTOR; + } +} +using namespace testtcpsocketserver; + +TEST_CASE_METHOD(F, "test_tcpsocket_success", TEST_MODULE) +{ + handler.response = "exampleresponse"; + handler.timeout = 100; + string result; + string request = "examplerequest"; + request.push_back(DELIMITER_CHAR); + string expectedResult = "exampleresponse"; + expectedResult.push_back(DELIMITER_CHAR); + + client.SendRPCMessage(request, result); + + CHECK(handler.request == request); + CHECK(result == expectedResult); +} + +TEST_CASE("test_tcpsocket_server_multiplestart", TEST_MODULE) +{ + TcpSocketServer server(IP, PORT); + CHECK(server.StartListening() == true); + CHECK(server.StartListening() == false); + + TcpSocketServer server2(IP, PORT); + CHECK(server2.StartListening() == false); + CHECK(server2.StopListening() == false); + + CHECK(server.StopListening() == true); +} + + +TEST_CASE("test_tcpsocket_client_invalid", TEST_MODULE) +{ + TcpSocketClient client("127.0.0.1", 40000); //If this test fails, check that port 40000 is really unused. If it is used, change this port value to an unused port, recompile tests and run tests again. + string result; + CHECK_EXCEPTION_TYPE(client.SendRPCMessage("foobar", result), JsonRpcException, check_exception1); +} + +#endif diff --git a/src/test/test_connector_unixdomainsocket.cpp b/src/test/test_connector_unixdomainsocket.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bcd27108abc9e6c887de100bbccb5d7ba919c5a9 --- /dev/null +++ b/src/test/test_connector_unixdomainsocket.cpp @@ -0,0 +1,96 @@ +/************************************************************************* + * libjson-rpc-cpp + ************************************************************************* + * @file test_connector_unixdomainsocket.cpp + * @date 6/8/2015 + * @author Peter Spiess-Knafl <dev@spiessknafl.at> + * @license See attached LICENSE.txt + ************************************************************************/ + +#ifdef UNIXDOMAINSOCKET_TESTING +#include <catch.hpp> +#include <jsonrpccpp/server/connectors/unixdomainsocketserver.h> +#include <jsonrpccpp/client/connectors/unixdomainsocketclient.h> +#include "mockclientconnectionhandler.h" + +#include "checkexception.h" + +using namespace jsonrpc; +using namespace std; + +#ifndef DELIMITER_CHAR + #define DELIMITER_CHAR char(0x0A) +#endif + +#define TEST_MODULE "[connector_unixdomainsocket]" + +#define SOCKET_PATH "/tmp/jsonrpccpp-socket" + +namespace testunixdomainsocketserver +{ + struct F { + UnixDomainSocketServer server; + UnixDomainSocketClient client; + MockClientConnectionHandler handler; + + F() : + server(SOCKET_PATH), + client(SOCKET_PATH) + { + server.SetHandler(&handler); + REQUIRE(server.StartListening()); + } + ~F() + { + server.StopListening(); + unlink(SOCKET_PATH); + } + }; + + bool check_exception1(JsonRpcException const&ex) + { + return ex.GetCode() == Errors::ERROR_CLIENT_CONNECTOR; + } +} +using namespace testunixdomainsocketserver; + +TEST_CASE_METHOD(F, "test_unixdomainsocket_success", TEST_MODULE) +{ + handler.response = "exampleresponse"; + handler.timeout = 100; + string result; + string request = "examplerequest"; + request.push_back(DELIMITER_CHAR); + string expectedResult = "exampleresponse"; + expectedResult.push_back(DELIMITER_CHAR); + + client.SendRPCMessage(request, result); + + CHECK(handler.request == request); + CHECK(result == expectedResult); +} + + +TEST_CASE("test_unixdomainsocket_server_multiplestart", TEST_MODULE) +{ + UnixDomainSocketServer server(SOCKET_PATH); + CHECK(server.StartListening() == true); + CHECK(server.StartListening() == false); + + UnixDomainSocketServer server2(SOCKET_PATH); + CHECK(server2.StartListening() == false); + CHECK(server2.StopListening() == false); + + CHECK(server.StopListening() == true); + + unlink(SOCKET_PATH); +} + +TEST_CASE("test_unixdomainsocket_client_invalid", TEST_MODULE) +{ + UnixDomainSocketClient client("tmp/someinvalidpath"); + string result; + CHECK_EXCEPTION_TYPE(client.SendRPCMessage("foobar", result), JsonRpcException, check_exception1); +} + +#endif diff --git a/src/test/test_integration.cpp b/src/test/test_integration.cpp index 35deb72505e1fb14d0c7693f500c3247b6cacb4c..d8d8744d117456e5d6e8ace99423a0d77f3e180c 100644 --- a/src/test/test_integration.cpp +++ b/src/test/test_integration.cpp @@ -8,13 +8,13 @@ ************************************************************************/ -#ifdef INTEGRATION_TESTING -#include <boost/test/unit_test.hpp> +#ifdef STUBGEN_TESTING +#include <catch.hpp> #include <jsonrpccpp/server/connectors/httpserver.h> #include <jsonrpccpp/client/connectors/httpclient.h> -#include "gen/abstractsubserver.h" +#include "gen/abstractstubserver.h" #include "gen/stubclient.h" using namespace jsonrpc; @@ -22,6 +22,9 @@ using namespace std; #define TEST_PORT 8383 #define CLIENT_URL "http://localhost:8383" +#define TEST_PATH "/tmp/jsonrpccppintegrationtest" + +#define TEST_MODULE "[integration]" class StubServer : public AbstractStubServer { public: @@ -64,9 +67,9 @@ class StubServer : public AbstractStubServer { } }; -BOOST_AUTO_TEST_SUITE(integration) +#ifdef HTTP_TESTING -BOOST_AUTO_TEST_CASE(test_integration1) +TEST_CASE("test_integration_http", TEST_MODULE) { HttpServer sconn(TEST_PORT); HttpClient cconn(CLIENT_URL); @@ -74,20 +77,48 @@ BOOST_AUTO_TEST_CASE(test_integration1) server.StartListening(); StubClient client(cconn); - BOOST_CHECK_EQUAL(client.addNumbers(3,4), 7); - BOOST_CHECK_EQUAL(client.addNumbers2(3.2,4.2), 7.4); - BOOST_CHECK_EQUAL(client.sayHello("Test"), "Hello Test"); - BOOST_CHECK_EQUAL(client.methodWithoutParameters(), "foo"); - BOOST_CHECK_EQUAL(client.isEqual("str1", "str1"), true); - BOOST_CHECK_EQUAL(client.isEqual("str1", "str2"), false); + CHECK(client.addNumbers(3,4) == 7); + CHECK(client.addNumbers2(3.2,4.2) == 7.4); + CHECK(client.sayHello("Test") == "Hello Test"); + CHECK(client.methodWithoutParameters() == "foo"); + CHECK(client.isEqual("str1", "str1") == true); + CHECK(client.isEqual("str1", "str2") == false); Json::Value result = client.buildObject("Test", 33); - BOOST_CHECK_EQUAL(result["name"].asString(), "Test"); - BOOST_CHECK_EQUAL(result["age"].asInt(), 33); + CHECK(result["name"].asString() == "Test"); + CHECK(result["age"].asInt() == 33); server.StopListening(); } -BOOST_AUTO_TEST_SUITE_END() +#endif +#ifdef UNIXDOMAINSOCKET_TESTING + +#include <jsonrpccpp/server/connectors/unixdomainsocketserver.h> +#include <jsonrpccpp/client/connectors/unixdomainsocketclient.h> + +TEST_CASE("test_integration_unixdomain", TEST_MODULE) +{ + UnixDomainSocketServer sconn(TEST_PATH); + UnixDomainSocketClient cconn(TEST_PATH); + + StubServer server(sconn); + server.StartListening(); + StubClient client(cconn); + + CHECK(client.addNumbers(3,4) == 7); + CHECK(client.addNumbers2(3.2,4.2) == 7.4); + CHECK(client.sayHello("Test") == "Hello Test"); + CHECK(client.methodWithoutParameters() == "foo"); + CHECK(client.isEqual("str1", "str1") == true); + CHECK(client.isEqual("str1", "str2") == false); + + Json::Value result = client.buildObject("Test", 33); + CHECK(result["name"].asString() == "Test"); + CHECK(result["age"].asInt() == 33); + + server.StopListening(); +} +#endif #endif diff --git a/src/test/test_server.cpp b/src/test/test_server.cpp index 3db63964e8973427f8a58318ab7b8c49df8e0e3c..3e1c92cfac801ea7ae3ead63a5e9878c5d159269 100644 --- a/src/test/test_server.cpp +++ b/src/test/test_server.cpp @@ -7,366 +7,376 @@ * @license See attached LICENSE.txt ************************************************************************/ -#include <boost/test/unit_test.hpp> +#include <catch.hpp> #include "testserver.h" #include "mockserverconnector.h" +#define TEST_MODULE "[server]" + using namespace jsonrpc; using namespace std; -BOOST_AUTO_TEST_SUITE(server) - -struct F { - MockServerConnector c; - TestServer server; +namespace testserver +{ + struct F { + MockServerConnector c; + TestServer server; - F() : server(c) {} -}; + F() : server(c) {} + }; -struct F1 { - MockServerConnector c; - TestServer server; + struct F1 { + MockServerConnector c; + TestServer server; - F1() : server(c, JSONRPC_SERVER_V1) {} -}; + F1() : server(c, JSONRPC_SERVER_V1) {} + }; +} +using namespace testserver; -BOOST_FIXTURE_TEST_CASE(test_server_v2_method_success, F) +TEST_CASE_METHOD(F, "test_server_v2_method_success", TEST_MODULE) { c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"sayHello\",\"params\":{\"name\":\"Peter\"}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"].asString(),"Hello: Peter!"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["id"].asInt(), 1); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["jsonrpc"].asString(), "2.0"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("error"), false); + CHECK(c.GetJsonResponse()["result"].asString() == "Hello: Peter!"); + CHECK(c.GetJsonResponse()["id"].asInt() == 1); + CHECK(c.GetJsonResponse()["jsonrpc"].asString() == "2.0"); + CHECK(c.GetJsonResponse().isMember("error") == false); c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"add\",\"params\":{\"value1\":5,\"value2\":7}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"].asInt(),12); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["id"].asInt(), 1); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["jsonrpc"].asString(), "2.0"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("error"), false); + CHECK(c.GetJsonResponse()["result"].asInt() == 12); + CHECK(c.GetJsonResponse()["id"].asInt() == 1); + CHECK(c.GetJsonResponse()["jsonrpc"].asString() == "2.0"); + CHECK(c.GetJsonResponse().isMember("error") == false); c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"sub\",\"params\":[5,7]}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"].asInt(),-2); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["id"].asInt(), 1); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["jsonrpc"].asString(), "2.0"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("error"), false); + CHECK(c.GetJsonResponse()["result"].asInt() == -2); + CHECK(c.GetJsonResponse()["id"].asInt() == 1); + CHECK(c.GetJsonResponse()["jsonrpc"].asString() == "2.0"); + CHECK(c.GetJsonResponse().isMember("error") == false); c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": null, \"method\": \"sub\",\"params\":[5,7]}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"].asInt(),-2); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["id"].isNull(), true); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["jsonrpc"].asString(), "2.0"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("error"), false); + CHECK(c.GetJsonResponse()["result"].asInt() == -2); + CHECK(c.GetJsonResponse()["id"].isNull() == true); + CHECK(c.GetJsonResponse()["jsonrpc"].asString() == "2.0"); + CHECK(c.GetJsonResponse().isMember("error") == false); c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": \"1\", \"method\": \"sub\",\"params\":[5,7]}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"].asInt(),-2); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["id"].asString(), "1"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["jsonrpc"].asString(), "2.0"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("error"), false); + CHECK(c.GetJsonResponse()["result"].asInt() == -2); + CHECK(c.GetJsonResponse()["id"].asString() == "1"); + CHECK(c.GetJsonResponse()["jsonrpc"].asString() == "2.0"); + CHECK(c.GetJsonResponse().isMember("error") == false); + + c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 4294967295, \"method\": \"sub\",\"params\":[5,7]}"); + CHECK(c.GetJsonResponse()["result"].asInt() == -2); + CHECK(c.GetJsonResponse()["id"].asLargestUInt() == (unsigned long)4294967295); + CHECK(c.GetJsonResponse()["jsonrpc"].asString() == "2.0"); + CHECK(c.GetJsonResponse().isMember("error") == false); + } -BOOST_FIXTURE_TEST_CASE(test_server_v2_notification_success, F) +TEST_CASE_METHOD(F, "test_server_v2_notification_success", TEST_MODULE) { c.SetRequest("{\"jsonrpc\":\"2.0\", \"method\": \"initCounter\",\"params\":{\"value\": 33}}"); - BOOST_CHECK_EQUAL(server.getCnt(), 33); - BOOST_CHECK_EQUAL(c.GetResponse(), ""); + CHECK(server.getCnt() == 33); + CHECK(c.GetResponse() == ""); c.SetRequest("{\"jsonrpc\":\"2.0\", \"method\": \"incrementCounter\",\"params\":{\"value\": 33}}"); - BOOST_CHECK_EQUAL(server.getCnt(), 66); - BOOST_CHECK_EQUAL(c.GetResponse(), ""); + CHECK(server.getCnt() == 66); + CHECK(c.GetResponse() == ""); } -BOOST_FIXTURE_TEST_CASE(test_server_v2_invalidjson, F) +TEST_CASE_METHOD(F, "test_server_v2_invalidjson", TEST_MODULE) { c.SetRequest("{\"jsonrpc\":\"2."); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32700); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32700); + CHECK(c.GetJsonResponse().isMember("result") == false); } -BOOST_FIXTURE_TEST_CASE(test_server_v2_invalidrequest, F) +TEST_CASE_METHOD(F, "test_server_v2_invalidrequest", TEST_MODULE) { //wrong rpc version c.SetRequest("{\"jsonrpc\":\"1.0\", \"id\": 1, \"method\": \"sayHello\",\"params\":{\"name\":\"Peter\"}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse().isMember("result") == false); //wrong rpc version type c.SetRequest("{\"jsonrpc\":2.0, \"id\": 1, \"method\": \"sayHello\",\"params\":{\"name\":\"Peter\"}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse().isMember("result") == false); //no method name c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1,\"params\":{\"name\":\"Peter\"}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse().isMember("result") == false); //wrong method name type c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": {}, \"params\":{\"name\":\"Peter\"}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse().isMember("result") == false); //invalid param structure c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"sayHello\",\"params\":1}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse().isMember("result") == false); // c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 3.2, \"method\": \"sayHello\",\"params\":{\"name\":\"Peter\"}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse().isMember("result") == false); c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": 3,\"params\":{\"name\":\"Peter\"}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse().isMember("result") == false); c.SetRequest("{}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse().isMember("result") == false); c.SetRequest("[]"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse().isMember("result") == false); c.SetRequest("23"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse().isMember("result") == false); } -BOOST_FIXTURE_TEST_CASE(test_server_v2_method_error, F) +TEST_CASE_METHOD(F, "test_server_v2_method_error", TEST_MODULE) { //invalid methodname c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"sayHello2\",\"params\":{\"name\":\"Peter\"}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32601); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32601); + CHECK(c.GetJsonResponse().isMember("result") == false); //call notification as procedure c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"initCounter\",\"params\":{\"value\":3}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32605); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32605); + CHECK(c.GetJsonResponse().isMember("result") == false); //call procedure as notification c.SetRequest("{\"jsonrpc\":\"2.0\", \"method\": \"sayHello\",\"params\":{\"name\":\"Peter\"}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32604); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32604); + CHECK(c.GetJsonResponse().isMember("result") == false); c.SetRequest("{\"jsonrpc\":\"2.0\", \"method\": \"sub\",\"params\":{\"value1\":3, \"value\": 4}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32604); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32604); + CHECK(c.GetJsonResponse().isMember("result") == false); c.SetRequest("{\"jsonrpc\":\"2.0\", \"method\": \"add\",\"params\":[3,4]}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32604); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32604); + CHECK(c.GetJsonResponse().isMember("result") == false); //userspace exception c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"exceptionMethod\"}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32099); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["message"], "User exception"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32099); + CHECK(c.GetJsonResponse()["error"]["message"] == "User exception"); + CHECK(c.GetJsonResponse()["error"]["data"][0] == 33); + CHECK(c.GetJsonResponse().isMember("result") == false); } -BOOST_FIXTURE_TEST_CASE(test_server_v2_params_error, F) +TEST_CASE_METHOD(F, "test_server_v2_params_error", TEST_MODULE) { //invalid param type c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"sayHello\",\"params\":{\"name\":23}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32602); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32602); + CHECK(c.GetJsonResponse().isMember("result") == false); //invalid param name c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"sayHello\",\"params\":{\"name2\":\"Peter\"}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32602); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32602); + CHECK(c.GetJsonResponse().isMember("result") == false); //invalid parameter passing mode (array instead of object) c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"sayHello\",\"params\":[\"Peter\"]}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32602); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32602); + CHECK(c.GetJsonResponse().isMember("result") == false); //missing parameter field c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"sayHello\"}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32602); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32602); + CHECK(c.GetJsonResponse().isMember("result") == false); } -BOOST_FIXTURE_TEST_CASE(test_server_v2_batchcall_success, F) +TEST_CASE_METHOD(F, "test_server_v2_batchcall_success", TEST_MODULE) { //Simple Batchcall with only methods c.SetRequest("[{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"sayHello\",\"params\":{\"name\":\"Peter\"}},{\"jsonrpc\":\"2.0\", \"id\": 2, \"method\": \"add\",\"params\":{\"value1\":23,\"value2\": 33}}]"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().size(), 2); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[0]["result"].asString(), "Hello: Peter!"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[0]["id"].asInt(), 1); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[1]["result"].asInt(), 56); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[1]["id"].asInt(), 2); + CHECK(c.GetJsonResponse().size() == 2); + CHECK(c.GetJsonResponse()[0]["result"].asString() == "Hello: Peter!"); + CHECK(c.GetJsonResponse()[0]["id"].asInt() == 1); + CHECK(c.GetJsonResponse()[1]["result"].asInt() == 56); + CHECK(c.GetJsonResponse()[1]["id"].asInt() == 2); //Batchcall containing methods and notifications c.SetRequest("[{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"sayHello\",\"params\":{\"name\":\"Peter\"}},{\"jsonrpc\":\"2.0\", \"method\": \"initCounter\",\"params\":{\"value\":23}}]"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().size(), 1); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[0]["result"].asString(), "Hello: Peter!"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[0]["id"].asInt(), 1); - BOOST_CHECK_EQUAL(server.getCnt(), 23); + CHECK(c.GetJsonResponse().size() == 1); + CHECK(c.GetJsonResponse()[0]["result"].asString() == "Hello: Peter!"); + CHECK(c.GetJsonResponse()[0]["id"].asInt() == 1); + CHECK(server.getCnt() == 23); //Batchcall containing only notifications c.SetRequest("[{\"jsonrpc\":\"2.0\", \"method\": \"initCounter\",\"params\":{\"value\":23}},{\"jsonrpc\":\"2.0\", \"method\": \"initCounter\",\"params\":{\"value\":23}}]"); - BOOST_CHECK_EQUAL(c.GetResponse(), ""); + CHECK(c.GetResponse() == ""); } -BOOST_FIXTURE_TEST_CASE(test_server_v2_batchcall_error, F) +TEST_CASE_METHOD(F, "test_server_v2_batchcall_error", TEST_MODULE) { //success and error responses c.SetRequest("[{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"sayHello\",\"params\":{\"name\":\"Peter\"}},{},{\"jsonrpc\":\"2.0\", \"id\": 3, \"method\": \"sayHello\",\"params\":{\"name\":\"Peter3\"}}]"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().size(), 3); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[0]["result"].asString(), "Hello: Peter!"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[0]["id"].asInt(), 1); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[1]["error"]["code"].asInt(), -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[1]["id"].isNull(), true); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[2]["result"].asString(), "Hello: Peter3!"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[2]["id"].asInt(), 3); + CHECK(c.GetJsonResponse().size() == 3); + CHECK(c.GetJsonResponse()[0]["result"].asString() == "Hello: Peter!"); + CHECK(c.GetJsonResponse()[0]["id"].asInt() == 1); + CHECK(c.GetJsonResponse()[1]["error"]["code"].asInt() == -32600); + CHECK(c.GetJsonResponse()[1]["id"].isNull() == true); + CHECK(c.GetJsonResponse()[2]["result"].asString() == "Hello: Peter3!"); + CHECK(c.GetJsonResponse()[2]["id"].asInt() == 3); //only invalid requests c.SetRequest("[1,2,3]"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().size(), 3); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[0]["error"]["code"].asInt(), -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[1]["error"]["code"].asInt(), -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse()[2]["error"]["code"].asInt(), -32600); + CHECK(c.GetJsonResponse().size() == 3); + CHECK(c.GetJsonResponse()[0]["error"]["code"].asInt() == -32600); + CHECK(c.GetJsonResponse()[1]["error"]["code"].asInt() == -32600); + CHECK(c.GetJsonResponse()[2]["error"]["code"].asInt() == -32600); } -BOOST_FIXTURE_TEST_CASE(test_server_v1_method_success, F1) +TEST_CASE_METHOD(F1, "test_server_v1_method_success", TEST_MODULE) { c.SetRequest("{\"id\": 1, \"method\": \"sub\",\"params\":[5,7]}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"].asInt(), -2); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["id"].asInt(), 1); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("jsonrpc"), false); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("error"), true); - BOOST_CHECK_EQUAL(c.GetJsonRequest()["error"], Json::nullValue); + CHECK(c.GetJsonResponse()["result"].asInt() == -2); + CHECK(c.GetJsonResponse()["id"].asInt() == 1); + CHECK(c.GetJsonResponse().isMember("jsonrpc") == false); + CHECK(c.GetJsonResponse().isMember("error") == true); + CHECK(c.GetJsonRequest()["error"] == Json::nullValue); c.SetRequest("{\"id\": \"1\", \"method\": \"sub\",\"params\":[5,7]}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"].asInt(),-2); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["id"].asString(), "1"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("jsonrpc"), false); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("error"), true); - BOOST_CHECK_EQUAL(c.GetJsonRequest()["error"], Json::nullValue); + CHECK(c.GetJsonResponse()["result"].asInt() == -2); + CHECK(c.GetJsonResponse()["id"].asString() == "1"); + CHECK(c.GetJsonResponse().isMember("jsonrpc") == false); + CHECK(c.GetJsonResponse().isMember("error") == true); + CHECK(c.GetJsonRequest()["error"] == Json::nullValue); c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": \"1\", \"method\": \"sub\",\"params\":[5,7]}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"].asInt(),-2); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["id"].asString(), "1"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("jsonrpc"), false); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("error"), true); - BOOST_CHECK_EQUAL(c.GetJsonRequest()["error"], Json::nullValue); + CHECK(c.GetJsonResponse()["result"].asInt() == -2); + CHECK(c.GetJsonResponse()["id"].asString() == "1"); + CHECK(c.GetJsonResponse().isMember("jsonrpc") == false); + CHECK(c.GetJsonResponse().isMember("error") == true); + CHECK(c.GetJsonRequest()["error"] == Json::nullValue); } -BOOST_FIXTURE_TEST_CASE(test_server_v1_notification_success, F1) +TEST_CASE_METHOD(F1, "test_server_v1_notification_success", TEST_MODULE) { c.SetRequest("{\"id\": null, \"method\": \"initZero\", \"params\": null}"); - BOOST_CHECK_EQUAL(server.getCnt(), 0); - BOOST_CHECK_EQUAL(c.GetResponse(), ""); + CHECK(server.getCnt() == 0); + CHECK(c.GetResponse() == ""); } -BOOST_FIXTURE_TEST_CASE(test_server_v1_method_invalid_request, F1) +TEST_CASE_METHOD(F1, "test_server_v1_method_invalid_request", TEST_MODULE) { c.SetRequest("{\"method\": \"sub\", \"params\": []}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"],Json::nullValue); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse()["result"] == Json::nullValue); c.SetRequest("{\"id\": 1, \"method\": \"sub\", \"params\": {\"foo\": true}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"],Json::nullValue); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse()["result"] == Json::nullValue); c.SetRequest("{\"id\": 1, \"method\": \"sub\", \"params\": true}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"],Json::nullValue); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse()["result"] == Json::nullValue); c.SetRequest("{\"id\": 1, \"params\": []}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"], Json::nullValue); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse()["result"] == Json::nullValue); c.SetRequest("{}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"], Json::nullValue); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse()["result"] == Json::nullValue); c.SetRequest("[]"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"], Json::nullValue); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse()["result"] == Json::nullValue); c.SetRequest("23"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"], Json::nullValue); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse()["result"] == Json::nullValue); } -BOOST_FIXTURE_TEST_CASE(test_server_v1_method_error, F1) +TEST_CASE_METHOD(F1, "test_server_v1_method_error", TEST_MODULE) { c.SetRequest("{\"id\": 1, \"method\": \"sub\", \"params\": [33]}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32602); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"],Json::nullValue); + CHECK(c.GetJsonResponse()["error"]["code"] == -32602); + CHECK(c.GetJsonResponse()["result"] ==Json::nullValue); c.SetRequest("{\"id\": 1, \"method\": \"sub\", \"params\": [33, \"foo\"]}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32602); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"],Json::nullValue); + CHECK(c.GetJsonResponse()["error"]["code"] == -32602); + CHECK(c.GetJsonResponse()["result"] == Json::nullValue); c.SetRequest("{\"id\": 1, \"method\": \"sub\"}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"],Json::nullValue); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse()["result"] == Json::nullValue); //userspace exception c.SetRequest("{\"id\": 1, \"method\": \"exceptionMethod\",\"params\":null}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32099); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["message"], "User exception"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"],Json::nullValue); + CHECK(c.GetJsonResponse()["error"]["code"] == -32099); + CHECK(c.GetJsonResponse()["error"]["message"] == "User exception"); + CHECK(c.GetJsonResponse()["result"] == Json::nullValue); } -BOOST_AUTO_TEST_CASE(test_server_hybrid) +TEST_CASE("test_server_hybrid", TEST_MODULE) { MockServerConnector c; TestServer server(c, JSONRPC_SERVER_V1V2); c.SetRequest("{\"id\": 1, \"method\": \"sub\",\"params\":[5,7]}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"].asInt(), -2); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["id"].asInt(), 1); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("jsonrpc"), false); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("error"), true); - BOOST_CHECK_EQUAL(c.GetJsonRequest()["error"], Json::nullValue); + CHECK(c.GetJsonResponse()["result"].asInt() == -2); + CHECK(c.GetJsonResponse()["id"].asInt() == 1); + CHECK(c.GetJsonResponse().isMember("jsonrpc") == false); + CHECK(c.GetJsonResponse().isMember("error") == true); + CHECK(c.GetJsonRequest()["error"] == Json::nullValue); c.SetRequest("{\"id\": null, \"method\": \"initZero\", \"params\": null}"); - BOOST_CHECK_EQUAL(server.getCnt(), 0); - BOOST_CHECK_EQUAL(c.GetResponse(), ""); + CHECK(server.getCnt() == 0); + CHECK(c.GetResponse() == ""); c.SetRequest("{\"jsonrpc\":\"2.0\", \"id\": 1, \"method\": \"sayHello\",\"params\":{\"name\":\"Peter\"}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["result"].asString(),"Hello: Peter!"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["id"].asInt(), 1); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["jsonrpc"].asString(), "2.0"); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("error"), false); + CHECK(c.GetJsonResponse()["result"].asString() == "Hello: Peter!"); + CHECK(c.GetJsonResponse()["id"].asInt() == 1); + CHECK(c.GetJsonResponse()["jsonrpc"].asString() == "2.0"); + CHECK(c.GetJsonResponse().isMember("error") == false); c.SetRequest("{\"jsonrpc\":\"2.0\", \"method\": \"initCounter\",\"params\":{\"value\": 33}}"); - BOOST_CHECK_EQUAL(server.getCnt(), 33); - BOOST_CHECK_EQUAL(c.GetResponse(), ""); + CHECK(server.getCnt() == 33); + CHECK(c.GetResponse() == ""); c.SetRequest("{\"jsonrpc\":\"2.0\", \"params\":{\"value\": 33}}"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32600); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32600); + CHECK(c.GetJsonResponse().isMember("result") == false); c.SetRequest("{\"jsonrpc\":\"2.0\", \"params\":{\"value\": 33"); - BOOST_CHECK_EQUAL(c.GetJsonResponse()["error"]["code"], -32700); - BOOST_CHECK_EQUAL(c.GetJsonResponse().isMember("result"),false); + CHECK(c.GetJsonResponse()["error"]["code"] == -32700); + CHECK(c.GetJsonResponse().isMember("result") == false); } -BOOST_AUTO_TEST_CASE(test_server_abstractserver) +TEST_CASE("test_server_abstractserver", TEST_MODULE) { MockServerConnector c; TestServer server(c, JSONRPC_SERVER_V1V2); - BOOST_CHECK_EQUAL(server.bindAndAddNotification(Procedure("testMethod", PARAMS_BY_NAME, JSON_STRING, "name", JSON_STRING, NULL), &TestServer::initCounter), false); - BOOST_CHECK_EQUAL(server.bindAndAddMethod(Procedure("initCounter", PARAMS_BY_NAME, "value", JSON_INTEGER, NULL), &TestServer::sayHello), false); + CHECK(server.bindAndAddNotification(Procedure("testMethod", PARAMS_BY_NAME, JSON_STRING, "name", JSON_STRING, NULL), &TestServer::initCounter) == false); + CHECK(server.bindAndAddMethod(Procedure("initCounter", PARAMS_BY_NAME, "value", JSON_INTEGER, NULL), &TestServer::sayHello) == false); - BOOST_CHECK_EQUAL(server.bindAndAddMethod(Procedure("testMethod", PARAMS_BY_NAME, JSON_STRING, "name", JSON_STRING, NULL), &TestServer::sayHello), true); - BOOST_CHECK_EQUAL(server.bindAndAddMethod(Procedure("testMethod", PARAMS_BY_NAME, JSON_STRING, "name", JSON_STRING, NULL), &TestServer::sayHello), false); + CHECK(server.bindAndAddMethod(Procedure("testMethod", PARAMS_BY_NAME, JSON_STRING, "name", JSON_STRING, NULL), &TestServer::sayHello) == true); + CHECK(server.bindAndAddMethod(Procedure("testMethod", PARAMS_BY_NAME, JSON_STRING, "name", JSON_STRING, NULL), &TestServer::sayHello) == false); - BOOST_CHECK_EQUAL(server.bindAndAddNotification(Procedure("testNotification", PARAMS_BY_NAME, "value", JSON_INTEGER, NULL), &TestServer::initCounter), true); - BOOST_CHECK_EQUAL(server.bindAndAddNotification(Procedure("testNotification", PARAMS_BY_NAME, "value", JSON_INTEGER, NULL), &TestServer::initCounter), false); + CHECK(server.bindAndAddNotification(Procedure("testNotification", PARAMS_BY_NAME, "value", JSON_INTEGER, NULL), &TestServer::initCounter) == true); + CHECK(server.bindAndAddNotification(Procedure("testNotification", PARAMS_BY_NAME, "value", JSON_INTEGER, NULL), &TestServer::initCounter) == false); - BOOST_CHECK_EQUAL(server.StartListening(), true); - BOOST_CHECK_EQUAL(server.StopListening(), true); + CHECK(server.StartListening() == true); + CHECK(server.StopListening() == true); MockServerConnector c2; - BOOST_CHECK_EQUAL(c2.SetRequest("abcd"), false); + CHECK(c2.SetRequest("abcd") == false); } - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_stubgenerator.cpp b/src/test/test_stubgenerator.cpp index dbc42fdb4af76126b7e07a6385abd3277b2bfd57..9318e3d00e0106e440f8e2f3bc66a622038b2c4b 100644 --- a/src/test/test_stubgenerator.cpp +++ b/src/test/test_stubgenerator.cpp @@ -8,7 +8,7 @@ ************************************************************************/ #ifdef STUBGEN_TESTING -#include <boost/test/unit_test.hpp> +#include <catch.hpp> #include <jsonrpccpp/common/specificationparser.h> #include <stubgenerator/server/cppserverstubgenerator.h> @@ -22,9 +22,32 @@ using namespace jsonrpc; using namespace std; -BOOST_AUTO_TEST_SUITE(stubgenerator) +namespace teststubgen +{ + struct F { + FILE* stdout; + FILE* stderr; + vector<StubGenerator*> stubgens; + vector<Procedure> procedures; + F() + { + stdout = fopen("stdout.txt", "w"); + stderr = fopen("stderr.txt", "w"); + } + + ~F() + { + fclose(stdout); + fclose(stderr); + } + }; +} + +using namespace teststubgen; -BOOST_AUTO_TEST_CASE(test_stubgen_cppclient) +#define TEST_MODULE "[stubgenerator]" + +TEST_CASE("test stubgen cppclient", TEST_MODULE) { stringstream stream; vector<Procedure> procedures = SpecificationParser::GetProceduresFromFile("testspec6.json"); @@ -32,21 +55,21 @@ BOOST_AUTO_TEST_CASE(test_stubgen_cppclient) stubgen.generateStub(); string result = stream.str(); - BOOST_CHECK_NE(result.find("#ifndef JSONRPC_CPP_STUB_NS1_NS2_TESTSTUBCLIENT_H_"), string::npos); - BOOST_CHECK_NE(result.find("#define JSONRPC_CPP_STUB_NS1_NS2_TESTSTUBCLIENT_H_"), string::npos); - BOOST_CHECK_NE(result.find("namespace ns1"), string::npos); - BOOST_CHECK_NE(result.find("namespace ns2"), string::npos); - BOOST_CHECK_NE(result.find("class TestStubClient : public jsonrpc::Client"), string::npos); - BOOST_CHECK_NE(result.find("std::string test_method(const std::string& name) throw (jsonrpc::JsonRpcException)"), string::npos); - BOOST_CHECK_NE(result.find("void test_notification(const std::string& name) throw (jsonrpc::JsonRpcException)"), string::npos); - BOOST_CHECK_NE(result.find("double test_method2(const Json::Value& object, const Json::Value& values) throw (jsonrpc::JsonRpcException)"), string::npos); - BOOST_CHECK_NE(result.find("void test_notification2(const Json::Value& object, const Json::Value& values) throw (jsonrpc::JsonRpcException)"), string::npos); - BOOST_CHECK_NE(result.find("#endif //JSONRPC_CPP_STUB_NS1_NS2_TESTSTUBCLIENT_H_"), string::npos); - - BOOST_CHECK_EQUAL(CPPHelper::class2Filename("ns1::ns2::TestClass"), "testclass.h"); + CHECK(result.find("#ifndef JSONRPC_CPP_STUB_NS1_NS2_TESTSTUBCLIENT_H_") != string::npos); + CHECK(result.find("#define JSONRPC_CPP_STUB_NS1_NS2_TESTSTUBCLIENT_H_") != string::npos); + CHECK(result.find("namespace ns1") != string::npos); + CHECK(result.find("namespace ns2") != string::npos); + CHECK(result.find("class TestStubClient : public jsonrpc::Client") != string::npos); + CHECK(result.find("std::string test_method(const std::string& name) throw (jsonrpc::JsonRpcException)") != string::npos); + CHECK(result.find("void test_notification(const std::string& name) throw (jsonrpc::JsonRpcException)") != string::npos); + CHECK(result.find("double test_method2(const Json::Value& object, const Json::Value& values) throw (jsonrpc::JsonRpcException)") != string::npos); + CHECK(result.find("void test_notification2(const Json::Value& object, const Json::Value& values) throw (jsonrpc::JsonRpcException)") != string::npos); + CHECK(result.find("#endif //JSONRPC_CPP_STUB_NS1_NS2_TESTSTUBCLIENT_H_") != string::npos); + + CHECK(CPPHelper::class2Filename("ns1::ns2::TestClass") == "testclass.h"); } -BOOST_AUTO_TEST_CASE(test_stubgen_cppserver) +TEST_CASE("test stubgen cppserver", TEST_MODULE) { stringstream stream; vector<Procedure> procedures = SpecificationParser::GetProceduresFromFile("testspec6.json"); @@ -54,19 +77,20 @@ BOOST_AUTO_TEST_CASE(test_stubgen_cppserver) stubgen.generateStub(); string result = stream.str(); - BOOST_CHECK_NE(result.find("#ifndef JSONRPC_CPP_STUB_NS1_NS2_TESTSTUBSERVER_H_"), string::npos); - BOOST_CHECK_NE(result.find("#define JSONRPC_CPP_STUB_NS1_NS2_TESTSTUBSERVER_H_"), string::npos); - BOOST_CHECK_NE(result.find("namespace ns1"), string::npos); - BOOST_CHECK_NE(result.find("namespace ns2"), string::npos); - BOOST_CHECK_NE(result.find("class TestStubServer : public jsonrpc::AbstractServer<TestStubServer>"), string::npos); - BOOST_CHECK_NE(result.find("virtual std::string test.method(const std::string& name) = 0;"), string::npos); - BOOST_CHECK_NE(result.find("virtual void test.notification(const std::string& name) = 0;"), string::npos); - BOOST_CHECK_NE(result.find("virtual double test.method2(const Json::Value& object, const Json::Value& values) = 0;"), string::npos); - BOOST_CHECK_NE(result.find("virtual void test.notification2(const Json::Value& object, const Json::Value& values) = 0;"), string::npos); - BOOST_CHECK_NE(result.find("#endif //JSONRPC_CPP_STUB_NS1_NS2_TESTSTUBSERVER_H_"), string::npos); + CHECK(result.find("#ifndef JSONRPC_CPP_STUB_NS1_NS2_TESTSTUBSERVER_H_") != string::npos); + CHECK(result.find("#define JSONRPC_CPP_STUB_NS1_NS2_TESTSTUBSERVER_H_") != string::npos); + CHECK(result.find("namespace ns1") != string::npos); + CHECK(result.find("namespace ns2") != string::npos); + CHECK(result.find("class TestStubServer : public jsonrpc::AbstractServer<TestStubServer>") != string::npos); + CHECK(result.find("virtual std::string test_method(const std::string& name) = 0;") != string::npos); + CHECK(result.find("virtual void test_notification(const std::string& name) = 0;") != string::npos); + CHECK(result.find("virtual double test_method2(const Json::Value& object, const Json::Value& values) = 0;") != string::npos); + CHECK(result.find("virtual void test_notification2(const Json::Value& object, const Json::Value& values) = 0;") != string::npos); + CHECK(result.find("this->bindAndAddMethod(jsonrpc::Procedure(\"test.method\", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, \"name\",jsonrpc::JSON_STRING, NULL), &ns1::ns2::TestStubServer::test_methodI);") != string::npos); + CHECK(result.find("#endif //JSONRPC_CPP_STUB_NS1_NS2_TESTSTUBSERVER_H_") != string::npos); } -BOOST_AUTO_TEST_CASE(test_stubgen_jsclient) +TEST_CASE("test_stubgen_jsclient", TEST_MODULE) { stringstream stream; vector<Procedure> procedures = SpecificationParser::GetProceduresFromFile("testspec6.json"); @@ -74,94 +98,97 @@ BOOST_AUTO_TEST_CASE(test_stubgen_jsclient) stubgen.generateStub(); string result = stream.str(); - BOOST_CHECK_NE(result.find("function TestStubClient(url) {"), string::npos); - BOOST_CHECK_NE(result.find("TestStubClient.prototype.test_method = function(name, callbackSuccess, callbackError)"), string::npos); - BOOST_CHECK_NE(result.find("TestStubClient.prototype.test_notification = function(name, callbackSuccess, callbackError)"), string::npos); - BOOST_CHECK_NE(result.find("TestStubClient.prototype.test_method2 = function(object, values, callbackSuccess, callbackError)"), string::npos); - BOOST_CHECK_NE(result.find("TestStubClient.prototype.test_notification2 = function(object, values, callbackSuccess, callbackError)"), string::npos); + CHECK(result.find("function TestStubClient(url) {") != string::npos); + CHECK(result.find("TestStubClient.prototype.test_method = function(name, callbackSuccess, callbackError)") != string::npos); + CHECK(result.find("TestStubClient.prototype.test_notification = function(name, callbackSuccess, callbackError)") != string::npos); + CHECK(result.find("TestStubClient.prototype.test_method2 = function(object, values, callbackSuccess, callbackError)") != string::npos); + CHECK(result.find("TestStubClient.prototype.test_notification2 = function(object, values, callbackSuccess, callbackError)") != string::npos); - BOOST_CHECK_EQUAL(JSClientStubGenerator::class2Filename("TestClass"), "testclass.js"); + CHECK(JSClientStubGenerator::class2Filename("TestClass") == "testclass.js"); } -BOOST_AUTO_TEST_CASE(test_stubgen_indentation) +TEST_CASE("test_stubgen_indentation", TEST_MODULE) { stringstream stream; CodeGenerator cg(stream); cg.setIndentSymbol(" "); cg.increaseIndentation(); cg.write("abc"); - BOOST_CHECK_EQUAL(stream.str(), " abc"); + CHECK(stream.str() == " abc"); stringstream stream2; CodeGenerator cg2(stream2); cg2.setIndentSymbol("\t"); cg2.increaseIndentation(); cg2.write("abc"); - BOOST_CHECK_EQUAL(stream2.str(), "\tabc"); + CHECK(stream2.str() == "\tabc"); } -BOOST_AUTO_TEST_CASE(test_stubgen_factory_help) +TEST_CASE_METHOD(F, "test_stubgen_factory_help", TEST_MODULE) { - vector<StubGenerator*> stubgens; - vector<Procedure> procedures; const char* argv[2] = {"jsonrpcstub","-h"}; + CHECK(StubGeneratorFactory::createStubGenerators(2, (char**)argv, procedures, stubgens, stdout, stderr) == true); + CHECK(stubgens.empty() == true); + CHECK(procedures.empty() == true); +} + +TEST_CASE_METHOD(F, "test_stubgen_factory_version", TEST_MODULE) +{ + const char* argv[2] = {"jsonrpcstub","--version"}; - BOOST_CHECK_EQUAL(StubGeneratorFactory::createStubGenerators(2, (char**)argv, procedures, stubgens), true); - BOOST_CHECK_EQUAL(stubgens.empty(), true); - BOOST_CHECK_EQUAL(procedures.empty(), true); + CHECK(StubGeneratorFactory::createStubGenerators(2, (char**)argv, procedures, stubgens, stdout, stderr) == true); + CHECK(stubgens.empty() == true); + CHECK(procedures.empty() == true); } -BOOST_AUTO_TEST_CASE(test_stubgen_factory_error) +TEST_CASE_METHOD(F, "test_stubgen_factory_error", TEST_MODULE) { - vector<StubGenerator*> stubgens; - vector<Procedure> procedures; const char* argv[2] = {"jsonrpcstub","--cpp-client=TestClient"}; - BOOST_CHECK_EQUAL(StubGeneratorFactory::createStubGenerators(2, (char**)argv, procedures, stubgens), false); - BOOST_CHECK_EQUAL(stubgens.empty(), true); - BOOST_CHECK_EQUAL(procedures.empty(), true); + CHECK(StubGeneratorFactory::createStubGenerators(2, (char**)argv, procedures, stubgens, stdout, stderr) == false); + CHECK(stubgens.empty() == true); + CHECK(procedures.empty() == true); vector<StubGenerator*> stubgens2; vector<Procedure> procedures2; const char* argv2[2] = {"jsonrpcstub","--cpxp-client=TestClient"}; - BOOST_CHECK_EQUAL(StubGeneratorFactory::createStubGenerators(2, (char**)argv2, procedures2, stubgens2), false); - BOOST_CHECK_EQUAL(stubgens2.empty(), true); - BOOST_CHECK_EQUAL(procedures2.empty(), true); + CHECK(StubGeneratorFactory::createStubGenerators(2, (char**)argv2, procedures2, stubgens2, stdout, stderr) == false); + CHECK(stubgens2.empty() == true); + CHECK(procedures2.empty() == true); vector<StubGenerator*> stubgens3; vector<Procedure> procedures3; const char* argv3[3] = {"jsonrpcstub", "testspec1.json", "--cpp-client=TestClient"}; - BOOST_CHECK_EQUAL(StubGeneratorFactory::createStubGenerators(3, (char**)argv3, procedures3, stubgens3), false); - BOOST_CHECK_EQUAL(stubgens3.empty(), true); - BOOST_CHECK_EQUAL(procedures3.empty(), true); + CHECK(StubGeneratorFactory::createStubGenerators(3, (char**)argv3, procedures3, stubgens3, stdout, stderr) == false); + CHECK(stubgens3.empty() == true); + CHECK(procedures3.empty() == true); } -BOOST_AUTO_TEST_CASE(test_stubgen_factory_success) +TEST_CASE_METHOD(F, "test_stubgen_factory_success", TEST_MODULE) { vector<StubGenerator*> stubgens; vector<Procedure> procedures; const char* argv[5] = {"jsonrpcstub", "testspec6.json", "--js-client=TestClient", "--cpp-client=TestClient", "--cpp-server=TestServer"}; - BOOST_CHECK_EQUAL(StubGeneratorFactory::createStubGenerators(5, (char**)argv, procedures, stubgens), true); - BOOST_CHECK_EQUAL(stubgens.size(), 3); - BOOST_CHECK_EQUAL(procedures.size(), 7); + CHECK(StubGeneratorFactory::createStubGenerators(5, (char**)argv, procedures, stubgens, stdout, stderr) == true); + CHECK(stubgens.size() == 3); + CHECK(procedures.size() == 7); StubGeneratorFactory::deleteStubGenerators(stubgens); } -BOOST_AUTO_TEST_CASE(test_stubgen_factory_fileoverride) +TEST_CASE_METHOD(F, "test_stubgen_factory_fileoverride", TEST_MODULE) { vector<StubGenerator*> stubgens; vector<Procedure> procedures; const char* argv[9] = {"jsonrpcstub", "testspec6.json", "--js-client=TestClient", "--cpp-client=TestClient", "--cpp-server=TestServer", "--cpp-client-file=client.h", "--cpp-server-file=server.h", "--js-client-file=client.js", "-v"}; - BOOST_CHECK_EQUAL(StubGeneratorFactory::createStubGenerators(9, (char**)argv, procedures, stubgens), true); - BOOST_CHECK_EQUAL(stubgens.size(), 3); - BOOST_CHECK_EQUAL(procedures.size(), 7); + CHECK(StubGeneratorFactory::createStubGenerators(9, (char**)argv, procedures, stubgens, stdout, stderr) == true); + CHECK(stubgens.size() == 3); + CHECK(procedures.size() == 7); StubGeneratorFactory::deleteStubGenerators(stubgens); } -BOOST_AUTO_TEST_SUITE_END() #endif diff --git a/src/test/testhttpserver.cpp b/src/test/testhttpserver.cpp index f8802453deabc57d4e9fc99a518b2cff087794a0..7e240a67e149552948fbdfb00a6b4236ed8f3d4c 100644 --- a/src/test/testhttpserver.cpp +++ b/src/test/testhttpserver.cpp @@ -63,7 +63,7 @@ int TestHttpServer::callback(void *cls, MHD_Connection *connection, const char * else { MHD_get_connection_values(connection, MHD_HEADER_KIND, header_iterator, cls); - struct MHD_Response *result = MHD_create_response_from_data(_this->response.size(),(void *) _this->response.c_str(), 0, 1); + struct MHD_Response *result = MHD_create_response_from_buffer(_this->response.size(),(void *) _this->response.c_str(), MHD_RESPMEM_MUST_COPY); MHD_add_response_header(result, "Content-Type", "application/json"); MHD_add_response_header(result, "Access-Control-Allow-Origin", "*"); MHD_queue_response(connection, MHD_HTTP_OK, result); diff --git a/src/test/testserver.cpp b/src/test/testserver.cpp index 2fbe286d32f2e86b0a65369463ad43268073c8ad..589a8e09fbff7a57f538e76271131e86015d56ce 100644 --- a/src/test/testserver.cpp +++ b/src/test/testserver.cpp @@ -53,7 +53,9 @@ void TestServer::exceptionMethod(const Json::Value &request, Json::Value &respon { (void)request; (void)response; - throw JsonRpcException(-32099, "User exception"); + Json::Value data; + data.append(33); + throw JsonRpcException(-32099, "User exception", data); } void TestServer::initCounter(const Json::Value &request) @@ -77,13 +79,13 @@ int TestServer::getCnt() return cnt; } -bool TestServer::bindAndAddMethod(const Procedure& proc, AbstractServer::methodPointer_t pointer) +bool TestServer::bindAndAddMethod(const Procedure& proc, AbstractServer<TestServer>::methodPointer_t pointer) { - return AbstractServer::bindAndAddMethod(proc, pointer); + return AbstractServer<TestServer>::bindAndAddMethod(proc, pointer); } -bool TestServer::bindAndAddNotification(const Procedure& proc, AbstractServer::notificationPointer_t pointer) +bool TestServer::bindAndAddNotification(const Procedure& proc, AbstractServer<TestServer>::notificationPointer_t pointer) { - return AbstractServer::bindAndAddNotification(proc, pointer); + return AbstractServer<TestServer>::bindAndAddNotification(proc, pointer); }