Clean up and update ra_tls demo
This commit is contained in:
		
							parent
							
								
									2810b8e4ce
								
							
						
					
					
						commit
						2d7fbefcc2
					
				
							
								
								
									
										9
									
								
								.github/workflows/hw_mode_test.yml
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										9
									
								
								.github/workflows/hw_mode_test.yml
									
									
									
									
										vendored
									
									
								
							| @ -865,11 +865,14 @@ jobs: | ||||
|         container-name: ${{ github.job }} | ||||
|         build-envs: 'OCCLUM_RELEASE_BUILD=1' | ||||
| 
 | ||||
|     - name: Download and build the pakckages | ||||
|       run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./prepare_and_build_package.sh" | ||||
|     - name: Download source code | ||||
|       run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./download_and_prepare.sh" | ||||
|      | ||||
|     - name: Build and install gRPC+RATLS | ||||
|       run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./build_and_install.sh musl" | ||||
| 
 | ||||
|     - name: Build occlum instances | ||||
|       run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./build_occlum_instance.sh" | ||||
|       run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./build_occlum_instance.sh musl" | ||||
| 
 | ||||
|     - name: Run gRPC server | ||||
|       run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./run.sh server &" | ||||
|  | ||||
| @ -1,23 +1,74 @@ | ||||
| # gRPC Package With RA-TLS | ||||
| 
 | ||||
| ## Simple GRPC protocol for the demo | ||||
| 
 | ||||
| #### Executing the demo in Occlum | ||||
| * Server side, holds a [`json file`](./secret_config.json) including secret name and the secret's base64 encoded string. | ||||
| 
 | ||||
| The following command will download the gRPC source code and apply the ra-tls patches, then build gRPC source code and demo. | ||||
| * Client side, request the secret by the secret name. | ||||
| 
 | ||||
| ## Example libraries/executables in the demo | ||||
| 
 | ||||
| * libhw_grpc_proto.so | ||||
| * libgrpc_ratls_client.so | ||||
| * libgrpc_ratls_server.so | ||||
| * client | ||||
| * server | ||||
| 
 | ||||
| ### APIs defined for sample server and client | ||||
| 
 | ||||
| * Server | ||||
| ``` | ||||
| ./prepare_and_build_package.sh  | ||||
| int gr_start_server( | ||||
|     const char *server_addr, // grpc server address+port, such as "localhost:50051" | ||||
|     const char *config_json, // ratls handshake config json file | ||||
|     const char *secret_json  // secret config json file | ||||
| ); | ||||
| ``` | ||||
| 
 | ||||
| * Client | ||||
| ``` | ||||
| int gr_client_get_secret( | ||||
|     const char *server_addr, // grpc server address+port, such as "localhost:50051" | ||||
|     const char *config_json, // ratls handshake config json file | ||||
|     const char *name, // secret name to be requested | ||||
|     const char *secret_file // secret file to be saved | ||||
| ); | ||||
| ``` | ||||
| 
 | ||||
| All source could be found on [`example`](./grpc/v1.38.1/examples/cpp/ratls/) | ||||
| 
 | ||||
| 
 | ||||
| ## Executing the demo in Occlum | ||||
| 
 | ||||
| The following command will download prerequisite source and the gRPC source code. | ||||
| ``` | ||||
| ./download_and_prepare.sh | ||||
| ``` | ||||
| 
 | ||||
| The following command will patch the gRPC source code and do the build and install. | ||||
| ``` | ||||
| ./build_and_install.sh | ||||
| ``` | ||||
| 
 | ||||
| If musl-libc version is expected. | ||||
| ``` | ||||
| ./build_and_install.sh musl | ||||
| ``` | ||||
| 
 | ||||
| The following command will generate the client and server occlum images. It automatically parses the mr_enclave and mr_signer of the client, and write the value into dynamic_config.json. If you want to verify the other measurements of client, please modify the dynamic_config.json before run the script. | ||||
| ``` | ||||
| ./build_occlum_instance.sh | ||||
| ``` | ||||
| If previous build choice is `musl`. | ||||
| ``` | ||||
| ./build_occlum_instance.sh musl | ||||
| ``` | ||||
| 
 | ||||
| Run the gRPC server & client in occlum. | ||||
| 
 | ||||
| ``` | ||||
| ./run.sh server & | ||||
| ./run.sh client | ||||
| ./run.sh client <request_secret_name> ( cert, key ) | ||||
| ``` | ||||
| 
 | ||||
| ***Note:*** 1. The demo runs in the same machine by default. If you want to run server and client in different machines. Please modify the examples/cpp/ratls. | ||||
|  | ||||
							
								
								
									
										77
									
								
								demos/ra_tls/build_and_install.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										77
									
								
								demos/ra_tls/build_and_install.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,77 @@ | ||||
| #!/bin/bash | ||||
| set -e | ||||
| 
 | ||||
| source ./env.sh | ||||
| 
 | ||||
| BUILD_TYPE=Release | ||||
| 
 | ||||
| if [[ $1 == "musl" ]]; then | ||||
|     echo "*** Build and run musl-libc demo ***" | ||||
|     CC=occlum-gcc | ||||
|     CXX=occlum-g++ | ||||
|     DCAP_LIB_PATH="/opt/occlum/toolchains/dcap_lib/musl" | ||||
|     INSTALL_PREFIX="/usr/local/occlum/x86_64-linux-musl" | ||||
| else | ||||
|     echo "*** Build and run glibc demo ***" | ||||
|     CC=gcc | ||||
|     CXX=g++ | ||||
|     DCAP_LIB_PATH="/opt/occlum/toolchains/dcap_lib/glibc" | ||||
|     INSTALL_PREFIX="/usr/local" | ||||
| fi | ||||
| 
 | ||||
| # Build and install cJSON | ||||
| function build_cjson() { | ||||
|     pushd cJSON-${CJSON_VER} | ||||
|     rm -rf build && mkdir build && cd build | ||||
|     cmake -DENABLE_CJSON_UTILS=On -DENABLE_CJSON_TEST=Off -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \ | ||||
|         -DCMAKE_C_COMPILER=${CC} .. | ||||
|     make install | ||||
|     popd | ||||
| } | ||||
| 
 | ||||
