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 }} |         container-name: ${{ github.job }} | ||||||
|         build-envs: 'OCCLUM_RELEASE_BUILD=1' |         build-envs: 'OCCLUM_RELEASE_BUILD=1' | ||||||
| 
 | 
 | ||||||
|     - name: Download and build the pakckages |     - name: Download source code | ||||||
|       run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./prepare_and_build_package.sh" |       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 |     - 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 |     - name: Run gRPC server | ||||||
|       run: docker exec ${{ env.CONTAINER_NAME }} bash -c "cd /root/occlum/demos/ra_tls; ./run.sh 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 | # 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. | 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 | ./build_occlum_instance.sh | ||||||
| ``` | ``` | ||||||
|  | If previous build choice is `musl`. | ||||||
|  | ``` | ||||||
|  | ./build_occlum_instance.sh musl | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| Run the gRPC server & client in occlum. | Run the gRPC server & client in occlum. | ||||||
| 
 | 
 | ||||||
| ``` | ``` | ||||||
| ./run.sh server & | ./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. | ***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 | #!/bin/bash | ||||||
| occlum_glibc=/opt/occlum/glibc/lib/ | set -e | ||||||
| set -ex |  | ||||||
| 
 | 
 | ||||||
| get_mr() { | function get_mr() { | ||||||
|     sgx_sign dump -enclave ../occlum_instance_$1/build/lib/libocclum-libos.signed.so -dumpfile ../metadata_info_$1.txt |     sgx_sign dump -enclave ../occlum_$1/build/lib/libocclum-libos.signed.so -dumpfile ../metadata_info_$1.txt | ||||||
|     if [ "$2" == "mr_enclave" ]; then |     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' |         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 |     elif [ "$2" == "mr_signer" ]; then | ||||||
| @ -11,43 +10,56 @@ get_mr() { | |||||||
|     fi |     fi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| build_instance() { | function build_instance() { | ||||||
|     # 1. Init Occlum Workspace |     # 1. Init Occlum Workspace | ||||||
|     rm -rf occlum_instance_$postfix |     rm -rf occlum_$postfix | ||||||
|     mkdir occlum_instance_$postfix |     mkdir occlum_$postfix | ||||||
|     pushd occlum_instance_$postfix |     pushd occlum_$postfix | ||||||
|     occlum init |     occlum init | ||||||
|     new_json="$(jq '.resource_limits.user_space_size = "320MB" | |     new_json="$(jq '.resource_limits.user_space_size = "500MB"' Occlum.json)" && \ | ||||||
|                     .process.default_mmap_size = "256MB"' Occlum.json)" && \ |  | ||||||
|     echo "${new_json}" > 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 |     if [ "$postfix" == "server" ]; then | ||||||
|  |         # Server will verify client's mr_enclave and mr_signer | ||||||
|         jq ' .verify_mr_enclave = "on" | |         jq ' .verify_mr_enclave = "on" | | ||||||
|              .verify_mr_signer = "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_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 |     fi | ||||||
|     mkdir -p image/usr/share/grpc | 
 | ||||||
|     cp -rf /share/grpc/*  image/usr/share/grpc/ |     rm -rf image | ||||||
|     cp $occlum_glibc/libdl.so.2 image/$occlum_glibc |     copy_bom -f $bomfile --root image --include-dir /opt/occlum/etc/template | ||||||
|     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/ |  | ||||||
|     occlum build |     occlum build | ||||||
|     popd |     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 | postfix=client | ||||||
| build_instance | build_instance | ||||||
| postfix=server | 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) | if(DEFINE_SGX_RA_TLS_OCCLUM_BACKEND) | ||||||
|   message("SGX_RA_TLS_OCCLUM_BACKEND is defined") |   message("SGX_RA_TLS_OCCLUM_BACKEND is defined") | ||||||
|  |   include_directories(/opt/intel/sgxsdk/include) | ||||||
|   add_definitions(-DSGX_RA_TLS_OCCLUM_BACKEND) |   add_definitions(-DSGX_RA_TLS_OCCLUM_BACKEND) | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
| @ -2089,7 +2090,8 @@ if(DEFINE_SGX_RA_TLS_OCCLUM_BACKEND) | |||||||
|     gpr |     gpr | ||||||
|     ${_gRPC_SSL_LIBRARIES} |     ${_gRPC_SSL_LIBRARIES} | ||||||
|     address_sorting |     address_sorting | ||||||
|     libdcap_quote.a |     occlum_dcap | ||||||
|  |     cjson | ||||||
|   ) |   ) | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
| @ -2793,7 +2795,6 @@ add_library(grpc++ | |||||||
|   src/cpp/sgx/sgx_ra_tls_backends.cc |   src/cpp/sgx/sgx_ra_tls_backends.cc | ||||||
|   src/cpp/sgx/sgx_ra_tls_occlum.cc |   src/cpp/sgx/sgx_ra_tls_occlum.cc | ||||||
|   src/cpp/sgx/sgx_ra_tls_utils.cc |   src/cpp/sgx/sgx_ra_tls_utils.cc | ||||||
|   src/cpp/sgx/cjson/cJSON.c |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| set_target_properties(grpc++ PROPERTIES | set_target_properties(grpc++ PROPERTIES | ||||||
|  | |||||||
| @ -41,7 +41,7 @@ add_custom_command( | |||||||
| include_directories("${CMAKE_CURRENT_BINARY_DIR}") | include_directories("${CMAKE_CURRENT_BINARY_DIR}") | ||||||
| 
 | 
 | ||||||
| # hw_grpc_proto | # hw_grpc_proto | ||||||
| add_library(hw_grpc_proto | add_library(hw_grpc_proto SHARED | ||||||
|   ${hw_grpc_srcs} |   ${hw_grpc_srcs} | ||||||
|   ${hw_grpc_hdrs} |   ${hw_grpc_hdrs} | ||||||
|   ${hw_proto_srcs} |   ${hw_proto_srcs} | ||||||
| @ -51,12 +51,14 @@ target_link_libraries(hw_grpc_proto | |||||||
|   ${_GRPC_GRPCPP} |   ${_GRPC_GRPCPP} | ||||||
|   ${_PROTOBUF_LIBPROTOBUF}) |   ${_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) | foreach(_target client server) | ||||||
|   add_executable(${_target} "${_target}.cc") |   add_executable(${_target} "${_target}.cc") | ||||||
|   target_link_libraries(${_target} |   target_link_libraries(${_target} | ||||||
|     hw_grpc_proto |     grpc_ratls_${_target}) | ||||||
|     ${_REFLECTION} |  | ||||||
|     ${_GRPC_GRPCPP} |  | ||||||
|     ${_PROTOBUF_LIBPROTOBUF}) |  | ||||||
| endforeach() | 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 BUILD_TYPE=Release | ||||||
| export EXP_PATH=`dirname $0` | export EXP_PATH=`dirname $0` | ||||||
| 
 | 
 | ||||||
| ${GRPC_PATH}/build_cpp.sh |  | ||||||
| 
 |  | ||||||
| # build c++ example | # build c++ example | ||||||
| cd ${EXP_PATH} | cd ${EXP_PATH} | ||||||
| mkdir -p build | mkdir -p build | ||||||
|  | |||||||
| @ -15,72 +15,27 @@ | |||||||
|  * limitations under the License. |  * limitations under the License. | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <unistd.h> | ||||||
| 
 | 
 | ||||||
| #include <grpcpp/grpcpp.h> | #include "../grpc_ratls_client.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 "../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) { | 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; |     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. |  * 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) { | int main(int argc, char** argv) { | ||||||
|     RunServer(); |     gr_start_server( | ||||||
|  |         "localhost:50051", | ||||||
|  |         "dynamic_config.json", | ||||||
|  |         "secret_config.json" | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| @ -21,18 +21,18 @@ option objc_class_prefix = "HLW"; | |||||||
| 
 | 
 | ||||||
| package ratls; | package ratls; | ||||||
| 
 | 
 | ||||||
| // The greeting service definition. | // The GRPC_RATLS secret service definition. | ||||||
| service Greeter { | service GrSecret { | ||||||
|   // Sends a greeting |   // Sends a greeting | ||||||
|   rpc SayHello (HelloRequest) returns (HelloReply) {} |   rpc GetSecret (SecretRequest) returns (SecretReply) {} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // The request message containing the user's name. | // The request message containing the request's name. | ||||||
| message HelloRequest { | message SecretRequest { | ||||||
|   string name = 1; |   string name = 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // The response message containing the greetings | // The response message containing the secret (base64 encoded string) | ||||||
| message HelloReply { | message SecretReply { | ||||||
|   string message = 1; |   string secret = 1; | ||||||
| } | } | ||||||
|  | |||||||
| @ -24,6 +24,8 @@ | |||||||
| #include <grpcpp/security/credentials.h> | #include <grpcpp/security/credentials.h> | ||||||
| #include <grpcpp/security/server_credentials.h> | #include <grpcpp/security/server_credentials.h> | ||||||
| 
 | 
 | ||||||
|  | #include <cjson/cJSON.h> | ||||||
|  | 
 | ||||||
| namespace grpc { | namespace grpc { | ||||||
| namespace sgx { | namespace sgx { | ||||||
| 
 | 
 | ||||||
| @ -51,6 +53,30 @@ std::shared_ptr<grpc::ServerCredentials> TlsServerCredentials(const char* sgx_cf | |||||||
| std::shared_ptr<grpc::Channel> CreateSecureChannel( | std::shared_ptr<grpc::Channel> CreateSecureChannel( | ||||||
|     string target_str, std::shared_ptr<grpc::ChannelCredentials> channel_creds); |     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 sgx
 | ||||||
| }  // namespace grpc
 | }  // 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_utils.h" | ||||||
| #include "sgx_ra_tls_backend.h" | #include "sgx_ra_tls_backend.h" | ||||||
| #include "sgx_quote_3.h" | #include "sgx_quote_3.h" | ||||||
| #include "dcap_quote.h" | #include "occlum_dcap.h" | ||||||
| 
 | 
 | ||||||
| namespace grpc { | namespace grpc { | ||||||
| namespace sgx { | namespace sgx { | ||||||
|  | |||||||
| @ -32,7 +32,7 @@ namespace sgx { | |||||||
| #include <openssl/asn1.h> | #include <openssl/asn1.h> | ||||||
| 
 | 
 | ||||||
| #include "sgx_quote_3.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_LONG_NAME = "RA-TLS Extension"; | ||||||
| const char * RA_TLS_SHORT_NAME = "RA-TLS"; | const char * RA_TLS_SHORT_NAME = "RA-TLS"; | ||||||
|  | |||||||
| @ -27,10 +27,11 @@ | |||||||
| #define grpc_printf printf | #define grpc_printf printf | ||||||
| #define grpc_fprintf fprintf | #define grpc_fprintf fprintf | ||||||
| 
 | 
 | ||||||
|  | #include <grpcpp/security/sgx/sgx_ra_tls.h> | ||||||
|  | 
 | ||||||
| namespace grpc { | namespace grpc { | ||||||
| namespace sgx { | namespace sgx { | ||||||
| 
 | 
 | ||||||
| #include "cjson/cJSON.h" |  | ||||||
| 
 | 
 | ||||||
| class library_engine { | class library_engine { | ||||||
|     public: |     public: | ||||||
| @ -53,30 +54,6 @@ class library_engine { | |||||||
|         char* error; |         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); | void check_free(void* ptr); | ||||||
| 
 | 
 | ||||||
| bool hex_to_byte(const char* src, char* dst, size_t dst_size); | 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_enclave" : "on", | ||||||
|     "verify_mr_signer" : "off", |     "verify_mr_signer" : "on", | ||||||
|     "verify_isv_prod_id" : "off", |     "verify_isv_prod_id" : "on", | ||||||
|     "verify_isv_svn" : "off", |     "verify_isv_svn" : "on", | ||||||
|     "sgx_mrs": [ |     "sgx_mrs": [ | ||||||
|         { |         { | ||||||
|             "mr_enclave" : "", |             "mr_enclave" : "", | ||||||
| @ -1,7 +1,9 @@ | |||||||
| #!/bin/bash | #!/bin/bash | ||||||
| set -ex | set -e | ||||||
| 
 | 
 | ||||||
| postfix=$1 | postfix=$1 | ||||||
|  | request=$2 | ||||||
|  | file=${3:-/host/secret} | ||||||
| 
 | 
 | ||||||
| if [ "$postfix" != "server" ] && [ "$postfix" != "client" ]; then | if [ "$postfix" != "server" ] && [ "$postfix" != "client" ]; then | ||||||
|     echo "input error args, it should be:"  |     echo "input error args, it should be:"  | ||||||
| @ -10,6 +12,6 @@ if [ "$postfix" != "server" ] && [ "$postfix" != "client" ]; then | |||||||
|     exit 1 |     exit 1 | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| pushd occlum_instance_$postfix | pushd occlum_$postfix | ||||||
| occlum run /bin/$postfix | occlum run /bin/$postfix ${request} ${file} | ||||||
| popd | 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