This is an automated email from the ASF dual-hosted git repository.

mssun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git


The following commit(s) were added to refs/heads/master by this push:
     new f0fc059  Add C client SDK and examples (#470)
f0fc059 is described below

commit f0fc0593b395ef4ce010a2e39dc05f6a43e06197
Author: Mingshen Sun <[email protected]>
AuthorDate: Tue Jan 26 10:39:50 2021 -0800

    Add C client SDK and examples (#470)
---
 cmake/scripts/test.sh       |   4 +
 examples/c/.clang-format    |   2 +
 examples/c/Makefile         |  38 +++++
 examples/c/builtin_echo.c   | 193 ++++++++++++++++++++++++
 sdk/c/Makefile              |  22 +++
 sdk/c/cbindgen.toml         |  32 ++++
 sdk/c/teaclave_client_sdk.h | 123 ++++++++++++++++
 sdk/rust/Cargo.toml         |   6 +
 sdk/rust/src/bindings.rs    | 350 ++++++++++++++++++++++++++++++++++++++++++++
 sdk/rust/src/lib.rs         | 112 ++++++++++++++
 10 files changed, 882 insertions(+)

diff --git a/cmake/scripts/test.sh b/cmake/scripts/test.sh
index 6702253..6ecf1e3 100755
--- a/cmake/scripts/test.sh
+++ b/cmake/scripts/test.sh
@@ -232,6 +232,10 @@ run_examples() {
   python3 builtin_password_check.py
   popd
 
+  pushd ${TEACLAVE_PROJECT_ROOT}/examples/c
+  make run
+  popd
+
   # kill all background services
   cleanup
 }
diff --git a/examples/c/.clang-format b/examples/c/.clang-format
new file mode 100644
index 0000000..80d3293
--- /dev/null
+++ b/examples/c/.clang-format
@@ -0,0 +1,2 @@
+BasedOnStyle: LLVM
+IndentWidth: 4
diff --git a/examples/c/Makefile b/examples/c/Makefile
new file mode 100644
index 0000000..2cc0b68
--- /dev/null
+++ b/examples/c/Makefile
@@ -0,0 +1,38 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+
+
+all: builtin_echo
+
+CFLAGS := -I../../sdk/c -Ltarget/debug/ -lteaclave_client_sdk
+
+ifeq ($(DCAP),ON)
+       CFLAGS += -DDCAP
+endif
+
+target/debug/libteaclave_client_sdk.so:
+       RUSTFLAGS="$(RUSTFLAGS)" cargo build --manifest-path 
../../sdk/rust/Cargo.toml --target-dir target
+
+builtin_echo: builtin_echo.c target/debug/libteaclave_client_sdk.so
+       gcc -o $@ builtin_echo.c $(CFLAGS)
+
+run: builtin_echo
+       LD_LIBRARY_PATH=target/debug  ./builtin_echo
+
+clean:
+       @rm -rf target
+       @rm builtin_echo
diff --git a/examples/c/builtin_echo.c b/examples/c/builtin_echo.c
new file mode 100644
index 0000000..acd6f1c
--- /dev/null
+++ b/examples/c/builtin_echo.c
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 "teaclave_client_sdk.h"
+#include <stdio.h>
+#include <string.h>
+
+#define BUFFER_SIZE 4086
+
+const char *authentication_service_address = "localhost:7776";
+const char *frontend_service_address = "localhost:7777";
+const char *enclave_info_path = "../../release/services/enclave_info.toml";
+#ifdef DCAP
+const char *as_root_ca_cert_path = "../../keys/dcap_root_ca_cert.pem";
+#else
+const char *as_root_ca_cert_path = "../../keys/ias_root_ca_cert.pem";
+#endif
+const char *user_id = "test_id";
+const char *user_password = "test_password";
+
+const char *register_function_request_serialized =
+    "{"
+    "    \"request\": \"register_function\","
+    "    \"name\": \"builtin-echo\","
+    "    \"description\": \"Native Echo Function\","
+    "    \"executor_type\": \"builtin\","
+    "    \"public\": true,"
+    "    \"payload\": [],"
+    "    \"arguments\": ["
+    "        \"message\""
+    "    ],"
+    "    \"inputs\": [],"
+    "    \"outputs\": []"
+    "}";
+
+const char *create_task_request_serialized =
+    "{"
+    "    \"request\": \"create_task\","
+    "    \"function_id\": \"%s\","
+    "    \"function_arguments\": \"{\\\"message\\\": \\\"Hello, "
+    "Teaclave!\\\"}\","
+    "    \"executor\": \"builtin\","
+    "    \"inputs_ownership\": [],"
+    "    \"outputs_ownership\": []"
+    "}";
+
+int login(char *token, size_t *token_len) {
+    int ret = 0;
+
+    AuthenticationClient *authentication_client =
+        teaclave_connect_authentication_service(authentication_service_address,
+                                                enclave_info_path,
+                                                as_root_ca_cert_path);
+    if (authentication_client == NULL) {
+        fprintf(stderr,
+                "[-] Failed to connect to the authentication service.\n");
+        ret = 1;
+        goto bail;
+    }
+
+    ret = teaclave_user_register(authentication_client, user_id, 
user_password);
+    if (ret != 0) {
+        fprintf(stderr, "[-] Failed to register user.\n");
+        fprintf(stderr, "[-] Maybe `%s' already exists. Continue. \n", 
user_id);
+    }
+
+    ret = teaclave_user_login(authentication_client, user_id, user_password,
+                              token, token_len);
+    if (ret != 0) {
+        fprintf(stderr, "[-] Failed to login.\n");
+        goto bail;
+    }
+    printf("[+] token: %s\n", token);
+
+bail:
+    if (authentication_client) {
+        ret = teaclave_close_authentication_service(authentication_client);
+        if (ret != 0) {
+            fprintf(stderr,
+                    "[-] Failed to close the authentication service 
client.\n");
+        }
+    }
+
+    return ret;
+}
+
+int main() {
+    int ret = 0;
+
+    char token[BUFFER_SIZE] = {0};
+    char serialized_response[BUFFER_SIZE] = {0};
+    char function_id[BUFFER_SIZE] = {0};
+    char serialized_request[BUFFER_SIZE] = {0};
+    char task_result[BUFFER_SIZE] = {0};
+    char task_id[BUFFER_SIZE] = {0};
+
+    /* Login. */
+    size_t token_len = BUFFER_SIZE;
+    ret = login(token, &token_len);
+    if (ret != 0) {
+        fprintf(stderr, "[-] Failed to login.\n");
+        goto bail;
+    }
+
+    /* Connect to the frontend serivice. */
+    FrontendClient *frontend_client = teaclave_connect_frontend_service(
+        frontend_service_address, enclave_info_path, as_root_ca_cert_path);
+    if (frontend_client == NULL) {
+        fprintf(stderr, "[-] Failed to connect to the frontend service.\n");
+        ret = 1;
+        goto bail;
+    }
+
+    /* Set user id and token. */
+    ret = teaclave_set_credential(frontend_client, user_id, token);
+    if (ret != 0) {
+        fprintf(stderr, "[-] Failed to set credential.\n");
+        goto bail;
+    }
+
+    /* Register function. */
+    size_t serialized_response_len = BUFFER_SIZE;
+    ret = teaclave_register_function_serialized(
+        frontend_client, register_function_request_serialized,
+        serialized_response, &serialized_response_len);
+    if (ret != 0) {
+        fprintf(stderr, "[-] Failed to register the function.\n");
+        goto bail;
+    }
+
+    sscanf(serialized_response, "{\"function_id\":\"%45s", function_id);
+    printf("[+] function_id: %s\n", function_id);
+
+    /* Create task. */
+    snprintf(serialized_request, BUFFER_SIZE, create_task_request_serialized,
+             function_id);
+
+    memset(serialized_response, 0, BUFFER_SIZE);
+    ret = teaclave_create_task_serialized(frontend_client, serialized_request,
+                                          serialized_response,
+                                          &serialized_response_len);
+    if (ret != 0) {
+        fprintf(stderr, "[-] Failed to create a task.\n");
+        goto bail;
+    }
+
+    sscanf(serialized_response, "{\"task_id\":\"%41s", task_id);
+    printf("[+] task_id: %s\n", task_id);
+
+    /* Invoke task. */
+    ret = teaclave_invoke_task(frontend_client, task_id);
+    if (ret != 0) {
+        fprintf(stderr, "[-] Failed to invoke the task.\n");
+        goto bail;
+    }
+
+    /* Get task result. */
+    size_t task_result_len = BUFFER_SIZE;
+    ret = teaclave_get_task_result(frontend_client, task_id, task_result,
+                                   &task_result_len);
+    if (ret != 0) {
+        fprintf(stderr, "[-] Failed to get the task result.\n");
+        goto bail;
+    }
+
+    printf("[+] Task result in string: %s\n", task_result);
+
+bail:
+    ret = teaclave_close_frontend_service(frontend_client);
+    if (ret != 0) {
+        fprintf(stderr, "[-] Failed to close the frontend service client.\n");
+    }
+
+    return ret;
+}
diff --git a/sdk/c/Makefile b/sdk/c/Makefile
new file mode 100644
index 0000000..533ddb7
--- /dev/null
+++ b/sdk/c/Makefile
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+
+
+RUST_CLIENT_SDK_SOURCE:=$(wildcard ../rust/src/*.rs)
+
+all: $(RUST_CLIENT_SDK_SOURCE)
+       rustup run nightly cbindgen ../rust -c cbindgen.toml -o 
teaclave_client_sdk.h
diff --git a/sdk/c/cbindgen.toml b/sdk/c/cbindgen.toml
new file mode 100644
index 0000000..dfbe67a
--- /dev/null
+++ b/sdk/c/cbindgen.toml
@@ -0,0 +1,32 @@
+language = "C"
+
+header = """
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+"""
+
+autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated 
using cbindgen.
+ * To generate this file:
+ * 1. Get the latest cbindgen using `cargo install --force cbindgen`
+ * 2. Run `rustup run nightly cbindgen ../rust -c cbindgen.toml -o
+     teaclave_client_sdk.h` or `make`.
+ */"""
+
+[parse.expand]
+crates = ["teaclave-client-sdk"]
diff --git a/sdk/c/teaclave_client_sdk.h b/sdk/c/teaclave_client_sdk.h
new file mode 100644
index 0000000..96f40dd
--- /dev/null
+++ b/sdk/c/teaclave_client_sdk.h
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+
+/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen.
+ * To generate this file:
+ * 1. Get the latest cbindgen using `cargo install --force cbindgen`
+ * 2. Run `rustup run nightly cbindgen ../rust -c cbindgen.toml -o
+     teaclave_client_sdk.h` or `make`.
+ */
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct AuthenticationClient AuthenticationClient;
+
+typedef struct FrontendClient FrontendClient;
+
+struct AuthenticationClient *teaclave_connect_authentication_service(const 
char *address,
+                                                                     const 
char *enclave_info_path,
+                                                                     const 
char *as_root_ca_cert_path);
+
+int teaclave_close_authentication_service(struct AuthenticationClient *client);
+
+int teaclave_user_register(struct AuthenticationClient *client,
+                           const char *user_id,
+                           const char *user_password);
+
+int teaclave_user_login(struct AuthenticationClient *client,
+                        const char *user_id,
+                        const char *user_password,
+                        char *token,
+                        size_t *token_len);
+
+struct FrontendClient *teaclave_connect_frontend_service(const char *address,
+                                                         const char 
*enclave_info_path,
+                                                         const char 
*as_root_ca_cert_path);
+
+int teaclave_close_frontend_service(struct FrontendClient *client);
+
+int teaclave_set_credential(struct FrontendClient *client,
+                            const char *user_id,
+                            const char *user_token);
+
+int teaclave_invoke_task(struct FrontendClient *client, const char *task_id);
+
+int teaclave_get_task_result(struct FrontendClient *client,
+                             const char *task_id,
+                             char *task_result,
+                             size_t *task_result_len);
+
+int teaclave_user_register_serialized(struct AuthenticationClient *client,
+                                      const char *serialized_request,
+                                      char *serialized_response,
+                                      size_t *serialized_response_len);
+
+int teaclave_user_login_serialized(struct AuthenticationClient *client,
+                                   const char *serialized_request,
+                                   char *serialized_response,
+                                   size_t *serialized_response_len);
+
+int teaclave_register_function_serialized(struct FrontendClient *client,
+                                          const char *serialized_request,
+                                          char *serialized_response,
+                                          size_t *serialized_response_len);
+
+int teaclave_get_function_serialized(struct FrontendClient *client,
+                                     const char *serialized_request,
+                                     char *serialized_response,
+                                     size_t *serialized_response_len);
+
+int teaclave_register_input_file_serialized(struct FrontendClient *client,
+                                            const char *serialized_request,
+                                            char *serialized_response,
+                                            size_t *serialized_response_len);
+
+int teaclave_register_output_file_serialized(struct FrontendClient *client,
+                                             const char *serialized_request,
+                                             char *serialized_response,
+                                             size_t *serialized_response_len);
+
+int teaclave_create_task_serialized(struct FrontendClient *client,
+                                    const char *serialized_request,
+                                    char *serialized_response,
+                                    size_t *serialized_response_len);
+
+int teaclave_assign_data_serialized(struct FrontendClient *client,
+                                    const char *serialized_request,
+                                    char *serialized_response,
+                                    size_t *serialized_response_len);
+
+int teaclave_approve_task_serialized(struct FrontendClient *client,
+                                     const char *serialized_request,
+                                     char *serialized_response,
+                                     size_t *serialized_response_len);
+
+int teaclave_invoke_task_serialized(struct FrontendClient *client,
+                                    const char *serialized_request,
+                                    char *serialized_response,
+                                    size_t *serialized_response_len);
+
+int teaclave_get_task_serialized(struct FrontendClient *client,
+                                 const char *serialized_request,
+                                 char *serialized_response,
+                                 size_t *serialized_response_len);
diff --git a/sdk/rust/Cargo.toml b/sdk/rust/Cargo.toml
index 4264c17..a195685 100644
--- a/sdk/rust/Cargo.toml
+++ b/sdk/rust/Cargo.toml
@@ -6,6 +6,9 @@ description = "Teaclave Rust Client SDK"
 license = "Apache-2.0"
 edition = "2018"
 
+[lib]
+crate-type = ["lib", "cdylib", "staticlib"]
+
 [dependencies]
 teaclave_types = { path = "../../types", features = ["app"] }
 teaclave_attestation = { path = "../../attestation" }
@@ -13,4 +16,7 @@ teaclave_rpc = { path = "../../rpc" }
 teaclave_proto = { path = "../../services/proto" }
 anyhow       = { version = "1.0.26" }
 url          = { version = "2.1.1" }
+serde_json    = { version = "1.0.39" }
+serde         = { version = "1.0.92" }
 pem = "0.7.0"
+libc = "0.2.68"
diff --git a/sdk/rust/src/bindings.rs b/sdk/rust/src/bindings.rs
new file mode 100644
index 0000000..41386af
--- /dev/null
+++ b/sdk/rust/src/bindings.rs
@@ -0,0 +1,350 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+
+use libc::size_t;
+use std::ffi::CStr;
+use std::ffi::CString;
+use std::fs;
+use std::os::raw::c_char;
+use std::os::raw::c_int;
+use std::ptr;
+
+use crate::{
+    AuthenticationClient, AuthenticationService, EnclaveInfo, FrontendClient, 
FrontendService,
+};
+
+macro_rules! unwrap_or_return_null {
+    ( $e:expr ) => {
+        match $e {
+            Ok(x) => x,
+            Err(_) => return ptr::null_mut(),
+        }
+    };
+}
+
+macro_rules! unwrap_or_return_one {
+    ( $e:expr ) => {
+        match $e {
+            Ok(x) => x,
+            Err(_) => return 1,
+        }
+    };
+}
+
+#[no_mangle]
+pub extern "C" fn teaclave_connect_authentication_service(
+    address: *const c_char,
+    enclave_info_path: *const c_char,
+    as_root_ca_cert_path: *const c_char,
+) -> *mut AuthenticationClient {
+    if address.is_null() || enclave_info_path.is_null() || 
as_root_ca_cert_path.is_null() {
+        return ptr::null_mut();
+    }
+
+    let address = unsafe { 
CStr::from_ptr(address).to_string_lossy().into_owned() };
+    let enclave_info_path = unsafe {
+        CStr::from_ptr(enclave_info_path)
+            .to_string_lossy()
+            .into_owned()
+    };
+    let as_root_ca_cert_path = unsafe {
+        CStr::from_ptr(as_root_ca_cert_path)
+            .to_string_lossy()
+            .into_owned()
+    };
+    let enclave_info = 
unwrap_or_return_null!(EnclaveInfo::from_file(enclave_info_path));
+    let bytes = unwrap_or_return_null!(fs::read(as_root_ca_cert_path));
+    let as_root_ca_cert = unwrap_or_return_null!(pem::parse(bytes)).contents;
+    let client = unwrap_or_return_null!(AuthenticationService::connect(
+        &address,
+        &enclave_info,
+        &as_root_ca_cert
+    ));
+
+    Box::into_raw(Box::new(client))
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn teaclave_close_authentication_service(
+    client: *mut AuthenticationClient,
+) -> c_int {
+    if client.is_null() {
+        return 1;
+    }
+
+    Box::from_raw(client);
+
+    0
+}
+
+#[no_mangle]
+pub extern "C" fn teaclave_user_register(
+    client: &mut AuthenticationClient,
+    user_id: *const c_char,
+    user_password: *const c_char,
+) -> c_int {
+    if (client as *mut AuthenticationClient).is_null()
+        || user_id.is_null()
+        || user_password.is_null()
+    {
+        return 1;
+    }
+
+    let user_id = unsafe { 
CStr::from_ptr(user_id).to_string_lossy().into_owned() };
+    let user_password = unsafe { 
CStr::from_ptr(user_password).to_string_lossy().into_owned() };
+    unwrap_or_return_one!(client.user_register(&user_id, &user_password));
+
+    0
+}
+
+#[no_mangle]
+pub extern "C" fn teaclave_user_login(
+    client: &mut AuthenticationClient,
+    user_id: *const c_char,
+    user_password: *const c_char,
+    token: *mut c_char,
+    token_len: *mut size_t,
+) -> c_int {
+    if (client as *mut AuthenticationClient).is_null()
+        || user_id.is_null()
+        || user_password.is_null()
+        || token.is_null()
+        || token_len.is_null()
+    {
+        return 1;
+    }
+
+    let user_id = unsafe { 
CStr::from_ptr(user_id).to_string_lossy().into_owned() };
+    let user_password = unsafe { 
CStr::from_ptr(user_password).to_string_lossy().into_owned() };
+
+    let token_string = unwrap_or_return_one!(client.user_login(&user_id, 
&user_password));
+    let token_c_string = unwrap_or_return_one!(CString::new(token_string));
+    let bytes = token_c_string.as_bytes_with_nul();
+
+    unsafe {
+        if *token_len < bytes.len() {
+            return 1;
+        } else {
+            ptr::copy_nonoverlapping(bytes.as_ptr(), token as _, bytes.len());
+            *token_len = bytes.len();
+        }
+    }
+
+    0
+}
+
+#[no_mangle]
+pub extern "C" fn teaclave_connect_frontend_service(
+    address: *const c_char,
+    enclave_info_path: *const c_char,
+    as_root_ca_cert_path: *const c_char,
+) -> *mut FrontendClient {
+    if address.is_null() || enclave_info_path.is_null() || 
as_root_ca_cert_path.is_null() {
+        return ptr::null_mut();
+    }
+
+    let address = unsafe { 
CStr::from_ptr(address).to_string_lossy().into_owned() };
+    let enclave_info_path = unsafe {
+        CStr::from_ptr(enclave_info_path)
+            .to_string_lossy()
+            .into_owned()
+    };
+    let as_root_ca_cert_path = unsafe {
+        CStr::from_ptr(as_root_ca_cert_path)
+            .to_string_lossy()
+            .into_owned()
+    };
+    let enclave_info = 
unwrap_or_return_null!(EnclaveInfo::from_file(enclave_info_path));
+    let bytes = unwrap_or_return_null!(fs::read(as_root_ca_cert_path));
+    let as_root_ca_cert = unwrap_or_return_null!(pem::parse(bytes)).contents;
+    let client = unwrap_or_return_null!(FrontendService::connect(
+        &address,
+        &enclave_info,
+        &as_root_ca_cert
+    ));
+
+    Box::into_raw(Box::new(client))
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn teaclave_close_frontend_service(client: *mut 
FrontendClient) -> c_int {
+    if client.is_null() {
+        return 1;
+    }
+
+    Box::from_raw(client);
+
+    0
+}
+
+#[no_mangle]
+pub extern "C" fn teaclave_set_credential(
+    client: &mut FrontendClient,
+    user_id: *const c_char,
+    user_token: *const c_char,
+) -> c_int {
+    if (client as *mut FrontendClient).is_null() || user_id.is_null() || 
user_token.is_null() {
+        return 1;
+    }
+
+    let user_id = unsafe { 
CStr::from_ptr(user_id).to_string_lossy().into_owned() };
+    let user_token = unsafe { 
CStr::from_ptr(user_token).to_string_lossy().into_owned() };
+    client.set_credential(&user_id, &user_token);
+
+    0
+}
+
+#[no_mangle]
+pub extern "C" fn teaclave_invoke_task(
+    client: &mut FrontendClient,
+    task_id: *const c_char,
+) -> c_int {
+    if (client as *mut FrontendClient).is_null() || task_id.is_null() {
+        return 1;
+    }
+
+    let task_id = unsafe { 
CStr::from_ptr(task_id).to_string_lossy().into_owned() };
+    match client.invoke_task(&task_id) {
+        Ok(_) => 0,
+        Err(_) => 1,
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn teaclave_get_task_result(
+    client: &mut FrontendClient,
+    task_id: *const c_char,
+    task_result: *mut c_char,
+    task_result_len: *mut size_t,
+) -> c_int {
+    if (client as *mut FrontendClient).is_null() || task_id.is_null() {
+        return 1;
+    }
+
+    let task_id = unsafe { 
CStr::from_ptr(task_id).to_string_lossy().into_owned() };
+    match client.get_task_result(&task_id) {
+        Ok(result) => {
+            unsafe {
+                if *task_result_len < result.len() {
+                    return 1;
+                } else {
+                    ptr::copy_nonoverlapping(result.as_ptr(), task_result as 
_, result.len());
+                    *task_result_len = result.len();
+                }
+            }
+            0
+        }
+        Err(_) => 1,
+    }
+}
+
+macro_rules! generate_function_serialized {
+    ( $client_type:ident, $c_function_name:ident, $rust_function_name:ident) 
=> {
+        #[no_mangle]
+        pub extern "C" fn $c_function_name(
+            client: &mut $client_type,
+            serialized_request: *const c_char,
+            serialized_response: *mut c_char,
+            serialized_response_len: *mut size_t,
+        ) -> c_int {
+            if (client as *mut $client_type).is_null()
+                || serialized_request.is_null()
+                || serialized_response.is_null()
+                || serialized_response_len.is_null()
+            {
+                return 1;
+            }
+
+            let serialized_request = unsafe {
+                CStr::from_ptr(serialized_request)
+                    .to_string_lossy()
+                    .into_owned()
+            };
+            let function_id_string =
+                
unwrap_or_return_one!(client.$rust_function_name(&serialized_request));
+            let function_id_c_string = 
unwrap_or_return_one!(CString::new(function_id_string));
+            let bytes = function_id_c_string.as_bytes_with_nul();
+
+            unsafe {
+                if *serialized_response_len < bytes.len() {
+                    return 1;
+                } else {
+                    ptr::copy_nonoverlapping(bytes.as_ptr(), 
serialized_response as _, bytes.len());
+                    *serialized_response_len = bytes.len();
+                }
+            }
+
+            0
+        }
+    };
+}
+
+generate_function_serialized!(
+    AuthenticationClient,
+    teaclave_user_register_serialized,
+    user_register_serialized
+);
+generate_function_serialized!(
+    AuthenticationClient,
+    teaclave_user_login_serialized,
+    user_login_serialized
+);
+generate_function_serialized!(
+    FrontendClient,
+    teaclave_register_function_serialized,
+    register_function_serialized
+);
+generate_function_serialized!(
+    FrontendClient,
+    teaclave_get_function_serialized,
+    get_function_serialized
+);
+generate_function_serialized!(
+    FrontendClient,
+    teaclave_register_input_file_serialized,
+    register_input_file_serialized
+);
+generate_function_serialized!(
+    FrontendClient,
+    teaclave_register_output_file_serialized,
+    register_output_file_serialized
+);
+generate_function_serialized!(
+    FrontendClient,
+    teaclave_create_task_serialized,
+    create_task_serialized
+);
+generate_function_serialized!(
+    FrontendClient,
+    teaclave_assign_data_serialized,
+    assign_data_serialized
+);
+generate_function_serialized!(
+    FrontendClient,
+    teaclave_approve_task_serialized,
+    approve_task_serialized
+);
+generate_function_serialized!(
+    FrontendClient,
+    teaclave_invoke_task_serialized,
+    invoke_task_serialized
+);
+generate_function_serialized!(
+    FrontendClient,
+    teaclave_get_task_serialized,
+    get_task_serialized
+);
diff --git a/sdk/rust/src/lib.rs b/sdk/rust/src/lib.rs
index 7357d19..633b9ce 100644
--- a/sdk/rust/src/lib.rs
+++ b/sdk/rust/src/lib.rs
@@ -20,7 +20,9 @@ use std::collections::HashMap;
 use std::convert::TryInto;
 use teaclave_attestation::verifier;
 use 
teaclave_proto::teaclave_authentication_service::TeaclaveAuthenticationApiClient;
+use teaclave_proto::teaclave_authentication_service_proto as 
authentication_proto;
 use teaclave_proto::teaclave_frontend_service::TeaclaveFrontendClient;
+use teaclave_proto::teaclave_frontend_service_proto as frontend_proto;
 use teaclave_rpc::config::SgxTrustedTlsClientConfig;
 use teaclave_rpc::endpoint::Endpoint;
 use teaclave_types::FileAuthTag;
@@ -41,6 +43,8 @@ pub use teaclave_types::{
     EnclaveInfo, Executor, FileCrypto, FunctionInput, FunctionOutput, 
TaskResult,
 };
 
+pub mod bindings;
+
 pub struct AuthenticationClient {
     api_client: TeaclaveAuthenticationApiClient,
 }
@@ -61,6 +65,16 @@ impl AuthenticationClient {
         Ok(response)
     }
 
+    pub fn user_register_serialized(&mut self, serialized_request: &str) -> 
Result<String> {
+        let request: authentication_proto::UserRegisterRequest =
+            serde_json::from_str(serialized_request)?;
+        let response: authentication_proto::UserRegisterResponse =
+            self.user_register_with_request(request.try_into()?)?.into();
+        let serialized_response = serde_json::to_string(&response)?;
+
+        Ok(serialized_response)
+    }
+
     pub fn user_register(&mut self, user_id: &str, user_password: &str) -> 
Result<()> {
         let request = UserRegisterRequest::new(user_id, user_password);
         let _response = self.user_register_with_request(request)?;
@@ -77,6 +91,16 @@ impl AuthenticationClient {
         Ok(response)
     }
 
+    pub fn user_login_serialized(&mut self, serialized_request: &str) -> 
Result<String> {
+        let request: authentication_proto::UserLoginRequest =
+            serde_json::from_str(serialized_request)?;
+        let response: authentication_proto::UserLoginResponse =
+            self.user_login_with_request(request.try_into()?)?.into();
+        let serialized_response = serde_json::to_string(&response)?;
+
+        Ok(serialized_response)
+    }
+
     pub fn user_login(&mut self, user_id: &str, user_password: &str) -> 
Result<String> {
         let request = UserLoginRequest::new(user_id, user_password);
         let response = self.user_login_with_request(request)?;
@@ -106,6 +130,7 @@ impl AuthenticationService {
     }
 }
 
+#[repr(C)]
 pub struct FrontendService;
 
 impl FrontendService {
@@ -145,6 +170,17 @@ impl FrontendClient {
         self.api_client.set_metadata(metadata);
     }
 
+    pub fn register_function_serialized(&mut self, serialized_request: &str) 
-> Result<String> {
+        let request: frontend_proto::RegisterFunctionRequest =
+            serde_json::from_str(serialized_request)?;
+        let response: frontend_proto::RegisterFunctionResponse = self
+            .register_function_with_request(request.try_into()?)?
+            .into();
+        let serialized_response = serde_json::to_string(&response)?;
+
+        Ok(serialized_response)
+    }
+
     pub fn register_function_with_request(
         &mut self,
         request: RegisterFunctionRequest,
@@ -195,6 +231,15 @@ impl FrontendClient {
         Ok(response)
     }
 
+    pub fn get_function_serialized(&mut self, serialized_request: &str) -> 
Result<String> {
+        let request: frontend_proto::GetFunctionRequest = 
serde_json::from_str(serialized_request)?;
+        let response: frontend_proto::GetFunctionResponse =
+            self.get_function_with_request(request.try_into()?)?.into();
+        let serialized_response = serde_json::to_string(&response)?;
+
+        Ok(serialized_response)
+    }
+
     pub fn get_function(&mut self, function_id: &str) -> Result<Function> {
         let function_id = function_id.try_into()?;
         let request = GetFunctionRequest::new(function_id);
@@ -212,6 +257,17 @@ impl FrontendClient {
         Ok(response)
     }
 
+    pub fn register_input_file_serialized(&mut self, serialized_request: &str) 
-> Result<String> {
+        let request: frontend_proto::RegisterInputFileRequest =
+            serde_json::from_str(serialized_request)?;
+        let response: frontend_proto::RegisterInputFileResponse = self
+            .register_input_file_with_request(request.try_into()?)?
+            .into();
+        let serialized_response = serde_json::to_string(&response)?;
+
+        Ok(serialized_response)
+    }
+
     pub fn register_input_file(
         &mut self,
         url: &str,
@@ -235,6 +291,17 @@ impl FrontendClient {
         Ok(response)
     }
 
+    pub fn register_output_file_serialized(&mut self, serialized_request: 
&str) -> Result<String> {
+        let request: frontend_proto::RegisterOutputFileRequest =
+            serde_json::from_str(serialized_request)?;
+        let response: frontend_proto::RegisterOutputFileResponse = self
+            .register_output_file_with_request(request.try_into()?)?
+            .into();
+        let serialized_response = serde_json::to_string(&response)?;
+
+        Ok(serialized_response)
+    }
+
     pub fn register_output_file(&mut self, url: &str, file_crypto: FileCrypto) 
-> Result<String> {
         let url = Url::parse(url)?;
         let request = RegisterOutputFileRequest::new(url, file_crypto);
@@ -243,6 +310,15 @@ impl FrontendClient {
         Ok(response.data_id.to_string())
     }
 
+    pub fn create_task_serialized(&mut self, serialized_request: &str) -> 
Result<String> {
+        let request: frontend_proto::CreateTaskRequest = 
serde_json::from_str(serialized_request)?;
+        let response: frontend_proto::CreateTaskResponse =
+            self.create_task_with_request(request.try_into()?)?.into();
+        let serialized_response = serde_json::to_string(&response)?;
+
+        Ok(serialized_response)
+    }
+
     pub fn create_task_with_request(
         &mut self,
         request: CreateTaskRequest,
@@ -302,6 +378,15 @@ impl FrontendClient {
         Ok(response)
     }
 
+    pub fn assign_data_serialized(&mut self, serialized_request: &str) -> 
Result<String> {
+        let request: frontend_proto::AssignDataRequest = 
serde_json::from_str(serialized_request)?;
+        let response: frontend_proto::AssignDataResponse =
+            self.assign_data_with_request(request.try_into()?)?.into();
+        let serialized_response = serde_json::to_string(&response)?;
+
+        Ok(serialized_response)
+    }
+
     pub fn assign_data(
         &mut self,
         task_id: &str,
@@ -343,6 +428,15 @@ impl FrontendClient {
         Ok(())
     }
 
+    pub fn approve_task_serialized(&mut self, serialized_request: &str) -> 
Result<String> {
+        let request: frontend_proto::ApproveTaskRequest = 
serde_json::from_str(serialized_request)?;
+        let response: frontend_proto::ApproveTaskResponse =
+            self.approve_task_with_request(request.try_into()?)?.into();
+        let serialized_response = serde_json::to_string(&response)?;
+
+        Ok(serialized_response)
+    }
+
     pub fn invoke_task_with_request(
         &mut self,
         request: InvokeTaskRequest,
@@ -352,6 +446,15 @@ impl FrontendClient {
         Ok(response)
     }
 
+    pub fn invoke_task_serialized(&mut self, serialized_request: &str) -> 
Result<String> {
+        let request: frontend_proto::InvokeTaskRequest = 
serde_json::from_str(serialized_request)?;
+        let response: frontend_proto::InvokeTaskResponse =
+            self.invoke_task_with_request(request.try_into()?)?.into();
+        let serialized_response = serde_json::to_string(&response)?;
+
+        Ok(serialized_response)
+    }
+
     pub fn invoke_task(&mut self, task_id: &str) -> Result<()> {
         let request = InvokeTaskRequest::new(task_id.try_into()?);
         let _ = self.invoke_task_with_request(request)?;
@@ -365,6 +468,15 @@ impl FrontendClient {
         Ok(response)
     }
 
+    pub fn get_task_serialized(&mut self, serialized_request: &str) -> 
Result<String> {
+        let request: frontend_proto::GetTaskRequest = 
serde_json::from_str(serialized_request)?;
+        let response: frontend_proto::GetTaskResponse =
+            self.get_task_with_request(request.try_into()?)?.into();
+        let serialized_response = serde_json::to_string(&response)?;
+
+        Ok(serialized_response)
+    }
+
     pub fn get_task_result(&mut self, task_id: &str) -> Result<Vec<u8>> {
         loop {
             let request = GetTaskRequest::new(task_id.try_into()?);


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to