| function build_grpc_ratls() { | ||||
|     # Copy occlum dcap lib first | ||||
|     cp ${DCAP_LIB_PATH}/libocclum_dcap.so* ${INSTALL_PREFIX}/lib | ||||
|     cp /opt/occlum/toolchains/dcap_lib/inc/occlum_dcap.h ${INSTALL_PREFIX}/include/ | ||||
| 
 | ||||
|     # Copy ratls added/updated files to grpc source | ||||
|     cp -rf grpc/${GRPC_VERSION}/* ${GRPC_PATH}/ | ||||
| 
 | ||||
|     ABSEIL_PATH=${GRPC_PATH}/third_party/abseil-cpp | ||||
| 
 | ||||
|     # build and install abseil library | ||||
|     # https://abseil.io/docs/cpp/quickstart-cmake.html | ||||
|     pushd ${ABSEIL_PATH} | ||||
|     rm -rf build && mkdir build && cd build | ||||
|     cmake -DCMAKE_CXX_STANDARD=11 -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \ | ||||
|             -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \ | ||||
|             -DCMAKE_CXX_COMPILER=${CXX} -DCMAKE_C_COMPILER=${CC} .. | ||||
|     make -j `nproc` | ||||
|     make install | ||||
|     popd | ||||
| 
 | ||||
|     # Build grpc + ratls | ||||
|     pushd ${GRPC_PATH} | ||||
|     rm -rf build && mkdir build && cd build | ||||
|     cmake -DgRPC_INSTALL=ON -DgRPC_ABSL_PROVIDER=package -DgRPC_BUILD_TESTS=OFF \ | ||||
|         -DgRPC_BUILD_CSHARP_EXT=OFF -DgRPC_BUILD_GRPC_CSHARP_PLUGIN=OFF \ | ||||
|         -DgRPC_BUILD_GRPC_PHP_PLUGIN=OFF -DgRPC_BUILD_GRPC_RUBY_PLUGIN=OFF \ | ||||
|         -DDEFINE_SGX_RA_TLS_OCCLUM_BACKEND=ON \ | ||||
|         -DCMAKE_CXX_COMPILER=${CXX} -DCMAKE_C_COMPILER=${CC} \ | ||||
|         -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} .. | ||||
|     make -j `nproc` | ||||
|     make install | ||||
|     popd | ||||
| 
 | ||||
|     # Build grpc ratls client and server demo | ||||
|     pushd ${GRPC_PATH}/examples/cpp/ratls | ||||
|     rm -rf build && mkdir -p build | ||||
|     cd build | ||||
|     cmake -D CMAKE_PREFIX_PATH=${INSTALL_PREFIX} -D CMAKE_BUILD_TYPE=${BUILD_TYPE} \ | ||||
|         -DCMAKE_CXX_COMPILER=${CXX} -DCMAKE_C_COMPILER=${CC} .. | ||||
|     make -j `nproc` | ||||
|     popd | ||||
| } | ||||
| 
 | ||||
| build_cjson | ||||
| build_grpc_ratls | ||||
| @ -1,9 +1,8 @@ | ||||
| #!/bin/bash | ||||
| occlum_glibc=/opt/occlum/glibc/lib/ | ||||
| set -ex | ||||
| set -e | ||||
| 
 | ||||
| get_mr() { | ||||
|     sgx_sign dump -enclave ../occlum_instance_$1/build/lib/libocclum-libos.signed.so -dumpfile ../metadata_info_$1.txt | ||||
| function get_mr() { | ||||
|     sgx_sign dump -enclave ../occlum_$1/build/lib/libocclum-libos.signed.so -dumpfile ../metadata_info_$1.txt | ||||
|     if [ "$2" == "mr_enclave" ]; then | ||||
|         sed -n -e '/enclave_hash.m/,/metadata->enclave_css.body.isv_prod_id/p' ../metadata_info_$1.txt |head -3|tail -2|xargs|sed 's/0x//g'|sed 's/ //g' | ||||
|     elif [ "$2" == "mr_signer" ]; then | ||||
| @ -11,43 +10,56 @@ get_mr() { | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| build_instance() { | ||||
| function build_instance() { | ||||
|     # 1. Init Occlum Workspace | ||||
|     rm -rf occlum_instance_$postfix | ||||
|     mkdir occlum_instance_$postfix | ||||
|     pushd occlum_instance_$postfix | ||||
|     rm -rf occlum_$postfix | ||||
|     mkdir occlum_$postfix | ||||
|     pushd occlum_$postfix | ||||
|     occlum init | ||||
|     new_json="$(jq '.resource_limits.user_space_size = "320MB" | | ||||
|                     .process.default_mmap_size = "256MB"' Occlum.json)" && \ | ||||
|     new_json="$(jq '.resource_limits.user_space_size = "500MB"' Occlum.json)" && \ | ||||
|     echo "${new_json}" > Occlum.json | ||||
|     # 2. Copy files into Occlum Workspace and Build | ||||
|     #cp ../dynamic_config.json image/etc/dynamic_config.json | ||||
|     cp ../dynamic_config.json image/dynamic_config.json | ||||
|     #cp ../dynamic_config_$postfix.json image/dynamic_config.json | ||||
| 
 | ||||
|     if [ "$postfix" == "server" ]; then | ||||
|         # Server will verify client's mr_enclave and mr_signer | ||||
|         jq ' .verify_mr_enclave = "on" | | ||||
|              .verify_mr_signer = "on" | | ||||
|              .verify_isv_prod_id = "off" | | ||||
|              .verify_isv_svn = "off" | | ||||
| 	     .sgx_mrs[0].mr_enclave = ''"'`get_mr client mr_enclave`'" | | ||||
| 	     .sgx_mrs[0].mr_signer = ''"'`get_mr client mr_signer`'" ' ../dynamic_config.json > image/dynamic_config.json  | ||||
| 	     .sgx_mrs[0].mr_signer = ''"'`get_mr client mr_signer`'" ' ../ra_config_template.json > dynamic_config.json | ||||
|      | ||||
|         if [ "$libnss_require" == "y" ]; then | ||||
|             cp /lib/x86_64-linux-gnu/libnss*.so.2 image/$occlum_glibc | ||||
|             cp /lib/x86_64-linux-gnu/libresolv.so.2 image/$occlum_glibc | ||||
|         fi | ||||
| 
 | ||||
|         bomfile="../grpc_ratls_server.yaml" | ||||
|     else | ||||
|         # Client verify nothing from server | ||||
|         jq ' .verify_mr_enclave = "off" | | ||||
|              .verify_mr_signer = "off" | | ||||
|              .verify_isv_prod_id = "off" | | ||||
|              .verify_isv_svn = "off" ' ../ra_config_template.json > dynamic_config.json | ||||
| 
 | ||||
|         bomfile="../grpc_ratls_client.yaml" | ||||
|     fi | ||||
|     mkdir -p image/usr/share/grpc | ||||
|     cp -rf /share/grpc/*  image/usr/share/grpc/ | ||||
|     cp $occlum_glibc/libdl.so.2 image/$occlum_glibc | ||||
|     cp $occlum_glibc/librt.so.1 image/$occlum_glibc | ||||
|     cp $occlum_glibc/libm.so.6 image/$occlum_glibc | ||||
|     cp /lib/x86_64-linux-gnu/libtinfo.so.5 image/$occlum_glibc | ||||
|     cp /lib/x86_64-linux-gnu/libnss*.so.2 image/$occlum_glibc | ||||
|     cp /lib/x86_64-linux-gnu/libresolv.so.2 image/$occlum_glibc | ||||
|     cp -rf /etc/hostname image/etc/ | ||||
|     cp -rf /etc/ssl image/etc/ | ||||
|     cp -rf /etc/passwd image/etc/ | ||||
|     cp -rf /etc/group image/etc/ | ||||
|     cp -rf /etc/nsswitch.conf image/etc/ | ||||
|     cp -rf /grpc/examples/cpp/ratls/build/* image/bin/ | ||||
| 
 | ||||
|     rm -rf image | ||||
|     copy_bom -f $bomfile --root image --include-dir /opt/occlum/etc/template | ||||
| 
 | ||||
|     occlum build | ||||
|     popd | ||||
| } | ||||
| 
 | ||||
| if [[ $1 == "musl" ]]; then | ||||
|     echo "*** Build and musl-libc Occlum instance ***" | ||||
| else | ||||
|     echo "*** Build and run glibc Occlum instance ***" | ||||
|     # glibc version requires libnss | ||||
|     libnss_require="y" | ||||
|     occlum_glibc=/opt/occlum/glibc/lib/ | ||||
| fi | ||||
| 
 | ||||
| postfix=client | ||||
| build_instance | ||||
| postfix=server | ||||
|  | ||||
							
								
								
									
										46
									
								
								demos/ra_tls/download_and_prepare.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										46
									
								
								demos/ra_tls/download_and_prepare.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,46 @@ | ||||
| #!/bin/bash | ||||
| set -e | ||||
| 
 | ||||
| source ./env.sh | ||||
| 
 | ||||
| # Download and update cmake | ||||
| function dl_and_build_cmake() { | ||||
|     # Ubuntu 20.04 has newer enough cmake version | ||||
|     if [ -f "/etc/os-release" ]; then | ||||
|         local os_name=$(cat /etc/os-release) | ||||
|         if [[ $os_name =~ "Ubuntu" && $os_name =~ "20.04" ]]; then | ||||
|             return | ||||
|         fi | ||||
|     fi | ||||
| 
 | ||||
|     rm -rf cmake-3.20.2* | ||||
|     wget https://github.com/Kitware/CMake/releases/download/v3.20.2/cmake-3.20.2.tar.gz | ||||
|     tar -zxvf cmake-3.20.2.tar.gz | ||||
|     pushd cmake-3.20.2 | ||||
|     ./bootstrap | ||||
|     make install | ||||
|     popd | ||||
| } | ||||
| 
 | ||||
| # GRPC env | ||||
| function dl_grpc() { | ||||
|     # GRPC source code | ||||
|     rm -rf ${GRPC_PATH} | ||||
|     git clone https://github.com/grpc/grpc -b ${GRPC_VERSION} ${GRPC_PATH} | ||||
|     pushd ${GRPC_PATH} \ | ||||
|         && git checkout ${GRPC_VERSION} \ | ||||
|         && git submodule update --init | ||||
|     popd | ||||
| } | ||||
| 
 | ||||
| # Download cJSON | ||||
| function dl_cjson() { | ||||
|     rm -rf cJSON* | ||||
|     wget https://github.com/DaveGamble/cJSON/archive/refs/tags/v${CJSON_VER}.tar.gz | ||||
|     tar zxvf v${CJSON_VER}.tar.gz | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| dl_and_build_cmake | ||||
| dl_grpc | ||||
| dl_cjson | ||||
							
								
								
									
										7
									
								
								demos/ra_tls/env.sh
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								demos/ra_tls/env.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #!/bin/bash | ||||
| set -e | ||||
| 
 | ||||
| GRPC_VERSION=v1.38.1 | ||||
| GRPC_PATH=grpc-src | ||||
| 
 | ||||
| CJSON_VER=1.7.15 | ||||
| @ -1,46 +0,0 @@ | ||||
| # | ||||
| # Copyright (c) 2022 Intel Corporation | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| 
 | ||||
| set -ex | ||||
| 
 | ||||
| export ABSEIL_PATH=${GRPC_PATH}/third_party/abseil-cpp | ||||
| 
 | ||||
| if [ ! -d "${BUILD_TYPE}" ]; then | ||||
|     BUILD_TYPE=Release | ||||
| fi | ||||
| 
 | ||||
| # build and install abseil library | ||||
| # https://abseil.io/docs/cpp/quickstart-cmake.html | ||||
| if [ ! -d "${ABSEIL_PATH}/build" ]; then | ||||
|     mkdir -p ${ABSEIL_PATH}/build | ||||
|     cd ${ABSEIL_PATH}/build | ||||
|     cmake -DCMAKE_CXX_STANDARD=11 -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \ | ||||
|           -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} .. | ||||
|     make -j `nproc` | ||||
|     make install | ||||
|     cd - | ||||
| fi | ||||
| 
 | ||||
| # build and install grpc library | ||||
| mkdir -p ${GRPC_PATH}/build | ||||
| cd ${GRPC_PATH}/build | ||||
| cmake -DgRPC_INSTALL=ON -DgRPC_ABSL_PROVIDER=package -DgRPC_BUILD_TESTS=OFF \ | ||||
|       -DgRPC_BUILD_CSHARP_EXT=OFF -DgRPC_BUILD_GRPC_CSHARP_PLUGIN=OFF \ | ||||
|       -DgRPC_BUILD_GRPC_PHP_PLUGIN=OFF -DgRPC_BUILD_GRPC_RUBY_PLUGIN=OFF \ | ||||
|       -DDEFINE_SGX_RA_TLS_OCCLUM_BACKEND=ON \ | ||||
|       -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} .. | ||||
| make -j `nproc` | ||||
| make install | ||||
| cd - | ||||
| @ -54,6 +54,7 @@ option(DEFINE_SGX_RA_TLS_OCCLUM_BACKEND "SGX Occlum Backend" OFF) | ||||
| 
 | ||||
| if(DEFINE_SGX_RA_TLS_OCCLUM_BACKEND) | ||||
|   message("SGX_RA_TLS_OCCLUM_BACKEND is defined") | ||||
|   include_directories(/opt/intel/sgxsdk/include) | ||||
|   add_definitions(-DSGX_RA_TLS_OCCLUM_BACKEND) | ||||
| endif() | ||||
| 
 | ||||
| @ -2089,7 +2090,8 @@ if(DEFINE_SGX_RA_TLS_OCCLUM_BACKEND) | ||||
|     gpr | ||||
|     ${_gRPC_SSL_LIBRARIES} | ||||
|     address_sorting | ||||
|     libdcap_quote.a | ||||
|     occlum_dcap | ||||
|     cjson | ||||
|   ) | ||||
| endif() | ||||
| 
 | ||||
| @ -2793,7 +2795,6 @@ add_library(grpc++ | ||||
|   src/cpp/sgx/sgx_ra_tls_backends.cc | ||||
|   src/cpp/sgx/sgx_ra_tls_occlum.cc | ||||
|   src/cpp/sgx/sgx_ra_tls_utils.cc | ||||
|   src/cpp/sgx/cjson/cJSON.c | ||||
| ) | ||||
| 
 | ||||
| set_target_properties(grpc++ PROPERTIES | ||||
|  | ||||
| @ -41,7 +41,7 @@ add_custom_command( | ||||
| include_directories("${CMAKE_CURRENT_BINARY_DIR}") | ||||
| 
 | ||||
| # hw_grpc_proto | ||||
| add_library(hw_grpc_proto | ||||
| add_library(hw_grpc_proto SHARED | ||||
|   ${hw_grpc_srcs} | ||||
|   ${hw_grpc_hdrs} | ||||
|   ${hw_proto_srcs} | ||||
| @ -51,12 +51,14 @@ target_link_libraries(hw_grpc_proto | ||||
|   ${_GRPC_GRPCPP} | ||||
|   ${_PROTOBUF_LIBPROTOBUF}) | ||||
| 
 | ||||
| # Targets greeter_[async_](client|server) | ||||
| foreach(_target grpc_ratls_client grpc_ratls_server) | ||||
|   add_library(${_target} SHARED "${_target}.cc") | ||||
|   target_link_libraries(${_target} | ||||
|     hw_grpc_proto) | ||||
| endforeach() | ||||
| 
 | ||||
| foreach(_target client server) | ||||
|   add_executable(${_target} "${_target}.cc") | ||||
|   target_link_libraries(${_target} | ||||
|     hw_grpc_proto | ||||
|     ${_REFLECTION} | ||||
|     ${_GRPC_GRPCPP} | ||||
|     ${_PROTOBUF_LIBPROTOBUF}) | ||||
|     grpc_ratls_${_target}) | ||||
| endforeach() | ||||
|  | ||||
							
								
								
									
										2
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/build.sh
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								demos/ra_tls/grpc/v1.38.1/examples/cpp/ratls/build.sh
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -18,8 +18,6 @@ set -ex | ||||
| export BUILD_TYPE=Release | ||||
| export EXP_PATH=`dirname $0` | ||||
| 
 | ||||
| ${GRPC_PATH}/build_cpp.sh | ||||
| 
 | ||||
| # build c++ example | ||||
| cd ${EXP_PATH} | ||||
| mkdir -p build | ||||
|  | ||||
| @ -15,72 +15,27 @@ | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #include <grpcpp/grpcpp.h> | ||||
| #include <grpcpp/security/sgx/sgx_ra_tls.h> | ||||
| #include "../grpc_ratls_client.h" | ||||
| 
 | ||||
| #ifdef BAZEL_BUILD | ||||
| #include "examples/protos/ratls.grpc.pb.h" | ||||
| #else | ||||
| #include "ratls.grpc.pb.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "../getopt.hpp" | ||||
| 
 | ||||
| using ratls::Greeter; | ||||
| using ratls::HelloReply; | ||||
| using ratls::HelloRequest; | ||||
| 
 | ||||
| struct argparser { | ||||
|     const char* config; | ||||
|     std::string server_address; | ||||
|     argparser() { | ||||
|         server_address = getarg("localhost:50051", "-host", "--host"); | ||||
|         config = getarg("dynamic_config.json", "-cfg", "--config"); | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| class GreeterClient { | ||||
|     public: | ||||
|         GreeterClient(std::shared_ptr<grpc::Channel> channel) : stub_(Greeter::NewStub(channel)) {} | ||||
| 
 | ||||
|         std::string SayHello(const std::string& user) { | ||||
|             HelloRequest request; | ||||
|             request.set_name(user); | ||||
| 
 | ||||
|             HelloReply reply; | ||||
| 
 | ||||
|             grpc::ClientContext context; | ||||
| 
 | ||||
|             grpc::Status status = stub_->SayHello(&context, request, &reply); | ||||
| 
 | ||||
|             if (status.ok()) { | ||||
|                 return reply.message(); | ||||
|             } else { | ||||
|                 std::cout << status.error_code() << ": " << status.error_message() << std::endl; | ||||
|                 return "RPC failed"; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         std::unique_ptr<Greeter::Stub> stub_; | ||||
| }; | ||||
| 
 | ||||
| void run_client() { | ||||
|     argparser args; | ||||
| 
 | ||||
|     auto cred = grpc::sgx::TlsCredentials(args.config); | ||||
|     auto channel = grpc::CreateChannel(args.server_address, cred); | ||||
| 
 | ||||
|     GreeterClient greeter(channel); | ||||
| 
 | ||||
|     std::string user_a = greeter.SayHello("a"); | ||||
|     std::string user_b = greeter.SayHello("b"); | ||||
| 
 | ||||
|     std::cout << "Greeter received: " << user_a << ", "<< user_b << std::endl; | ||||
| }; | ||||
| 
 | ||||
| int main(int argc, char** argv) { | ||||
|     run_client(); | ||||
|     // Parse arguments
 | ||||
|     if (argc < 3) { | ||||
|         printf("[ERROR] At least one argument must be provided\n\n"); | ||||
|         printf("Usage: client [<request_name>] [<secret_file_to_be_saved>]\n"); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     gr_client_get_secret( | ||||
|         "localhost:50051", | ||||
|         "dynamic_config.json", | ||||
|         argv[1], | ||||
|         argv[2] | ||||
|     ); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| @ -1,316 +0,0 @@ | ||||
| // Simple getopt replacement class (C++11). 
 | ||||
| // - rlyeh, zlib/libpng licensed.
 | ||||
| // https://github.com/r-lyeh-archived/getopt/blob/master/getopt.hpp
 | ||||
| 
 | ||||
| // Two APIs provided:
 | ||||
| //
 | ||||
| // 1) Simple functional api `getarg(...)`. 
 | ||||
| //    - No initialization required: (argc, argv) pair automatically retrieved.
 | ||||
| //    - First argument is default option value, then all option indentifiers follow.
 | ||||
| //
 | ||||
| // int main() {
 | ||||
| //     bool help = getarg( false, "-h", "--help", "-?" );
 | ||||
| //     int version = getarg( 0, "-v", "--version", "--show-version" );
 | ||||
| //     int depth = getarg( 1, "-d", "--depth", "--max-depth");
 | ||||
| //     std::string file = getarg( "", "-f", "--file" );
 | ||||
| //     [...]
 | ||||
| // }
 | ||||
| //
 | ||||
| // 2) Simple OOP map-based api `getopt class`. Initialization (argc, argv) pair required.
 | ||||
| //
 | ||||
| //    This getopt class is a std::map replacement where key/value are std::string types.
 | ||||
| //    Given invokation './app.out --user=me --pass=123 -h' this class delivers not only:
 | ||||
| //    map[0] = "./app.out", map[1] = "--user=me", map[2]="--pass=123", map[3]='-h'
 | ||||
| //    but also, map["--user"]="me", map["--pass"]="123" and also, map["-h"]=true
 | ||||
| //
 | ||||
| //    Additional API:
 | ||||
| //    - .cmdline() for a print app invokation string
 | ||||
| //    - .str() for pretty map printing
 | ||||
| //    - .size() number of arguments (equivalent to argc), rather than std::map.size()
 | ||||
| //
 | ||||
| // int main( int argc, const char **argv ) {
 | ||||
| //     getopt args( argc, argv );
 | ||||
| //     if( args.has("-h") || args.has("--help") || args.has("-?") || args.size() == 1 ) {
 | ||||
| //         std::cout << args["0"] << " [-?|-h|--help] [-v|--version] [--depth=number]" << std::endl;
 | ||||
| //         return 0;
 | ||||
| //     }
 | ||||
| //     if( args.has("-v") || args.has("--version") ) {
 | ||||
| //         std::cout << args["0"] << " sample v1.0.0. Compiled on " << __DATE__ << std::endl;
 | ||||
| //     }
 | ||||
| //     if( args.has("--depth") ) {
 | ||||
| //         int depth = atoi( args["--depth"].c_str() );
 | ||||
| //         std::cout << "depth set to " << depth << std::endl;
 | ||||
| //     }
 | ||||
| //     [...]
 | ||||
| // }
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <map> | ||||
| #include <string> | ||||
| #include <sstream> | ||||
| #include <vector> | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #include <io.h> | ||||
| #include <winsock2.h> | ||||
| #include <shellapi.h> | ||||
| #pragma comment(lib, "Shell32.lib") | ||||
| #else | ||||
| #include <fstream> | ||||
| #include <unistd.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <sstream> | ||||
| #endif | ||||
| 
 | ||||
| #define GETOPT_VERSION "1.0.0" // (2016/04/18) Initial version
 | ||||
| 
 | ||||
| namespace getopt_utils | ||||
| { | ||||
|     // string conversion
 | ||||
| 
 | ||||
|     template< typename T > | ||||
|     inline T as( const std::string &self ) { | ||||
|         T t; | ||||
|         return (std::istringstream(self) >> t) ? t : | ||||
|                (T)(self.size() && (self != "0") && (self != "false")); | ||||
|     } | ||||
| 
 | ||||
|     template<> | ||||
|     inline char as( const std::string &self ) { | ||||
|         return self.size() == 1 ? (char)(self[0]) : (char)(as<int>(self)); | ||||
|     } | ||||
|     template<> | ||||
|     inline signed char as( const std::string &self ) { | ||||
|         return self.size() == 1 ? (signed char)(self[0]) : (signed char)(as<int>(self)); | ||||
|     } | ||||
|     template<> | ||||
|     inline unsigned char as( const std::string &self ) { | ||||
|         return self.size() == 1 ? (unsigned char)(self[0]) : (unsigned char)(as<int>(self)); | ||||
|     } | ||||
| 
 | ||||
|     template<> | ||||
|     inline const char *as( const std::string &self ) { | ||||
|         return self.c_str(); | ||||
|     } | ||||
|     template<> | ||||
|     inline std::string as( const std::string &self ) { | ||||
|         return self; | ||||
|     } | ||||
| 
 | ||||
|     // token split
 | ||||
| 
 | ||||
|     inline size_t split( std::vector<std::string> &tokens, const std::string &self, const std::string &delimiters ) { | ||||
|         std::string str; | ||||
|         tokens.clear(); | ||||
|         for( auto &ch : self ) { | ||||
|             if( delimiters.find_first_of( ch ) != std::string::npos ) { | ||||
|                 if( str.size() ) tokens.push_back( str ), str = ""; | ||||
|                 tokens.push_back( std::string() + ch ); | ||||
|             } else str += ch; | ||||
|         } | ||||
|         return str.empty() ? tokens.size() : ( tokens.push_back( str ), tokens.size() ); | ||||
|     }; | ||||
| 
 | ||||
|     // portable cmdline 
 | ||||
| 
 | ||||
|     inline std::vector<std::string> cmdline() { | ||||
|         std::vector<std::string> args; | ||||
|         std::string arg; | ||||
|     #       ifdef _WIN32 | ||||
|             int argv; | ||||
|             auto *list = CommandLineToArgvW( GetCommandLineW(), &argv ); | ||||
|             if( list ) { | ||||
|                 for( int i = 0; i < argv; ++i ) { | ||||
|                     std::wstring ws( list[i] ); | ||||
|                     args.push_back( std::string( ws.begin(), ws.end() ) ); | ||||
|                 } | ||||
|                 LocalFree(list); | ||||
|             } | ||||
|     #       else | ||||
|             pid_t pid = getpid(); | ||||
| 
 | ||||
|             char fname[32] = {}; | ||||
|             sprintf(fname, "/proc/%d/cmdline", pid); | ||||
|             std::ifstream ifs(fname); | ||||
|             if( ifs.good() ) { | ||||
|                 std::stringstream ss; | ||||
|                 ifs >> ss.rdbuf(); | ||||
|                 arg = ss.str(); | ||||
|             } | ||||
|             for( auto end = arg.size(), i = end - end; i < end; ++i ) { | ||||
|                 auto st = i; | ||||
|                 while (i < arg.size() && arg[i] != '\0') ++i; | ||||
|                 args.push_back( arg.substr(st, i - st) ); | ||||
|             } | ||||
|     #       endif | ||||
|         return args; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // main map class; explicit initialization
 | ||||
| 
 | ||||
| struct getopt : public std::map< std::string, std::string > | ||||
| { | ||||
|     using super = std::map< std::string, std::string >; | ||||
| 
 | ||||
|     getopt( int argc, const char **argv ) : super() { | ||||
|         // reconstruct vector
 | ||||
|         std::vector<std::string> args( argc, std::string() ); | ||||
|         for( int i = 0; i < argc; ++i ) { | ||||
|             args[ i ] = argv[ i ]; | ||||
|         } | ||||
|         // create key=value and key= args as well
 | ||||
|         for( auto &it : args ) { | ||||
|             std::vector<std::string> tokens; | ||||
|             auto size = getopt_utils::split( tokens, it, "=" ); | ||||
| 
 | ||||
|             if( size == 3 && tokens[1] == "=" ) | ||||
|                 (*this)[ tokens[0] ] = tokens[2]; | ||||
|             else | ||||
|             if( size == 2 && tokens[1] == "=" ) | ||||
|                 (*this)[ tokens[0] ] = true; | ||||
|             else | ||||
|             if( size == 1 && tokens[0] != argv[0] ) | ||||
|                 (*this)[ tokens[0] ] = true; | ||||
|         } | ||||
|         // recreate args
 | ||||
|         while( argc-- ) { | ||||
|             (*this)[ std::to_string(argc) ] = std::string( argv[argc] ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     getopt( const std::vector<std::string> &args ) : super() { | ||||
|         std::vector<const char *> argv; | ||||
|         for( auto &it : args ) { | ||||
|             argv.push_back( it.c_str() ); | ||||
|         } | ||||
|         *this = getopt( argv.size(), argv.data() ); | ||||
|     } | ||||
| 
 | ||||
|     size_t size() const { | ||||
|         unsigned i = 0; | ||||
|         while( has(std::to_string(i)) ) ++i; | ||||
|         return i; | ||||
|     } | ||||
| 
 | ||||
|     bool has( const std::string &op ) const { | ||||
|         return this->find(op) != this->end(); | ||||
|     } | ||||
| 
 | ||||
|     std::string str() const { | ||||
|         std::stringstream ss; | ||||
|         std::string sep; | ||||
|         for( auto &it : *this ) { | ||||
|             ss << sep << it.first << "=" << it.second; | ||||
|             sep = ','; | ||||
|         } | ||||
|         return ss.str(); | ||||
|     } | ||||
| 
 | ||||
|     std::string cmdline() const { | ||||
|         std::stringstream cmd; | ||||
|         std::string sep; | ||||
|         // concatenate args
 | ||||
|         for( auto end = size(), arg = end - end; arg < end; ++arg ) { | ||||
|             cmd << sep << this->find(std::to_string(arg))->second; | ||||
|             sep = ' '; | ||||
|         } | ||||
|         return cmd.str(); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // variadic syntax sugars {
 | ||||
| 
 | ||||
| template< typename T > | ||||
| inline T getarg( const T &defaults, const char *argv ) { | ||||
|     static struct getopt map( getopt_utils::cmdline() ); | ||||
|     return map.has( argv ) ? getopt_utils::as<T>(map[ argv ]) : defaults; | ||||
| } | ||||
| 
 | ||||
| template< typename T, typename... Args > | ||||
| inline T getarg( const T &defaults, const char *arg0, Args... argv ) { | ||||
|     T t = getarg<T>( defaults, arg0 ); | ||||
|     return t == defaults ? getarg<T>( defaults, argv... ) : t; | ||||
| } | ||||
| 
 | ||||
| inline const char * getarg( const char *defaults, const char *argv ) { | ||||
|     static struct getopt map( getopt_utils::cmdline() ); | ||||
|     return map.has( argv ) ? getopt_utils::as<const char *>(map[ argv ]) : defaults; | ||||
| } | ||||
| 
 | ||||
| template< typename... Args > | ||||
| inline const char * getarg( const char *defaults, const char *arg0, Args... argv ) { | ||||
|     const char *t = getarg( defaults, arg0 ); | ||||
|     return t == defaults ? getarg( defaults, argv... ) : t; | ||||
| } | ||||
| 
 | ||||
| // }
 | ||||
| 
 | ||||
| 
 | ||||
| #ifdef GETOPT_BUILD_DEMO | ||||
| #include <iostream> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| int main( int argc, const char **argv ) { | ||||
| 
 | ||||
|     auto show_help = [&]() { | ||||
|         std::cout << argv[0] << " [-h|--help|-?] [-f=path|--file=path] [-v|--version] [-d=number|--depth=number|--max-depth=number]" << std::endl; | ||||
|         exit(0); | ||||
|     }; | ||||
| 
 | ||||
|     // Simple functional api. No initialization required.
 | ||||
| 
 | ||||
|     bool help = getarg( false, "-h", "--help", "-?" ); | ||||
|     int version = getarg( 0, "-v", "--version", "--show-version" ); | ||||
|     int depth = getarg( 0, "-d", "--depth", "--max-depth"); | ||||
|     std::string file = getarg( "", "-f", "--file" ); | ||||
| 
 | ||||
|     if( help || argc <= 1 ) { | ||||
|         show_help(); | ||||
|     } | ||||
| 
 | ||||
|     if( version ) { | ||||
|         std::cout << argv[0] << " demo v1.0.0. Compiled on " << __DATE__ << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     if( depth ) { | ||||
|         std::cout << "provided depth: " << depth << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     if( !file.empty() ) { | ||||
|         std::cout << "provided file: " << file << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     // OOP map-based api. Explicit (argc, argv) initialization required.
 | ||||
| 
 | ||||
|     struct getopt args( argc, argv ); | ||||
| 
 | ||||
|     if( args.has("-h") || args.has("--help") || args.has("-?") || args.size() == 1 ) { | ||||
|         show_help(); | ||||
|     } | ||||
| 
 | ||||
|     if( args.has("-v") || args.has("--version") ) { | ||||
|         std::cout << args["0"] << " demo v1.0.0. Compiled on " << __DATE__ << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     if( args.has("-d") || args.has("--depth") || args.has("--max-depth") ) { | ||||
|         std::string arg = args["-d"]; | ||||
|         if( arg.empty() ) arg = args["--depth"]; | ||||
|         if( arg.empty() ) arg = args["--max-depth"]; | ||||
|         int depth = atoi( arg.c_str() ); | ||||
|         std::cout << "provided depth: " << depth << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     if( args.has("-f") || args.has("--file") ) { | ||||
|         std::string arg = args["-f"]; | ||||
|         if( arg.empty() ) arg = args["--file"]; | ||||
|         std::string fname = arg; | ||||
|         std::cout << "provided file: " << fname << std::endl; | ||||
|     } | ||||
| 
 | ||||
|     std::cout << "---" << std::endl; | ||||
|     std::cout << args.cmdline() << std::endl; | ||||
|     //std::cout << args.size() << " provided args: " << args.str() << std::endl;
 | ||||
| } | ||||
| #endif | ||||
| @ -0,0 +1,148 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| 
 | ||||
| #include <grpcpp/grpcpp.h> | ||||
| #include <grpcpp/security/sgx/sgx_ra_tls.h> | ||||
| 
 | ||||
| #ifdef BAZEL_BUILD | ||||
| #include "examples/protos/ratls.grpc.pb.h" | ||||
| #else | ||||
| #include "ratls.grpc.pb.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "../grpc_ratls_client.h" | ||||
| 
 | ||||
| using ratls::GrSecret; | ||||
| using ratls::SecretRequest; | ||||
| using ratls::SecretReply; | ||||
| 
 | ||||
| // Client
 | ||||
| class GrSecretClient { | ||||
|     public: | ||||
|         GrSecretClient(std::shared_ptr<grpc::Channel> channel) : stub_(GrSecret::NewStub(channel)) {} | ||||
| 
 | ||||
|         std::string GetSecret(const std::string& name) { | ||||
|             SecretRequest request; | ||||
|             request.set_name(name); | ||||
| 
 | ||||
|             SecretReply reply; | ||||
| 
 | ||||
|             grpc::ClientContext context; | ||||
| 
 | ||||
|             grpc::Status status = stub_->GetSecret(&context, request, &reply); | ||||
| 
 | ||||
|             if (status.ok()) { | ||||
|                 return reply.secret(); | ||||
|             } else { | ||||
|                 std::cout << status.error_code() << ": " << status.error_message() << std::endl; | ||||
|                 return "RPC failed"; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         std::unique_ptr<GrSecret::Stub> stub_; | ||||
| }; | ||||
| 
 | ||||
| static const unsigned char base64_table[65] = | ||||
|     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||||
| 
 | ||||
| static size_t base64_decode_len(const char *b64input) { | ||||
|     size_t len = strlen(b64input), padding = 0; | ||||
| 
 | ||||
|     if (b64input[len - 1] == '=' && b64input[len - 2] == '=') { //last two chars are =
 | ||||
|         padding = 2; | ||||
|     } else if (b64input[len - 1] == '=') { //last char is =
 | ||||
|         padding = 1; | ||||
|     } | ||||
| 
 | ||||
|     return (len * 3) / 4 - padding; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * base64_decode - Base64 decode | ||||
|  */ | ||||
| void base64_decode(const char *b64input, unsigned char *dest, size_t dest_len) { | ||||
|     unsigned char dtable[256], *pos, block[4], tmp; | ||||
|     size_t i, count, olen; | ||||
|     size_t len = strlen(b64input); | ||||
| 
 | ||||
|     memset(dtable, 0x80, 256); | ||||
|     for (i = 0; i < sizeof(base64_table) - 1; i++) { | ||||
|         dtable[base64_table[i]] = (unsigned char) i; | ||||
|     } | ||||
|     dtable['='] = 0; | ||||
| 
 | ||||
|     olen = base64_decode_len(b64input); | ||||
|     if (olen > dest_len) { | ||||
|         printf("Base64 encoded length %ld is biggeer than %ld\n", olen, dest_len); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     pos = dest; | ||||
|     count = 0; | ||||
|     for (i = 0; i < len; i++) { | ||||
|         tmp = dtable[(unsigned char)b64input[i]]; | ||||
|         if (tmp == 0x80) { | ||||
|             continue; | ||||
|         } | ||||
|         block[count] = tmp; | ||||
|         count++; | ||||
|         if (count == 4) { | ||||
|             *pos++ = (block[0] << 2) | (block[1] >> 4); | ||||
|             *pos++ = (block[1] << 4) | (block[2] >> 2); | ||||
|             *pos++ = (block[2] << 6) | block[3]; | ||||
|             count = 0; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int gr_client_get_secret( | ||||
|     const char *server_addr, | ||||
|     const char *config_json, | ||||
|     const char *name, | ||||
|     const char *secret_file | ||||
| ) | ||||
| { | ||||
|     auto cred = grpc::sgx::TlsCredentials(config_json); | ||||
|     auto channel = grpc::CreateChannel(server_addr, cred); | ||||
| 
 | ||||
|     GrSecretClient gr_secret(channel); | ||||
| 
 | ||||
|     std::string secret = gr_secret.GetSecret(name); | ||||
|     //std::cout << "secret received: " << secret << std::endl;
 | ||||
| 
 | ||||
|     //Decode From Base64
 | ||||
|     size_t len = base64_decode_len(secret.c_str()); | ||||
|     if (len) { | ||||
|         char *secret_orig = (char *)malloc(len); | ||||
|         base64_decode(secret.c_str(), (unsigned char *)secret_orig, len); | ||||
|         std::string secret_string(secret_orig, secret_orig + len - 1); | ||||
| 
 | ||||
|         //write to file
 | ||||
|         std::ofstream myfile; | ||||
|         myfile.open(secret_file); | ||||
|         myfile << secret_string; | ||||
|         myfile.close(); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| @ -0,0 +1,20 @@ | ||||
| #ifndef _GRPC_RATLS_CLIENT_H_ | ||||
| #define _GRPC_RATLS_CLIENT_H_ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| // client get secret
 | ||||
| extern int gr_client_get_secret( | ||||
|     const char *server_addr, // grpc server address+port, such as "localhost:50051"
 | ||||
|     const char *config_json, // ratls handshake config json file
 | ||||
|     const char *name, // secret name to be requested
 | ||||
|     const char *secret_file // secret file to be saved
 | ||||
| ); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif  // _GRPC_RATLS_CLIENT_H_
 | ||||
| @ -0,0 +1,96 @@ | ||||
| /*
 | ||||
|  * | ||||
|  * Copyright (c) 2022 Intel Corporation | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <grpcpp/grpcpp.h> | ||||
| #include <grpcpp/security/sgx/sgx_ra_tls.h> | ||||
| #include <grpcpp/ext/proto_server_reflection_plugin.h> | ||||
| 
 | ||||
| #ifdef BAZEL_BUILD | ||||
| #include "examples/protos/ratls.grpc.pb.h" | ||||
| #else | ||||
| #include "ratls.grpc.pb.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "../grpc_ratls_server.h" | ||||
| 
 | ||||
| using ratls::GrSecret; | ||||
| using ratls::SecretRequest; | ||||
| using ratls::SecretReply; | ||||
| 
 | ||||
| 
 | ||||
| // Logic and data behind the server's behavior.
 | ||||
| class GrSecretServiceImpl final: public GrSecret::Service { | ||||
|     public: | ||||
|         grpc::Status GetSecret( | ||||
|             grpc::ServerContext* context, const SecretRequest* request, SecretReply* reply) override { | ||||
|             //std::cout << "Request:  " << request->name() << std::endl;
 | ||||
|             auto secret = this->get_secret_string(request->name().c_str()); | ||||
|             if (!secret.empty()) { | ||||
|                 reply->set_secret(secret); | ||||
|                 return grpc::Status::OK; | ||||
|             } else { | ||||
|                 return grpc::Status::CANCELLED; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         GrSecretServiceImpl(const char* file) : secret_file(nullptr) { | ||||
|             this->secret_file = file; | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         std::string get_secret_string(const char *name) { | ||||
|             std::string secret = ""; | ||||
|             class grpc::sgx::json_engine secret_config(this->secret_file); | ||||
|             auto item = secret_config.get_item(secret_config.get_handle(), name); | ||||
|             if (item) { | ||||
|                 secret = secret_config.print_item(item); | ||||
|             } | ||||
| 
 | ||||
|             return secret; | ||||
|         } | ||||
| 
 | ||||
|         const char *secret_file; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| int gr_start_server( | ||||
|     const char *server_addr, | ||||
|     const char *config_json, | ||||
|     const char *secret_json | ||||
| )  | ||||
| { | ||||
|     GrSecretServiceImpl service(secret_json); | ||||
| 
 | ||||
|     grpc::EnableDefaultHealthCheckService(true); | ||||
|     grpc::reflection::InitProtoReflectionServerBuilderPlugin(); | ||||
|     grpc::ServerBuilder builder; | ||||
| 
 | ||||
|     auto creds = grpc::sgx::TlsServerCredentials(config_json); | ||||
|     GPR_ASSERT(creds.get() != nullptr); | ||||
| 
 | ||||
|     builder.AddListeningPort(server_addr, creds); | ||||
|     builder.RegisterService(&service); | ||||
| 
 | ||||
|     std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); | ||||
|     std::cout << "Server listening on " << server_addr << std::endl; | ||||
| 
 | ||||
|     server->Wait(); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| @ -0,0 +1,19 @@ | ||||
| #ifndef _GRPC_RATLS_SERVER_H_ | ||||
| #define _GRPC_RATLS_SERVER_H_ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| // start server
 | ||||
| extern int gr_start_server( | ||||
|     const char *server_addr, // grpc server address+port, such as "localhost:50051"
 | ||||
|     const char *config_json, // ratls handshake config json file
 | ||||
|     const char *secret_json  // secret config json file
 | ||||
| ); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif  // _GRPC_RATLS_SERVER_H_
 | ||||
| @ -15,66 +15,15 @@ | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| #include "../grpc_ratls_server.h" | ||||
| 
 | ||||
| #include <grpcpp/grpcpp.h> | ||||
| #include <grpcpp/security/sgx/sgx_ra_tls.h> | ||||
| #include <grpcpp/ext/proto_server_reflection_plugin.h> | ||||
| 
 | ||||
| #ifdef BAZEL_BUILD | ||||
| #include "examples/protos/ratls.grpc.pb.h" | ||||
| #else | ||||
| #include "ratls.grpc.pb.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "../getopt.hpp" | ||||
| 
 | ||||
| using ratls::Greeter; | ||||
| using ratls::HelloReply; | ||||
| using ratls::HelloRequest; | ||||
| 
 | ||||
| struct argparser { | ||||
|     const char* config; | ||||
|     std::string server_address; | ||||
|     argparser() { | ||||
|         server_address = getarg("localhost:50051", "-host", "--host"); | ||||
|         config = getarg("dynamic_config.json", "-cfg", "--config"); | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| // Logic and data behind the server's behavior.
 | ||||
| class GreeterServiceImpl final : public Greeter::Service { | ||||
|     grpc::Status SayHello( | ||||
|         grpc::ServerContext* context, const HelloRequest* request, HelloReply* reply) override { | ||||
|         std::string prefix("Hello "); | ||||
|         reply->set_message(prefix + request->name()); | ||||
|         return grpc::Status::OK; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| void RunServer() { | ||||
|     argparser args; | ||||
| 
 | ||||
|     GreeterServiceImpl service; | ||||
| 
 | ||||
|     grpc::EnableDefaultHealthCheckService(true); | ||||
|     grpc::reflection::InitProtoReflectionServerBuilderPlugin(); | ||||
| 
 | ||||
|     grpc::ServerBuilder builder; | ||||
| 
 | ||||
|     auto creds = grpc::sgx::TlsServerCredentials(args.config); | ||||
|     GPR_ASSERT(creds.get() != nullptr); | ||||
| 
 | ||||
|     builder.AddListeningPort(args.server_address, creds); | ||||
| 
 | ||||
|     builder.RegisterService(&service); | ||||
| 
 | ||||
|     std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); | ||||
|     std::cout << "Server listening on " << args.server_address << std::endl; | ||||
| 
 | ||||
|     server->Wait(); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char** argv) { | ||||
|     RunServer(); | ||||
|     gr_start_server( | ||||
|         "localhost:50051", | ||||
|         "dynamic_config.json", | ||||
|         "secret_config.json" | ||||
|     ); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| @ -21,18 +21,18 @@ option objc_class_prefix = "HLW"; | ||||
| 
 | ||||
| package ratls; | ||||
| 
 | ||||
| // The greeting service definition. | ||||
| service Greeter { | ||||
| // The GRPC_RATLS secret service definition. | ||||
| service GrSecret { | ||||
|   // Sends a greeting | ||||
|   rpc SayHello (HelloRequest) returns (HelloReply) {} | ||||
|   rpc GetSecret (SecretRequest) returns (SecretReply) {} | ||||
| } | ||||
| 
 | ||||
| // The request message containing the user's name. | ||||
| message HelloRequest { | ||||
| // The request message containing the request's name. | ||||
| message SecretRequest { | ||||
|   string name = 1; | ||||
| } | ||||
| 
 | ||||
| // The response message containing the greetings | ||||
| message HelloReply { | ||||
|   string message = 1; | ||||
| // The response message containing the secret (base64 encoded string) | ||||
| message SecretReply { | ||||
|   string secret = 1; | ||||
| } | ||||
|  | ||||
| @ -24,6 +24,8 @@ | ||||
| #include <grpcpp/security/credentials.h> | ||||
| #include <grpcpp/security/server_credentials.h> | ||||
| 
 | ||||
| #include <cjson/cJSON.h> | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| @ -51,6 +53,30 @@ std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(const char* sgx_cf | ||||
| std::shared_ptr<grpc::Channel> CreateSecureChannel( | ||||
|     string target_str, std::shared_ptr<grpc::ChannelCredentials> channel_creds); | ||||
| 
 | ||||
| class json_engine { | ||||
|     public: | ||||
|         json_engine(); | ||||
| 
 | ||||
|         json_engine(const char*); | ||||
| 
 | ||||
|         ~json_engine(); | ||||
| 
 | ||||
|         bool open(const char*); | ||||
| 
 | ||||
|         void close(); | ||||
| 
 | ||||
|         cJSON* get_handle(); | ||||
| 
 | ||||
|         cJSON* get_item(cJSON* obj, const char* item); | ||||
| 
 | ||||
|         char* print_item(cJSON* obj); | ||||
| 
 | ||||
|         bool compare_item(cJSON* obj, const char* item); | ||||
| 
 | ||||
|     private: | ||||
|         cJSON* handle; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace sgx
 | ||||
| }  // namespace grpc
 | ||||
| 
 | ||||
|  | ||||
| @ -1,567 +0,0 @@ | ||||
| /*
 | ||||
|   Copyright (c) 2009 Dave Gamble | ||||
| 
 | ||||
|   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 Software without restriction, including without limitation the rights | ||||
|   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|   copies of the Software, and to permit persons to whom the Software is | ||||
|   furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
|   The above copyright notice and this permission notice shall be included in | ||||
|   all copies or substantial portions of the Software. | ||||
| 
 | ||||
|   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|   THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| /* cJSON */ | ||||
| /* JSON parser in C. */ | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #include <math.h> | ||||
| #include <stdlib.h> | ||||
| #include <float.h> | ||||
| #include <limits.h> | ||||
| #include <ctype.h> | ||||
| #include "cJSON.h" | ||||
| 
 | ||||
| static const char *ep; | ||||
| 
 | ||||
| const char *cJSON_GetErrorPtr(void) {return ep;} | ||||
| 
 | ||||
| static int cJSON_strcasecmp(const char *s1,const char *s2) | ||||
| { | ||||
| 	if (!s1) return (s1==s2)?0:1;if (!s2) return 1; | ||||
| 	for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)	if(*s1 == 0)	return 0; | ||||
| 	return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); | ||||
| } | ||||
| 
 | ||||
| static void *(*cJSON_malloc)(size_t sz) = malloc; | ||||
| static void (*cJSON_free)(void *ptr) = free; | ||||
| 
 | ||||
| static char* cJSON_strdup(const char* str) | ||||
| { | ||||
|       size_t len; | ||||
|       char* copy; | ||||
| 
 | ||||
|       len = strlen(str) + 1; | ||||
|       if (!(copy = (char*)cJSON_malloc(len))) return 0; | ||||
|       memcpy(copy,str,len); | ||||
|       return copy; | ||||
| } | ||||
| 
 | ||||
| void cJSON_InitHooks(cJSON_Hooks* hooks) | ||||
| { | ||||
|     if (!hooks) { /* Reset hooks */ | ||||
|         cJSON_malloc = malloc; | ||||
|         cJSON_free = free; | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
| 	cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; | ||||
| 	cJSON_free	 = (hooks->free_fn)?hooks->free_fn:free; | ||||
| } | ||||
| 
 | ||||
| /* Internal constructor. */ | ||||
| static cJSON *cJSON_New_Item(void) | ||||
| { | ||||
| 	cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); | ||||
| 	if (node) memset(node,0,sizeof(cJSON)); | ||||
| 	return node; | ||||
| } | ||||
| 
 | ||||
| /* Delete a cJSON structure. */ | ||||
| void cJSON_Delete(cJSON *c) | ||||
| { | ||||
| 	cJSON *next; | ||||
| 	while (c) | ||||
| 	{ | ||||
| 		next=c->next; | ||||
| 		if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); | ||||
| 		if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); | ||||
| 		if (c->string) cJSON_free(c->string); | ||||
| 		cJSON_free(c); | ||||
| 		c=next; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Parse the input text to generate a number, and populate the result into item. */ | ||||
| static const char *parse_number(cJSON *item,const char *num) | ||||
| { | ||||
| 	double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; | ||||
| 
 | ||||
| 	/* Could use sscanf for this? */ | ||||
| 	if (*num=='-') sign=-1,num++;	/* Has sign? */ | ||||
| 	if (*num=='0') num++;			/* is zero */ | ||||
| 	if (*num>='1' && *num<='9')	do	n=(n*10.0)+(*num++ -'0');	while (*num>='0' && *num<='9');	/* Number? */ | ||||
| 	if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;		do	n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}	/* Fractional part? */ | ||||
| 	if (*num=='e' || *num=='E')		/* Exponent? */ | ||||
| 	{	num++;if (*num=='+') num++;	else if (*num=='-') signsubscale=-1,num++;		/* With sign? */ | ||||
| 		while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');	/* Number? */ | ||||
| 	} | ||||
| 
 | ||||
| 	n=sign*n*pow(10.0,(scale+subscale*signsubscale));	/* number = +/- number.fraction * 10^+/- exponent */ | ||||
| 	 | ||||
| 	item->valuedouble=n; | ||||
| 	item->valueint=(int)n; | ||||
| 	item->type=cJSON_Number; | ||||
| 	return num; | ||||
| } | ||||
| 
 | ||||
| /* Render the number nicely from the given item into a string. */ | ||||
| static char *print_number(cJSON *item) | ||||
| { | ||||
| 	char *str; | ||||
| 	double d=item->valuedouble; | ||||
| 	if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) | ||||
| 	{ | ||||
| 		str=(char*)cJSON_malloc(21);	/* 2^64+1 can be represented in 21 chars. */ | ||||
| 		if (str) sprintf(str,"%d",item->valueint); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		str=(char*)cJSON_malloc(64);	/* This is a nice tradeoff. */ | ||||
| 		if (str) | ||||
| 		{ | ||||
| 			if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); | ||||
| 			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)			sprintf(str,"%e",d); | ||||
| 			else												sprintf(str,"%f",d); | ||||
| 		} | ||||
| 	} | ||||
| 	return str; | ||||
| } | ||||
| 
 | ||||
| /* Parse the input text into an unescaped cstring, and populate item. */ | ||||
| static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; | ||||
| static const char *parse_string(cJSON *item,const char *str) | ||||
| { | ||||
| 	const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; | ||||
| 	if (*str!='\"') {ep=str;return 0;}	/* not a string! */ | ||||
| 	 | ||||
| 	while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;	/* Skip escaped quotes. */ | ||||
| 	 | ||||
| 	out=(char*)cJSON_malloc(len+1);	/* This is how long we need for the string, roughly. */ | ||||
| 	if (!out) return 0; | ||||
| 	 | ||||
| 	ptr=str+1;ptr2=out; | ||||
| 	while (*ptr!='\"' && *ptr) | ||||
| 	{ | ||||
| 		if (*ptr!='\\') *ptr2++=*ptr++; | ||||
| 		else | ||||
| 		{ | ||||
| 			ptr++; | ||||
| 			switch (*ptr) | ||||
| 			{ | ||||
| 				case 'b': *ptr2++='\b';	break; | ||||
| 				case 'f': *ptr2++='\f';	break; | ||||
| 				case 'n': *ptr2++='\n';	break; | ||||
| 				case 'r': *ptr2++='\r';	break; | ||||
| 				case 't': *ptr2++='\t';	break; | ||||
| 				case 'u':	 /* transcode utf16 to utf8. */ | ||||
| 					sscanf(ptr+1,"%4x",&uc);ptr+=4;	/* get the unicode char. */ | ||||
| 
 | ||||
| 					if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)	break;	/* check for invalid.	*/ | ||||
| 
 | ||||
| 					if (uc>=0xD800 && uc<=0xDBFF)	/* UTF16 surrogate pairs.	*/ | ||||
| 					{ | ||||
| 						if (ptr[1]!='\\' || ptr[2]!='u')	break;	/* missing second-half of surrogate.	*/ | ||||
| 						sscanf(ptr+3,"%4x",&uc2);ptr+=6; | ||||
| 						if (uc2<0xDC00 || uc2>0xDFFF)		break;	/* invalid second-half of surrogate.	*/ | ||||
| 						uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); | ||||
| 					} | ||||
| 
 | ||||
| 					len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; | ||||
| 					 | ||||
| 					switch (len) { | ||||
| 						case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | ||||
| 						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | ||||
| 						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | ||||
| 						case 1: *--ptr2 =(uc | firstByteMark[len]); | ||||
| 					} | ||||
| 					ptr2+=len; | ||||
| 					break; | ||||
| 				default:  *ptr2++=*ptr; break; | ||||
| 			} | ||||
| 			ptr++; | ||||
| 		} | ||||
| 	} | ||||
| 	*ptr2=0; | ||||
| 	if (*ptr=='\"') ptr++; | ||||
| 	item->valuestring=out; | ||||
| 	item->type=cJSON_String; | ||||
| 	return ptr; | ||||
| } | ||||
| 
 | ||||
| /* Render the cstring provided to an escaped version that can be printed. */ | ||||
| static char *print_string_ptr(const char *str) | ||||
| { | ||||
| 	const char *ptr;char *ptr2,*out;int len=0;unsigned char token; | ||||
| 	 | ||||
| 	if (!str) return cJSON_strdup(""); | ||||
| 	ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} | ||||
| 	 | ||||
| 	out=(char*)cJSON_malloc(len+3); | ||||
| 	if (!out) return 0; | ||||
| 
 | ||||
| 	ptr2=out;ptr=str; | ||||
| 	*ptr2++='\"'; | ||||
| 	while (*ptr) | ||||
| 	{ | ||||
| 		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; | ||||
| 		else | ||||
| 		{ | ||||
| 			*ptr2++='\\'; | ||||
| 			switch (token=*ptr++) | ||||
| 			{ | ||||
| 				case '\\':	*ptr2++='\\';	break; | ||||
| 				case '\"':	*ptr2++='\"';	break; | ||||
| 				case '\b':	*ptr2++='b';	break; | ||||
| 				case '\f':	*ptr2++='f';	break; | ||||
| 				case '\n':	*ptr2++='n';	break; | ||||
| 				case '\r':	*ptr2++='r';	break; | ||||
| 				case '\t':	*ptr2++='t';	break; | ||||
| 				default: sprintf(ptr2,"u%04x",token);ptr2+=5;	break;	/* escape and print */ | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	*ptr2++='\"';*ptr2++=0; | ||||
| 	return out; | ||||
| } | ||||
| /* Invote print_string_ptr (which is useful) on an item. */ | ||||
| static char *print_string(cJSON *item)	{return print_string_ptr(item->valuestring);} | ||||
| 
 | ||||
| /* Predeclare these prototypes. */ | ||||
| static const char *parse_value(cJSON *item,const char *value); | ||||
| static char *print_value(cJSON *item,int depth,int fmt); | ||||
| static const char *parse_array(cJSON *item,const char *value); | ||||
| static char *print_array(cJSON *item,int depth,int fmt); | ||||
| static const char *parse_object(cJSON *item,const char *value); | ||||
| static char *print_object(cJSON *item,int depth,int fmt); | ||||
| 
 | ||||
| /* Utility to jump whitespace and cr/lf */ | ||||
| static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} | ||||
| 
 | ||||
| /* Parse an object - create a new root, and populate. */ | ||||
| cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) | ||||
| { | ||||
| 	const char *end=0; | ||||
| 	cJSON *c=cJSON_New_Item(); | ||||
| 	ep=0; | ||||
| 	if (!c) return 0;       /* memory fail */ | ||||
| 
 | ||||
| 	end=parse_value(c,skip(value)); | ||||
| 	if (!end)	{cJSON_Delete(c);return 0;}	/* parse failure. ep is set. */ | ||||
| 
 | ||||
| 	/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ | ||||
| 	if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} | ||||
| 	if (return_parse_end) *return_parse_end=end; | ||||
| 	return c; | ||||
| } | ||||
| /* Default options for cJSON_Parse */ | ||||
| cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} | ||||
| 
 | ||||
| /* Render a cJSON item/entity/structure to text. */ | ||||
| char *cJSON_Print(cJSON *item)				{return print_value(item,0,1);} | ||||
| char *cJSON_PrintUnformatted(cJSON *item)	{return print_value(item,0,0);} | ||||
| 
 | ||||
| /* Parser core - when encountering text, process appropriately. */ | ||||
| static const char *parse_value(cJSON *item,const char *value) | ||||
| { | ||||
| 	if (!value)						return 0;	/* Fail on null. */ | ||||
| 	if (!strncmp(value,"null",4))	{ item->type=cJSON_NULL;  return value+4; } | ||||
| 	if (!strncmp(value,"false",5))	{ item->type=cJSON_False; return value+5; } | ||||
| 	if (!strncmp(value,"true",4))	{ item->type=cJSON_True; item->valueint=1;	return value+4; } | ||||
| 	if (*value=='\"')				{ return parse_string(item,value); } | ||||
| 	if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(item,value); } | ||||
| 	if (*value=='[')				{ return parse_array(item,value); } | ||||
| 	if (*value=='{')				{ return parse_object(item,value); } | ||||
| 
 | ||||
| 	ep=value;return 0;	/* failure. */ | ||||
| } | ||||
| 
 | ||||
| /* Render a value to text. */ | ||||
| static char *print_value(cJSON *item,int depth,int fmt) | ||||
| { | ||||
| 	char *out=0; | ||||
| 	if (!item) return 0; | ||||
| 	switch ((item->type)&255) | ||||
| 	{ | ||||
| 		case cJSON_NULL:	out=cJSON_strdup("null");	break; | ||||
| 		case cJSON_False:	out=cJSON_strdup("false");break; | ||||
| 		case cJSON_True:	out=cJSON_strdup("true"); break; | ||||
| 		case cJSON_Number:	out=print_number(item);break; | ||||
| 		case cJSON_String:	out=print_string(item);break; | ||||
| 		case cJSON_Array:	out=print_array(item,depth,fmt);break; | ||||
| 		case cJSON_Object:	out=print_object(item,depth,fmt);break; | ||||
| 	} | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| /* Build an array from input text. */ | ||||
| static const char *parse_array(cJSON *item,const char *value) | ||||
| { | ||||
| 	cJSON *child; | ||||
| 	if (*value!='[')	{ep=value;return 0;}	/* not an array! */ | ||||
| 
 | ||||
| 	item->type=cJSON_Array; | ||||
| 	value=skip(value+1); | ||||
| 	if (*value==']') return value+1;	/* empty array. */ | ||||
| 
 | ||||
| 	item->child=child=cJSON_New_Item(); | ||||
| 	if (!item->child) return 0;		 /* memory fail */ | ||||
| 	value=skip(parse_value(child,skip(value)));	/* skip any spacing, get the value. */ | ||||
| 	if (!value) return 0; | ||||
| 
 | ||||
| 	while (*value==',') | ||||
| 	{ | ||||
| 		cJSON *new_item; | ||||
| 		if (!(new_item=cJSON_New_Item())) return 0; 	/* memory fail */ | ||||
| 		child->next=new_item;new_item->prev=child;child=new_item; | ||||
| 		value=skip(parse_value(child,skip(value+1))); | ||||
| 		if (!value) return 0;	/* memory fail */ | ||||
| 	} | ||||
| 
 | ||||
| 	if (*value==']') return value+1;	/* end of array */ | ||||
| 	ep=value;return 0;	/* malformed. */ | ||||
| } | ||||
| 
 | ||||
| /* Render an array to text */ | ||||
| static char *print_array(cJSON *item,int depth,int fmt) | ||||
| { | ||||
| 	char **entries; | ||||
| 	char *out=0,*ptr,*ret;int len=5; | ||||
| 	cJSON *child=item->child; | ||||
| 	int numentries=0,i=0,fail=0; | ||||
| 	 | ||||
| 	/* How many entries in the array? */ | ||||
| 	while (child) numentries++,child=child->next; | ||||
| 	/* Explicitly handle numentries==0 */ | ||||
| 	if (!numentries) | ||||
| 	{ | ||||
| 		out=(char*)cJSON_malloc(3); | ||||
| 		if (out) strcpy(out,"[]"); | ||||
| 		return out; | ||||
| 	} | ||||
| 	/* Allocate an array to hold the values for each */ | ||||
| 	entries=(char**)cJSON_malloc(numentries*sizeof(char*)); | ||||
| 	if (!entries) return 0; | ||||
| 	memset(entries,0,numentries*sizeof(char*)); | ||||
| 	/* Retrieve all the results: */ | ||||
| 	child=item->child; | ||||
| 	while (child && !fail) | ||||
| 	{ | ||||
| 		ret=print_value(child,depth+1,fmt); | ||||
| 		entries[i++]=ret; | ||||
| 		if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; | ||||
| 		child=child->next; | ||||
| 	} | ||||
| 	 | ||||
| 	/* If we didn't fail, try to malloc the output string */ | ||||
| 	if (!fail) out=(char*)cJSON_malloc(len); | ||||
| 	/* If that fails, we fail. */ | ||||
| 	if (!out) fail=1; | ||||
| 
 | ||||
| 	/* Handle failure. */ | ||||
| 	if (fail) | ||||
| 	{ | ||||
| 		for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]); | ||||
| 		cJSON_free(entries); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Compose the output array. */ | ||||
| 	*out='['; | ||||
| 	ptr=out+1;*ptr=0; | ||||
| 	for (i=0;i<numentries;i++) | ||||
| 	{ | ||||
| 		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); | ||||
| 		if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;} | ||||
| 		cJSON_free(entries[i]); | ||||
| 	} | ||||
| 	cJSON_free(entries); | ||||
| 	*ptr++=']';*ptr++=0; | ||||
| 	return out;	 | ||||
| } | ||||
| 
 | ||||
| /* Build an object from the text. */ | ||||
| static const char *parse_object(cJSON *item,const char *value) | ||||
| { | ||||
| 	cJSON *child; | ||||
| 	if (*value!='{')	{ep=value;return 0;}	/* not an object! */ | ||||
| 	 | ||||
| 	item->type=cJSON_Object; | ||||
| 	value=skip(value+1); | ||||
| 	if (*value=='}') return value+1;	/* empty array. */ | ||||
| 	 | ||||
| 	item->child=child=cJSON_New_Item(); | ||||
| 	if (!item->child) return 0; | ||||
| 	value=skip(parse_string(child,skip(value))); | ||||
| 	if (!value) return 0; | ||||
| 	child->string=child->valuestring;child->valuestring=0; | ||||
| 	if (*value!=':') {ep=value;return 0;}	/* fail! */ | ||||
| 	value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */ | ||||
| 	if (!value) return 0; | ||||
| 	 | ||||
| 	while (*value==',') | ||||
| 	{ | ||||
| 		cJSON *new_item; | ||||
| 		if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */ | ||||
| 		child->next=new_item;new_item->prev=child;child=new_item; | ||||
| 		value=skip(parse_string(child,skip(value+1))); | ||||
| 		if (!value) return 0; | ||||
| 		child->string=child->valuestring;child->valuestring=0; | ||||
| 		if (*value!=':') {ep=value;return 0;}	/* fail! */ | ||||
| 		value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */ | ||||
| 		if (!value) return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	if (*value=='}') return value+1;	/* end of array */ | ||||
| 	ep=value;return 0;	/* malformed. */ | ||||
| } | ||||
| 
 | ||||
| /* Render an object to text. */ | ||||
| static char *print_object(cJSON *item,int depth,int fmt) | ||||
| { | ||||
| 	char **entries=0,**names=0; | ||||
| 	char *out=0,*ptr,*ret,*str;int len=7,i=0,j; | ||||
| 	cJSON *child=item->child; | ||||
| 	int numentries=0,fail=0; | ||||
| 	/* Count the number of entries. */ | ||||
| 	while (child) numentries++,child=child->next; | ||||
| 	/* Explicitly handle empty object case */ | ||||
| 	if (!numentries) | ||||
| 	{ | ||||
| 		out=(char*)cJSON_malloc(fmt?depth+3:3); | ||||
| 		if (!out)	return 0; | ||||
| 		ptr=out;*ptr++='{'; | ||||
| 		if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';} | ||||
| 		*ptr++='}';*ptr++=0; | ||||
| 		return out; | ||||
| 	} | ||||
| 	/* Allocate space for the names and the objects */ | ||||
| 	entries=(char**)cJSON_malloc(numentries*sizeof(char*)); | ||||
| 	if (!entries) return 0; | ||||
| 	names=(char**)cJSON_malloc(numentries*sizeof(char*)); | ||||
| 	if (!names) {cJSON_free(entries);return 0;} | ||||
| 	memset(entries,0,sizeof(char*)*numentries); | ||||
| 	memset(names,0,sizeof(char*)*numentries); | ||||
| 
 | ||||
| 	/* Collect all the results into our arrays: */ | ||||
| 	child=item->child;depth++;if (fmt) len+=depth; | ||||
| 	while (child) | ||||
| 	{ | ||||
| 		names[i]=str=print_string_ptr(child->string); | ||||
| 		entries[i++]=ret=print_value(child,depth,fmt); | ||||
| 		if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; | ||||
| 		child=child->next; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Try to allocate the output string */ | ||||
| 	if (!fail) out=(char*)cJSON_malloc(len); | ||||
| 	if (!out) fail=1; | ||||
| 
 | ||||
| 	/* Handle failure */ | ||||
| 	if (fail) | ||||
| 	{ | ||||
| 		for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);} | ||||
| 		cJSON_free(names);cJSON_free(entries); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Compose the output: */ | ||||
| 	*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0; | ||||
| 	for (i=0;i<numentries;i++) | ||||
| 	{ | ||||
| 		if (fmt) for (j=0;j<depth;j++) *ptr++='\t'; | ||||
| 		strcpy(ptr,names[i]);ptr+=strlen(names[i]); | ||||
| 		*ptr++=':';if (fmt) *ptr++='\t'; | ||||
| 		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); | ||||
| 		if (i!=numentries-1) *ptr++=','; | ||||
| 		if (fmt) *ptr++='\n';*ptr=0; | ||||
| 		cJSON_free(names[i]);cJSON_free(entries[i]); | ||||
| 	} | ||||
| 	 | ||||
| 	cJSON_free(names);cJSON_free(entries); | ||||
| 	if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t'; | ||||
| 	*ptr++='}';*ptr++=0; | ||||
| 	return out;	 | ||||
| } | ||||
| 
 | ||||
| /* Get Array size/item / object item. */ | ||||
| int    cJSON_GetArraySize(cJSON *array)							{cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;} | ||||
| cJSON *cJSON_GetArrayItem(cJSON *array,int item)				{cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;} | ||||
| cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	{cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} | ||||
| 
 | ||||
| /* Utility for array list handling. */ | ||||
| static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} | ||||
| /* Utility for handling references. */ | ||||
| static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} | ||||
| 
 | ||||
| /* Add item to array/object. */ | ||||
| void   cJSON_AddItemToArray(cJSON *array, cJSON *item)						{cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} | ||||
| void   cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} | ||||
| void	cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)						{cJSON_AddItemToArray(array,create_reference(item));} | ||||
| void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)	{cJSON_AddItemToObject(object,string,create_reference(item));} | ||||
| 
 | ||||
| cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)			{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; | ||||
| 	if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} | ||||
| void   cJSON_DeleteItemFromArray(cJSON *array,int which)			{cJSON_Delete(cJSON_DetachItemFromArray(array,which));} | ||||
| cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} | ||||
| void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} | ||||
| 
 | ||||
| /* Replace array/object items with new ones. */ | ||||
| void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; | ||||
| 	newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; | ||||
| 	if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} | ||||
| void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} | ||||
| 
 | ||||
| /* Create basic types: */ | ||||
| cJSON *cJSON_CreateNull(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} | ||||
| cJSON *cJSON_CreateTrue(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} | ||||
| cJSON *cJSON_CreateFalse(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} | ||||
| cJSON *cJSON_CreateBool(int b)					{cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} | ||||
| cJSON *cJSON_CreateNumber(double num)			{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} | ||||
| cJSON *cJSON_CreateString(const char *string)	{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} | ||||
| cJSON *cJSON_CreateArray(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} | ||||
| cJSON *cJSON_CreateObject(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} | ||||
| 
 | ||||
| /* Create Arrays: */ | ||||
| cJSON *cJSON_CreateIntArray(int *numbers,int count)				{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| cJSON *cJSON_CreateFloatArray(float *numbers,int count)			{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| cJSON *cJSON_CreateDoubleArray(double *numbers,int count)		{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| cJSON *cJSON_CreateStringArray(const char **strings,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| 
 | ||||
| /* Duplication */ | ||||
| cJSON *cJSON_Duplicate(cJSON *item,int recurse) | ||||
| { | ||||
| 	cJSON *newitem,*cptr,*nptr=0,*newchild; | ||||
| 	/* Bail on bad ptr */ | ||||
| 	if (!item) return 0; | ||||
| 	/* Create new item */ | ||||
| 	newitem=cJSON_New_Item(); | ||||
| 	if (!newitem) return 0; | ||||
| 	/* Copy over all vars */ | ||||
| 	newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; | ||||
| 	if (item->valuestring)	{newitem->valuestring=cJSON_strdup(item->valuestring);	if (!newitem->valuestring)	{cJSON_Delete(newitem);return 0;}} | ||||
| 	if (item->string)		{newitem->string=cJSON_strdup(item->string);			if (!newitem->string)		{cJSON_Delete(newitem);return 0;}} | ||||
| 	/* If non-recursive, then we're done! */ | ||||
| 	if (!recurse) return newitem; | ||||
| 	/* Walk the ->next chain for the child. */ | ||||
| 	cptr=item->child; | ||||
| 	while (cptr) | ||||
| 	{ | ||||
| 		newchild=cJSON_Duplicate(cptr,1);		/* Duplicate (with recurse) each item in the ->next chain */ | ||||
| 		if (!newchild) {cJSON_Delete(newitem);return 0;} | ||||
| 		if (nptr)	{nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}	/* If newitem->child already set, then crosswire ->prev and ->next and move on */ | ||||
| 		else		{newitem->child=newchild;nptr=newchild;}					/* Set newitem->child and move to it */ | ||||
| 		cptr=cptr->next; | ||||
| 	} | ||||
| 	return newitem; | ||||
| } | ||||
| @ -1,140 +0,0 @@ | ||||
| /*
 | ||||
|   Copyright (c) 2009 Dave Gamble | ||||
|   | ||||
|   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 Software without restriction, including without limitation the rights | ||||
|   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|   copies of the Software, and to permit persons to whom the Software is | ||||
|   furnished to do so, subject to the following conditions: | ||||
|   | ||||
|   The above copyright notice and this permission notice shall be included in | ||||
|   all copies or substantial portions of the Software. | ||||
|   | ||||
|   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|   THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef cJSON__h | ||||
| #define cJSON__h | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
| #include <stdio.h> | ||||
| /* cJSON Types: */ | ||||
| #define cJSON_False 0 | ||||
| #define cJSON_True 1 | ||||
| #define cJSON_NULL 2 | ||||
| #define cJSON_Number 3 | ||||
| #define cJSON_String 4 | ||||
| #define cJSON_Array 5 | ||||
| #define cJSON_Object 6 | ||||
| 	 | ||||
| #define cJSON_IsReference 256 | ||||
| 
 | ||||
| /* The cJSON structure: */ | ||||
| typedef struct cJSON { | ||||
| 	struct cJSON *next,*prev;	/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ | ||||
| 	struct cJSON *child;		/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ | ||||
| 
 | ||||
| 	int type;					/* The type of the item, as above. */ | ||||
| 
 | ||||
| 	char *valuestring;			/* The item's string, if type==cJSON_String */ | ||||
| 	int valueint;				/* The item's number, if type==cJSON_Number */ | ||||
| 	double valuedouble;			/* The item's number, if type==cJSON_Number */ | ||||
| 
 | ||||
| 	char *string;				/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ | ||||
| } cJSON; | ||||
| 
 | ||||
| typedef struct cJSON_Hooks { | ||||
|       void *(*malloc_fn)(size_t sz); | ||||
|       void (*free_fn)(void *ptr); | ||||
| } cJSON_Hooks; | ||||
| 
 | ||||
| /* Supply malloc, realloc and free functions to cJSON */ | ||||
| extern void cJSON_InitHooks(cJSON_Hooks* hooks); | ||||
| 
 | ||||
| 
 | ||||
| /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ | ||||
| extern cJSON *cJSON_Parse(const char *value); | ||||
| /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ | ||||
| extern char  *cJSON_Print(cJSON *item); | ||||
| /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ | ||||
| extern char  *cJSON_PrintUnformatted(cJSON *item); | ||||
| /* Delete a cJSON entity and all subentities. */ | ||||
| extern void   cJSON_Delete(cJSON *c); | ||||
| 
 | ||||
| /* Returns the number of items in an array (or object). */ | ||||
| extern int	  cJSON_GetArraySize(cJSON *array); | ||||
| /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ | ||||
| extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); | ||||
| /* Get item "string" from object. Case insensitive. */ | ||||
| extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); | ||||
| 
 | ||||
| /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ | ||||
| extern const char *cJSON_GetErrorPtr(void); | ||||
| 	 | ||||
| /* These calls create a cJSON item of the appropriate type. */ | ||||
| extern cJSON *cJSON_CreateNull(void); | ||||
| extern cJSON *cJSON_CreateTrue(void); | ||||
| extern cJSON *cJSON_CreateFalse(void); | ||||
| extern cJSON *cJSON_CreateBool(int b); | ||||
| extern cJSON *cJSON_CreateNumber(double num); | ||||
| extern cJSON *cJSON_CreateString(const char *string); | ||||
| extern cJSON *cJSON_CreateArray(void); | ||||
| extern cJSON *cJSON_CreateObject(void); | ||||
| 
 | ||||
| /* These utilities create an Array of count items. */ | ||||
| extern cJSON *cJSON_CreateIntArray(int *numbers,int count); | ||||
| extern cJSON *cJSON_CreateFloatArray(float *numbers,int count); | ||||
| extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); | ||||
| extern cJSON *cJSON_CreateStringArray(const char **strings,int count); | ||||
| 
 | ||||
| /* Append item to the specified array/object. */ | ||||
| extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); | ||||
| extern void	cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); | ||||
| /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ | ||||
| extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); | ||||
| extern void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); | ||||
| 
 | ||||
| /* Remove/Detatch items from Arrays/Objects. */ | ||||
| extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); | ||||
| extern void   cJSON_DeleteItemFromArray(cJSON *array,int which); | ||||
| extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); | ||||
| extern void   cJSON_DeleteItemFromObject(cJSON *object,const char *string); | ||||
| 	 | ||||
| /* Update array items. */ | ||||
| extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); | ||||
| extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); | ||||
| 
 | ||||
| /* Duplicate a cJSON item */ | ||||
| extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); | ||||
| /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
 | ||||
| need to be released. With recurse!=0, it will duplicate any children connected to the item. | ||||
| The item->next and ->prev pointers are always zero on return from Duplicate. */ | ||||
| 
 | ||||
| /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ | ||||
| extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); | ||||
| 
 | ||||
| /* Macros for creating things quickly. */ | ||||
| #define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull()) | ||||
| #define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) | ||||
| #define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) | ||||
| #define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) | ||||
| #define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) | ||||
| #define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) | ||||
| 
 | ||||
| /* When assigning an integer value, it needs to be propagated to valuedouble too. */ | ||||
| #define cJSON_SetIntValue(object,val)			((object)?(object)->valueint=(object)->valuedouble=(val):(val)) | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
| @ -1,567 +0,0 @@ | ||||
| /*
 | ||||
|   Copyright (c) 2009 Dave Gamble | ||||
| 
 | ||||
|   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 Software without restriction, including without limitation the rights | ||||
|   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|   copies of the Software, and to permit persons to whom the Software is | ||||
|   furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
|   The above copyright notice and this permission notice shall be included in | ||||
|   all copies or substantial portions of the Software. | ||||
| 
 | ||||
|   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|   THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| /* cJSON */ | ||||
| /* JSON parser in C. */ | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #include <math.h> | ||||
| #include <stdlib.h> | ||||
| #include <float.h> | ||||
| #include <limits.h> | ||||
| #include <ctype.h> | ||||
| #include "cJSON.h" | ||||
| 
 | ||||
| static const char *ep; | ||||
| 
 | ||||
| const char *cJSON_GetErrorPtr(void) {return ep;} | ||||
| 
 | ||||
| static int cJSON_strcasecmp(const char *s1,const char *s2) | ||||
| { | ||||
| 	if (!s1) return (s1==s2)?0:1;if (!s2) return 1; | ||||
| 	for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)	if(*s1 == 0)	return 0; | ||||
| 	return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); | ||||
| } | ||||
| 
 | ||||
| static void *(*cJSON_malloc)(size_t sz) = malloc; | ||||
| static void (*cJSON_free)(void *ptr) = free; | ||||
| 
 | ||||
| static char* cJSON_strdup(const char* str) | ||||
| { | ||||
|       size_t len; | ||||
|       char* copy; | ||||
| 
 | ||||
|       len = strlen(str) + 1; | ||||
|       if (!(copy = (char*)cJSON_malloc(len))) return 0; | ||||
|       memcpy(copy,str,len); | ||||
|       return copy; | ||||
| } | ||||
| 
 | ||||
| void cJSON_InitHooks(cJSON_Hooks* hooks) | ||||
| { | ||||
|     if (!hooks) { /* Reset hooks */ | ||||
|         cJSON_malloc = malloc; | ||||
|         cJSON_free = free; | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
| 	cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; | ||||
| 	cJSON_free	 = (hooks->free_fn)?hooks->free_fn:free; | ||||
| } | ||||
| 
 | ||||
| /* Internal constructor. */ | ||||
| static cJSON *cJSON_New_Item(void) | ||||
| { | ||||
| 	cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); | ||||
| 	if (node) memset(node,0,sizeof(cJSON)); | ||||
| 	return node; | ||||
| } | ||||
| 
 | ||||
| /* Delete a cJSON structure. */ | ||||
| void cJSON_Delete(cJSON *c) | ||||
| { | ||||
| 	cJSON *next; | ||||
| 	while (c) | ||||
| 	{ | ||||
| 		next=c->next; | ||||
| 		if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); | ||||
| 		if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); | ||||
| 		if (c->string) cJSON_free(c->string); | ||||
| 		cJSON_free(c); | ||||
| 		c=next; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Parse the input text to generate a number, and populate the result into item. */ | ||||
| static const char *parse_number(cJSON *item,const char *num) | ||||
| { | ||||
| 	double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; | ||||
| 
 | ||||
| 	/* Could use sscanf for this? */ | ||||
| 	if (*num=='-') sign=-1,num++;	/* Has sign? */ | ||||
| 	if (*num=='0') num++;			/* is zero */ | ||||
| 	if (*num>='1' && *num<='9')	do	n=(n*10.0)+(*num++ -'0');	while (*num>='0' && *num<='9');	/* Number? */ | ||||
| 	if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;		do	n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}	/* Fractional part? */ | ||||
| 	if (*num=='e' || *num=='E')		/* Exponent? */ | ||||
| 	{	num++;if (*num=='+') num++;	else if (*num=='-') signsubscale=-1,num++;		/* With sign? */ | ||||
| 		while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');	/* Number? */ | ||||
| 	} | ||||
| 
 | ||||
| 	n=sign*n*pow(10.0,(scale+subscale*signsubscale));	/* number = +/- number.fraction * 10^+/- exponent */ | ||||
| 	 | ||||
| 	item->valuedouble=n; | ||||
| 	item->valueint=(int)n; | ||||
| 	item->type=cJSON_Number; | ||||
| 	return num; | ||||
| } | ||||
| 
 | ||||
| /* Render the number nicely from the given item into a string. */ | ||||
| static char *print_number(cJSON *item) | ||||
| { | ||||
| 	char *str; | ||||
| 	double d=item->valuedouble; | ||||
| 	if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) | ||||
| 	{ | ||||
| 		str=(char*)cJSON_malloc(21);	/* 2^64+1 can be represented in 21 chars. */ | ||||
| 		if (str) sprintf(str,"%d",item->valueint); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		str=(char*)cJSON_malloc(64);	/* This is a nice tradeoff. */ | ||||
| 		if (str) | ||||
| 		{ | ||||
| 			if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); | ||||
| 			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)			sprintf(str,"%e",d); | ||||
| 			else												sprintf(str,"%f",d); | ||||
| 		} | ||||
| 	} | ||||
| 	return str; | ||||
| } | ||||
| 
 | ||||
| /* Parse the input text into an unescaped cstring, and populate item. */ | ||||
| static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; | ||||
| static const char *parse_string(cJSON *item,const char *str) | ||||
| { | ||||
| 	const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; | ||||
| 	if (*str!='\"') {ep=str;return 0;}	/* not a string! */ | ||||
| 	 | ||||
| 	while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;	/* Skip escaped quotes. */ | ||||
| 	 | ||||
| 	out=(char*)cJSON_malloc(len+1);	/* This is how long we need for the string, roughly. */ | ||||
| 	if (!out) return 0; | ||||
| 	 | ||||
| 	ptr=str+1;ptr2=out; | ||||
| 	while (*ptr!='\"' && *ptr) | ||||
| 	{ | ||||
| 		if (*ptr!='\\') *ptr2++=*ptr++; | ||||
| 		else | ||||
| 		{ | ||||
| 			ptr++; | ||||
| 			switch (*ptr) | ||||
| 			{ | ||||
| 				case 'b': *ptr2++='\b';	break; | ||||
| 				case 'f': *ptr2++='\f';	break; | ||||
| 				case 'n': *ptr2++='\n';	break; | ||||
| 				case 'r': *ptr2++='\r';	break; | ||||
| 				case 't': *ptr2++='\t';	break; | ||||
| 				case 'u':	 /* transcode utf16 to utf8. */ | ||||
| 					sscanf(ptr+1,"%4x",&uc);ptr+=4;	/* get the unicode char. */ | ||||
| 
 | ||||
| 					if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)	break;	/* check for invalid.	*/ | ||||
| 
 | ||||
| 					if (uc>=0xD800 && uc<=0xDBFF)	/* UTF16 surrogate pairs.	*/ | ||||
| 					{ | ||||
| 						if (ptr[1]!='\\' || ptr[2]!='u')	break;	/* missing second-half of surrogate.	*/ | ||||
| 						sscanf(ptr+3,"%4x",&uc2);ptr+=6; | ||||
| 						if (uc2<0xDC00 || uc2>0xDFFF)		break;	/* invalid second-half of surrogate.	*/ | ||||
| 						uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); | ||||
| 					} | ||||
| 
 | ||||
| 					len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; | ||||
| 					 | ||||
| 					switch (len) { | ||||
| 						case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | ||||
| 						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | ||||
| 						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; | ||||
| 						case 1: *--ptr2 =(uc | firstByteMark[len]); | ||||
| 					} | ||||
| 					ptr2+=len; | ||||
| 					break; | ||||
| 				default:  *ptr2++=*ptr; break; | ||||
| 			} | ||||
| 			ptr++; | ||||
| 		} | ||||
| 	} | ||||
| 	*ptr2=0; | ||||
| 	if (*ptr=='\"') ptr++; | ||||
| 	item->valuestring=out; | ||||
| 	item->type=cJSON_String; | ||||
| 	return ptr; | ||||
| } | ||||
| 
 | ||||
| /* Render the cstring provided to an escaped version that can be printed. */ | ||||
| static char *print_string_ptr(const char *str) | ||||
| { | ||||
| 	const char *ptr;char *ptr2,*out;int len=0;unsigned char token; | ||||
| 	 | ||||
| 	if (!str) return cJSON_strdup(""); | ||||
| 	ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} | ||||
| 	 | ||||
| 	out=(char*)cJSON_malloc(len+3); | ||||
| 	if (!out) return 0; | ||||
| 
 | ||||
| 	ptr2=out;ptr=str; | ||||
| 	*ptr2++='\"'; | ||||
| 	while (*ptr) | ||||
| 	{ | ||||
| 		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; | ||||
| 		else | ||||
| 		{ | ||||
| 			*ptr2++='\\'; | ||||
| 			switch (token=*ptr++) | ||||
| 			{ | ||||
| 				case '\\':	*ptr2++='\\';	break; | ||||
| 				case '\"':	*ptr2++='\"';	break; | ||||
| 				case '\b':	*ptr2++='b';	break; | ||||
| 				case '\f':	*ptr2++='f';	break; | ||||
| 				case '\n':	*ptr2++='n';	break; | ||||
| 				case '\r':	*ptr2++='r';	break; | ||||
| 				case '\t':	*ptr2++='t';	break; | ||||
| 				default: sprintf(ptr2,"u%04x",token);ptr2+=5;	break;	/* escape and print */ | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	*ptr2++='\"';*ptr2++=0; | ||||
| 	return out; | ||||
| } | ||||
| /* Invote print_string_ptr (which is useful) on an item. */ | ||||
| static char *print_string(cJSON *item)	{return print_string_ptr(item->valuestring);} | ||||
| 
 | ||||
| /* Predeclare these prototypes. */ | ||||
| static const char *parse_value(cJSON *item,const char *value); | ||||
| static char *print_value(cJSON *item,int depth,int fmt); | ||||
| static const char *parse_array(cJSON *item,const char *value); | ||||
| static char *print_array(cJSON *item,int depth,int fmt); | ||||
| static const char *parse_object(cJSON *item,const char *value); | ||||
| static char *print_object(cJSON *item,int depth,int fmt); | ||||
| 
 | ||||
| /* Utility to jump whitespace and cr/lf */ | ||||
| static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} | ||||
| 
 | ||||
| /* Parse an object - create a new root, and populate. */ | ||||
| cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) | ||||
| { | ||||
| 	const char *end=0; | ||||
| 	cJSON *c=cJSON_New_Item(); | ||||
| 	ep=0; | ||||
| 	if (!c) return 0;       /* memory fail */ | ||||
| 
 | ||||
| 	end=parse_value(c,skip(value)); | ||||
| 	if (!end)	{cJSON_Delete(c);return 0;}	/* parse failure. ep is set. */ | ||||
| 
 | ||||
| 	/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ | ||||
| 	if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} | ||||
| 	if (return_parse_end) *return_parse_end=end; | ||||
| 	return c; | ||||
| } | ||||
| /* Default options for cJSON_Parse */ | ||||
| cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} | ||||
| 
 | ||||
| /* Render a cJSON item/entity/structure to text. */ | ||||
| char *cJSON_Print(cJSON *item)				{return print_value(item,0,1);} | ||||
| char *cJSON_PrintUnformatted(cJSON *item)	{return print_value(item,0,0);} | ||||
| 
 | ||||
| /* Parser core - when encountering text, process appropriately. */ | ||||
| static const char *parse_value(cJSON *item,const char *value) | ||||
| { | ||||
| 	if (!value)						return 0;	/* Fail on null. */ | ||||
| 	if (!strncmp(value,"null",4))	{ item->type=cJSON_NULL;  return value+4; } | ||||
| 	if (!strncmp(value,"false",5))	{ item->type=cJSON_False; return value+5; } | ||||
| 	if (!strncmp(value,"true",4))	{ item->type=cJSON_True; item->valueint=1;	return value+4; } | ||||
| 	if (*value=='\"')				{ return parse_string(item,value); } | ||||
| 	if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(item,value); } | ||||
| 	if (*value=='[')				{ return parse_array(item,value); } | ||||
| 	if (*value=='{')				{ return parse_object(item,value); } | ||||
| 
 | ||||
| 	ep=value;return 0;	/* failure. */ | ||||
| } | ||||
| 
 | ||||
| /* Render a value to text. */ | ||||
| static char *print_value(cJSON *item,int depth,int fmt) | ||||
| { | ||||
| 	char *out=0; | ||||
| 	if (!item) return 0; | ||||
| 	switch ((item->type)&255) | ||||
| 	{ | ||||
| 		case cJSON_NULL:	out=cJSON_strdup("null");	break; | ||||
| 		case cJSON_False:	out=cJSON_strdup("false");break; | ||||
| 		case cJSON_True:	out=cJSON_strdup("true"); break; | ||||
| 		case cJSON_Number:	out=print_number(item);break; | ||||
| 		case cJSON_String:	out=print_string(item);break; | ||||
| 		case cJSON_Array:	out=print_array(item,depth,fmt);break; | ||||
| 		case cJSON_Object:	out=print_object(item,depth,fmt);break; | ||||
| 	} | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| /* Build an array from input text. */ | ||||
| static const char *parse_array(cJSON *item,const char *value) | ||||
| { | ||||
| 	cJSON *child; | ||||
| 	if (*value!='[')	{ep=value;return 0;}	/* not an array! */ | ||||
| 
 | ||||
| 	item->type=cJSON_Array; | ||||
| 	value=skip(value+1); | ||||
| 	if (*value==']') return value+1;	/* empty array. */ | ||||
| 
 | ||||
| 	item->child=child=cJSON_New_Item(); | ||||
| 	if (!item->child) return 0;		 /* memory fail */ | ||||
| 	value=skip(parse_value(child,skip(value)));	/* skip any spacing, get the value. */ | ||||
| 	if (!value) return 0; | ||||
| 
 | ||||
| 	while (*value==',') | ||||
| 	{ | ||||
| 		cJSON *new_item; | ||||
| 		if (!(new_item=cJSON_New_Item())) return 0; 	/* memory fail */ | ||||
| 		child->next=new_item;new_item->prev=child;child=new_item; | ||||
| 		value=skip(parse_value(child,skip(value+1))); | ||||
| 		if (!value) return 0;	/* memory fail */ | ||||
| 	} | ||||
| 
 | ||||
| 	if (*value==']') return value+1;	/* end of array */ | ||||
| 	ep=value;return 0;	/* malformed. */ | ||||
| } | ||||
| 
 | ||||
| /* Render an array to text */ | ||||
| static char *print_array(cJSON *item,int depth,int fmt) | ||||
| { | ||||
| 	char **entries; | ||||
| 	char *out=0,*ptr,*ret;int len=5; | ||||
| 	cJSON *child=item->child; | ||||
| 	int numentries=0,i=0,fail=0; | ||||
| 	 | ||||
| 	/* How many entries in the array? */ | ||||
| 	while (child) numentries++,child=child->next; | ||||
| 	/* Explicitly handle numentries==0 */ | ||||
| 	if (!numentries) | ||||
| 	{ | ||||
| 		out=(char*)cJSON_malloc(3); | ||||
| 		if (out) strcpy(out,"[]"); | ||||
| 		return out; | ||||
| 	} | ||||
| 	/* Allocate an array to hold the values for each */ | ||||
| 	entries=(char**)cJSON_malloc(numentries*sizeof(char*)); | ||||
| 	if (!entries) return 0; | ||||
| 	memset(entries,0,numentries*sizeof(char*)); | ||||
| 	/* Retrieve all the results: */ | ||||
| 	child=item->child; | ||||
| 	while (child && !fail) | ||||
| 	{ | ||||
| 		ret=print_value(child,depth+1,fmt); | ||||
| 		entries[i++]=ret; | ||||
| 		if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; | ||||
| 		child=child->next; | ||||
| 	} | ||||
| 	 | ||||
| 	/* If we didn't fail, try to malloc the output string */ | ||||
| 	if (!fail) out=(char*)cJSON_malloc(len); | ||||
| 	/* If that fails, we fail. */ | ||||
| 	if (!out) fail=1; | ||||
| 
 | ||||
| 	/* Handle failure. */ | ||||
| 	if (fail) | ||||
| 	{ | ||||
| 		for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]); | ||||
| 		cJSON_free(entries); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Compose the output array. */ | ||||
| 	*out='['; | ||||
| 	ptr=out+1;*ptr=0; | ||||
| 	for (i=0;i<numentries;i++) | ||||
| 	{ | ||||
| 		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); | ||||
| 		if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;} | ||||
| 		cJSON_free(entries[i]); | ||||
| 	} | ||||
| 	cJSON_free(entries); | ||||
| 	*ptr++=']';*ptr++=0; | ||||
| 	return out;	 | ||||
| } | ||||
| 
 | ||||
| /* Build an object from the text. */ | ||||
| static const char *parse_object(cJSON *item,const char *value) | ||||
| { | ||||
| 	cJSON *child; | ||||
| 	if (*value!='{')	{ep=value;return 0;}	/* not an object! */ | ||||
| 	 | ||||
| 	item->type=cJSON_Object; | ||||
| 	value=skip(value+1); | ||||
| 	if (*value=='}') return value+1;	/* empty array. */ | ||||
| 	 | ||||
| 	item->child=child=cJSON_New_Item(); | ||||
| 	if (!item->child) return 0; | ||||
| 	value=skip(parse_string(child,skip(value))); | ||||
| 	if (!value) return 0; | ||||
| 	child->string=child->valuestring;child->valuestring=0; | ||||
| 	if (*value!=':') {ep=value;return 0;}	/* fail! */ | ||||
| 	value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */ | ||||
| 	if (!value) return 0; | ||||
| 	 | ||||
| 	while (*value==',') | ||||
| 	{ | ||||
| 		cJSON *new_item; | ||||
| 		if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */ | ||||
| 		child->next=new_item;new_item->prev=child;child=new_item; | ||||
| 		value=skip(parse_string(child,skip(value+1))); | ||||
| 		if (!value) return 0; | ||||
| 		child->string=child->valuestring;child->valuestring=0; | ||||
| 		if (*value!=':') {ep=value;return 0;}	/* fail! */ | ||||
| 		value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */ | ||||
| 		if (!value) return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	if (*value=='}') return value+1;	/* end of array */ | ||||
| 	ep=value;return 0;	/* malformed. */ | ||||
| } | ||||
| 
 | ||||
| /* Render an object to text. */ | ||||
| static char *print_object(cJSON *item,int depth,int fmt) | ||||
| { | ||||
| 	char **entries=0,**names=0; | ||||
| 	char *out=0,*ptr,*ret,*str;int len=7,i=0,j; | ||||
| 	cJSON *child=item->child; | ||||
| 	int numentries=0,fail=0; | ||||
| 	/* Count the number of entries. */ | ||||
| 	while (child) numentries++,child=child->next; | ||||
| 	/* Explicitly handle empty object case */ | ||||
| 	if (!numentries) | ||||
| 	{ | ||||
| 		out=(char*)cJSON_malloc(fmt?depth+3:3); | ||||
| 		if (!out)	return 0; | ||||
| 		ptr=out;*ptr++='{'; | ||||
| 		if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';} | ||||
| 		*ptr++='}';*ptr++=0; | ||||
| 		return out; | ||||
| 	} | ||||
| 	/* Allocate space for the names and the objects */ | ||||
| 	entries=(char**)cJSON_malloc(numentries*sizeof(char*)); | ||||
| 	if (!entries) return 0; | ||||
| 	names=(char**)cJSON_malloc(numentries*sizeof(char*)); | ||||
| 	if (!names) {cJSON_free(entries);return 0;} | ||||
| 	memset(entries,0,sizeof(char*)*numentries); | ||||
| 	memset(names,0,sizeof(char*)*numentries); | ||||
| 
 | ||||
| 	/* Collect all the results into our arrays: */ | ||||
| 	child=item->child;depth++;if (fmt) len+=depth; | ||||
| 	while (child) | ||||
| 	{ | ||||
| 		names[i]=str=print_string_ptr(child->string); | ||||
| 		entries[i++]=ret=print_value(child,depth,fmt); | ||||
| 		if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; | ||||
| 		child=child->next; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Try to allocate the output string */ | ||||
| 	if (!fail) out=(char*)cJSON_malloc(len); | ||||
| 	if (!out) fail=1; | ||||
| 
 | ||||
| 	/* Handle failure */ | ||||
| 	if (fail) | ||||
| 	{ | ||||
| 		for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);} | ||||
| 		cJSON_free(names);cJSON_free(entries); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	 | ||||
| 	/* Compose the output: */ | ||||
| 	*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0; | ||||
| 	for (i=0;i<numentries;i++) | ||||
| 	{ | ||||
| 		if (fmt) for (j=0;j<depth;j++) *ptr++='\t'; | ||||
| 		strcpy(ptr,names[i]);ptr+=strlen(names[i]); | ||||
| 		*ptr++=':';if (fmt) *ptr++='\t'; | ||||
| 		strcpy(ptr,entries[i]);ptr+=strlen(entries[i]); | ||||
| 		if (i!=numentries-1) *ptr++=','; | ||||
| 		if (fmt) *ptr++='\n';*ptr=0; | ||||
| 		cJSON_free(names[i]);cJSON_free(entries[i]); | ||||
| 	} | ||||
| 	 | ||||
| 	cJSON_free(names);cJSON_free(entries); | ||||
| 	if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t'; | ||||
| 	*ptr++='}';*ptr++=0; | ||||
| 	return out;	 | ||||
| } | ||||
| 
 | ||||
| /* Get Array size/item / object item. */ | ||||
| int    cJSON_GetArraySize(cJSON *array)							{cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;} | ||||
| cJSON *cJSON_GetArrayItem(cJSON *array,int item)				{cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;} | ||||
| cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	{cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} | ||||
| 
 | ||||
| /* Utility for array list handling. */ | ||||
| static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} | ||||
| /* Utility for handling references. */ | ||||
| static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} | ||||
| 
 | ||||
| /* Add item to array/object. */ | ||||
| void   cJSON_AddItemToArray(cJSON *array, cJSON *item)						{cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} | ||||
| void   cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} | ||||
| void	cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)						{cJSON_AddItemToArray(array,create_reference(item));} | ||||
| void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)	{cJSON_AddItemToObject(object,string,create_reference(item));} | ||||
| 
 | ||||
| cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)			{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; | ||||
| 	if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} | ||||
| void   cJSON_DeleteItemFromArray(cJSON *array,int which)			{cJSON_Delete(cJSON_DetachItemFromArray(array,which));} | ||||
| cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} | ||||
| void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} | ||||
| 
 | ||||
| /* Replace array/object items with new ones. */ | ||||
| void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; | ||||
| 	newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; | ||||
| 	if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} | ||||
| void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} | ||||
| 
 | ||||
| /* Create basic types: */ | ||||
| cJSON *cJSON_CreateNull(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} | ||||
| cJSON *cJSON_CreateTrue(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} | ||||
| cJSON *cJSON_CreateFalse(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} | ||||
| cJSON *cJSON_CreateBool(int b)					{cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} | ||||
| cJSON *cJSON_CreateNumber(double num)			{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} | ||||
| cJSON *cJSON_CreateString(const char *string)	{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} | ||||
| cJSON *cJSON_CreateArray(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} | ||||
| cJSON *cJSON_CreateObject(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} | ||||
| 
 | ||||
| /* Create Arrays: */ | ||||
| cJSON *cJSON_CreateIntArray(int *numbers,int count)				{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| cJSON *cJSON_CreateFloatArray(float *numbers,int count)			{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| cJSON *cJSON_CreateDoubleArray(double *numbers,int count)		{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| cJSON *cJSON_CreateStringArray(const char **strings,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;} | ||||
| 
 | ||||
| /* Duplication */ | ||||
| cJSON *cJSON_Duplicate(cJSON *item,int recurse) | ||||
| { | ||||
| 	cJSON *newitem,*cptr,*nptr=0,*newchild; | ||||
| 	/* Bail on bad ptr */ | ||||
| 	if (!item) return 0; | ||||
| 	/* Create new item */ | ||||
| 	newitem=cJSON_New_Item(); | ||||
| 	if (!newitem) return 0; | ||||
| 	/* Copy over all vars */ | ||||
| 	newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; | ||||
| 	if (item->valuestring)	{newitem->valuestring=cJSON_strdup(item->valuestring);	if (!newitem->valuestring)	{cJSON_Delete(newitem);return 0;}} | ||||
| 	if (item->string)		{newitem->string=cJSON_strdup(item->string);			if (!newitem->string)		{cJSON_Delete(newitem);return 0;}} | ||||
| 	/* If non-recursive, then we're done! */ | ||||
| 	if (!recurse) return newitem; | ||||
| 	/* Walk the ->next chain for the child. */ | ||||
| 	cptr=item->child; | ||||
| 	while (cptr) | ||||
| 	{ | ||||
| 		newchild=cJSON_Duplicate(cptr,1);		/* Duplicate (with recurse) each item in the ->next chain */ | ||||
| 		if (!newchild) {cJSON_Delete(newitem);return 0;} | ||||
| 		if (nptr)	{nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}	/* If newitem->child already set, then crosswire ->prev and ->next and move on */ | ||||
| 		else		{newitem->child=newchild;nptr=newchild;}					/* Set newitem->child and move to it */ | ||||
| 		cptr=cptr->next; | ||||
| 	} | ||||
| 	return newitem; | ||||
| } | ||||
| @ -1,140 +0,0 @@ | ||||
| /*
 | ||||
|   Copyright (c) 2009 Dave Gamble | ||||
|   | ||||
|   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 Software without restriction, including without limitation the rights | ||||
|   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|   copies of the Software, and to permit persons to whom the Software is | ||||
|   furnished to do so, subject to the following conditions: | ||||
|   | ||||
|   The above copyright notice and this permission notice shall be included in | ||||
|   all copies or substantial portions of the Software. | ||||
|   | ||||
|   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|   THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef cJSON__h | ||||
| #define cJSON__h | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
| #include <stdio.h> | ||||
| /* cJSON Types: */ | ||||
| #define cJSON_False 0 | ||||
| #define cJSON_True 1 | ||||
| #define cJSON_NULL 2 | ||||
| #define cJSON_Number 3 | ||||
| #define cJSON_String 4 | ||||
| #define cJSON_Array 5 | ||||
| #define cJSON_Object 6 | ||||
| 	 | ||||
| #define cJSON_IsReference 256 | ||||
| 
 | ||||
| /* The cJSON structure: */ | ||||
| typedef struct cJSON { | ||||
| 	struct cJSON *next,*prev;	/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ | ||||
| 	struct cJSON *child;		/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ | ||||
| 
 | ||||
| 	int type;					/* The type of the item, as above. */ | ||||
| 
 | ||||
| 	char *valuestring;			/* The item's string, if type==cJSON_String */ | ||||
| 	int valueint;				/* The item's number, if type==cJSON_Number */ | ||||
| 	double valuedouble;			/* The item's number, if type==cJSON_Number */ | ||||
| 
 | ||||
| 	char *string;				/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ | ||||
| } cJSON; | ||||
| 
 | ||||
| typedef struct cJSON_Hooks { | ||||
|       void *(*malloc_fn)(size_t sz); | ||||
|       void (*free_fn)(void *ptr); | ||||
| } cJSON_Hooks; | ||||
| 
 | ||||
| /* Supply malloc, realloc and free functions to cJSON */ | ||||
| extern void cJSON_InitHooks(cJSON_Hooks* hooks); | ||||
| 
 | ||||
| 
 | ||||
| /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ | ||||
| extern cJSON *cJSON_Parse(const char *value); | ||||
| /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ | ||||
| extern char  *cJSON_Print(cJSON *item); | ||||
| /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ | ||||
| extern char  *cJSON_PrintUnformatted(cJSON *item); | ||||
| /* Delete a cJSON entity and all subentities. */ | ||||
| extern void   cJSON_Delete(cJSON *c); | ||||
| 
 | ||||
| /* Returns the number of items in an array (or object). */ | ||||
| extern int	  cJSON_GetArraySize(cJSON *array); | ||||
| /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ | ||||
| extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); | ||||
| /* Get item "string" from object. Case insensitive. */ | ||||
| extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); | ||||
| 
 | ||||
| /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ | ||||
| extern const char *cJSON_GetErrorPtr(void); | ||||
| 	 | ||||
| /* These calls create a cJSON item of the appropriate type. */ | ||||
| extern cJSON *cJSON_CreateNull(void); | ||||
| extern cJSON *cJSON_CreateTrue(void); | ||||
| extern cJSON *cJSON_CreateFalse(void); | ||||
| extern cJSON *cJSON_CreateBool(int b); | ||||
| extern cJSON *cJSON_CreateNumber(double num); | ||||
| extern cJSON *cJSON_CreateString(const char *string); | ||||
| extern cJSON *cJSON_CreateArray(void); | ||||
| extern cJSON *cJSON_CreateObject(void); | ||||
| 
 | ||||
| /* These utilities create an Array of count items. */ | ||||
| extern cJSON *cJSON_CreateIntArray(int *numbers,int count); | ||||
| extern cJSON *cJSON_CreateFloatArray(float *numbers,int count); | ||||
| extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); | ||||
| extern cJSON *cJSON_CreateStringArray(const char **strings,int count); | ||||
| 
 | ||||
| /* Append item to the specified array/object. */ | ||||
| extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); | ||||
| extern void	cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); | ||||
| /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ | ||||
| extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); | ||||
| extern void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); | ||||
| 
 | ||||
| /* Remove/Detatch items from Arrays/Objects. */ | ||||
| extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); | ||||
| extern void   cJSON_DeleteItemFromArray(cJSON *array,int which); | ||||
| extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); | ||||
| extern void   cJSON_DeleteItemFromObject(cJSON *object,const char *string); | ||||
| 	 | ||||
| /* Update array items. */ | ||||
| extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); | ||||
| extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); | ||||
| 
 | ||||
| /* Duplicate a cJSON item */ | ||||
| extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); | ||||
| /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
 | ||||
| need to be released. With recurse!=0, it will duplicate any children connected to the item. | ||||
| The item->next and ->prev pointers are always zero on return from Duplicate. */ | ||||
| 
 | ||||
| /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ | ||||
| extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); | ||||
| 
 | ||||
| /* Macros for creating things quickly. */ | ||||
| #define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull()) | ||||
| #define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) | ||||
| #define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) | ||||
| #define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) | ||||
| #define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) | ||||
| #define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) | ||||
| 
 | ||||
| /* When assigning an integer value, it needs to be propagated to valuedouble too. */ | ||||
| #define cJSON_SetIntValue(object,val)			((object)?(object)->valueint=(object)->valuedouble=(val):(val)) | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
| @ -1,7 +1,7 @@ | ||||
| #include "sgx_ra_tls_utils.h" | ||||
| #include "sgx_ra_tls_backend.h" | ||||
| #include "sgx_quote_3.h" | ||||
| #include "dcap_quote.h" | ||||
| #include "occlum_dcap.h" | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
|  | ||||
| @ -32,7 +32,7 @@ namespace sgx { | ||||
| #include <openssl/asn1.h> | ||||
| 
 | ||||
| #include "sgx_quote_3.h" | ||||
| #include "dcap_quote.h" | ||||
| #include "occlum_dcap.h" | ||||
| 
 | ||||
| const char * RA_TLS_LONG_NAME = "RA-TLS Extension"; | ||||
| const char * RA_TLS_SHORT_NAME = "RA-TLS"; | ||||
|  | ||||
| @ -27,10 +27,11 @@ | ||||
| #define grpc_printf printf | ||||
| #define grpc_fprintf fprintf | ||||
| 
 | ||||
| #include <grpcpp/security/sgx/sgx_ra_tls.h> | ||||
| 
 | ||||
| namespace grpc { | ||||
| namespace sgx { | ||||
| 
 | ||||
| #include "cjson/cJSON.h" | ||||
| 
 | ||||
| class library_engine { | ||||
|     public: | ||||
| @ -53,30 +54,6 @@ class library_engine { | ||||
|         char* error; | ||||
| }; | ||||
| 
 | ||||
| class json_engine { | ||||
|     public: | ||||
|         json_engine(); | ||||
| 
 | ||||
|         json_engine(const char*); | ||||
| 
 | ||||
|         ~json_engine(); | ||||
| 
 | ||||
|         bool open(const char*); | ||||
| 
 | ||||
|         void close(); | ||||
| 
 | ||||
|         cJSON* get_handle(); | ||||
| 
 | ||||
|         cJSON* get_item(cJSON* obj, const char* item); | ||||
| 
 | ||||
|         char* print_item(cJSON* obj); | ||||
| 
 | ||||
|         bool compare_item(cJSON* obj, const char* item); | ||||
| 
 | ||||
|     private: | ||||
|         cJSON* handle; | ||||
| }; | ||||
| 
 | ||||
| void check_free(void* ptr); | ||||
| 
 | ||||
| bool hex_to_byte(const char* src, char* dst, size_t dst_size); | ||||
|  | ||||
							
								
								
									
										15
									
								
								demos/ra_tls/grpc_ratls_client.yaml
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										15
									
								
								demos/ra_tls/grpc_ratls_client.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| includes: | ||||
|   - base.yaml | ||||
| targets: | ||||
|   - target: /bin/ | ||||
|     copy: | ||||
|       - files: | ||||
|         - ../grpc-src/examples/cpp/ratls/build/client | ||||
|   - target: / | ||||
|     copy: | ||||
|       - files: | ||||
|         - dynamic_config.json | ||||
|   - target: /usr/share/grpc/ | ||||
|     copy: | ||||
|       - files: | ||||
|         - ../grpc-src/etc/roots.pem | ||||
							
								
								
									
										16
									
								
								demos/ra_tls/grpc_ratls_server.yaml
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										16
									
								
								demos/ra_tls/grpc_ratls_server.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| includes: | ||||
|   - base.yaml | ||||
| targets: | ||||
|   - target: /bin/ | ||||
|     copy: | ||||
|       - files: | ||||
|         - ../grpc-src/examples/cpp/ratls/build/server | ||||
|   - target: / | ||||
|     copy: | ||||
|       - files: | ||||
|         - dynamic_config.json | ||||
|         - ../secret_config.json | ||||
|   - target: /usr/share/grpc/ | ||||
|     copy: | ||||
|       - files: | ||||
|         - ../grpc-src/etc/roots.pem | ||||
| @ -1,59 +0,0 @@ | ||||
| #!/bin/bash | ||||
| INSTALL_PREFIX=/usr/local | ||||
| apt-get update \ | ||||
|     && apt-get install -y --no-install-recommends apt-utils \ | ||||
|     && apt-get install -y \ | ||||
|         ca-certificates \ | ||||
|         build-essential \ | ||||
|         autoconf \ | ||||
|         libtool \ | ||||
|         python3-pip \ | ||||
|         python3-dev \ | ||||
|         git \ | ||||
|         wget \ | ||||
|         unzip | ||||
| 
 | ||||
| mkdir -p ${INSTALL_PREFIX} \ | ||||
|     && wget -q -O cmake-linux.sh https://github.com/Kitware/CMake/releases/download/v3.19.6/cmake-3.19.6-Linux-x86_64.sh \ | ||||
|     && sh cmake-linux.sh -- --skip-license --prefix=${INSTALL_PREFIX} \ | ||||
|     && rm cmake-linux.sh | ||||
| 
 | ||||
| # Install cJSON | ||||
| CJSON_PATH=/cJSON | ||||
| git clone https://github.com/DaveGamble/cJSON.git ${CJSON_PATH} | ||||
| pushd ${CJSON_PATH} \ | ||||
|     && make static \ | ||||
|     && cp -r *.a ${INSTALL_PREFIX}/lib \ | ||||
|     && mkdir -p ${INSTALL_PREFIX}/include/cjson \ | ||||
|     && cp -r *.h ${INSTALL_PREFIX}/include/cjson | ||||
| popd | ||||
| 
 | ||||
| # GRPC env | ||||
| GRPC_VERSION=v1.38.x | ||||
| export GRPC_PATH=/grpc | ||||
| 
 | ||||
| # GRPC source code | ||||
| git clone https://github.com/grpc/grpc -b ${GRPC_VERSION} ${GRPC_PATH} | ||||
| pushd ${GRPC_PATH} \ | ||||
|     && pip3 install --upgrade pip setuptools==44.1.1 \ | ||||
|     && pip3 install -r requirements.txt \ | ||||
|     && git checkout v1.38.1 \ | ||||
|     && git submodule update --init | ||||
| popd | ||||
| 
 | ||||
| cp -rf grpc/common/* ${GRPC_PATH}/ | ||||
| cp -rf grpc/v1.38.1/* ${GRPC_PATH}/ | ||||
| 
 | ||||
| git clone  https://github.com/occlum/occlum | ||||
| pushd occlum | ||||
| make submodule | ||||
| cd demos/remote_attestation/dcap/dcap_lib | ||||
| cargo build --all-targets | ||||
| cp target/debug/libdcap_quote.a /usr/local/lib/ | ||||
| cp ../c_app/dcap_quote.h /usr/local/include/ | ||||
| popd | ||||
| 
 | ||||
| pushd ${GRPC_PATH}/examples/cpp/ratls | ||||
| ./build.sh | ||||
| popd | ||||
| 
 | ||||
| @ -1,8 +1,8 @@ | ||||
| { | ||||
|     "verify_mr_enclave" : "off", | ||||
|     "verify_mr_signer" : "off", | ||||
|     "verify_isv_prod_id" : "off", | ||||
|     "verify_isv_svn" : "off", | ||||
|     "verify_mr_enclave" : "on", | ||||
|     "verify_mr_signer" : "on", | ||||
|     "verify_isv_prod_id" : "on", | ||||
|     "verify_isv_svn" : "on", | ||||
|     "sgx_mrs": [ | ||||
|         { | ||||
|             "mr_enclave" : "", | ||||
| @ -1,7 +1,9 @@ | ||||
| #!/bin/bash | ||||
| set -ex | ||||
| set -e | ||||
| 
 | ||||
| postfix=$1 | ||||
| request=$2 | ||||
| file=${3:-/host/secret} | ||||
| 
 | ||||
| if [ "$postfix" != "server" ] && [ "$postfix" != "client" ]; then | ||||
|     echo "input error args, it should be:"  | ||||
| @ -10,6 +12,6 @@ if [ "$postfix" != "server" ] && [ "$postfix" != "client" ]; then | ||||
|     exit 1 | ||||
| fi | ||||
| 
 | ||||
| pushd occlum_instance_$postfix | ||||
| occlum run /bin/$postfix | ||||
| pushd occlum_$postfix | ||||
| occlum run /bin/$postfix ${request} ${file} | ||||
| popd | ||||
|  | ||||
							
								
								
									
										4
									
								
								demos/ra_tls/secret_config.json
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										4
									
								
								demos/ra_tls/secret_config.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| { | ||||
|     "cert" : "dGVzdCBzYW1wbGUgY2VydGlmaWNhdGVzCg==", | ||||
|     "key" : "dGVzdCBzYW1wbGUga2V5Cg==" | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user