You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@teaclave.apache.org by ms...@apache.org on 2022/01/26 18:55:37 UTC

[incubator-teaclave] branch master updated: Update Rust and C API for cancel_task, fix task status updating (#601)

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 9c6c94f  Update Rust and C API for cancel_task, fix task status updating (#601)
9c6c94f is described below

commit 9c6c94f827097e10de044d1cdfedf0cab2a80a33
Author: Hongbo <12...@users.noreply.github.com>
AuthorDate: Wed Jan 26 10:55:30 2022 -0800

    Update Rust and C API for cancel_task, fix task status updating (#601)
---
 sdk/c/teaclave_client_sdk.h                  | 136 +++++++++++++++++++++++++--
 sdk/payload/wasm/teaclave_context/Cargo.lock |   7 ++
 sdk/rust/src/bindings.rs                     |  27 ++++++
 sdk/rust/src/lib.rs                          |  86 +++++++++++++++--
 services/management/enclave/src/service.rs   |   9 +-
 5 files changed, 250 insertions(+), 15 deletions(-)

diff --git a/sdk/c/teaclave_client_sdk.h b/sdk/c/teaclave_client_sdk.h
index 22a6d5b..affaa62 100644
--- a/sdk/c/teaclave_client_sdk.h
+++ b/sdk/c/teaclave_client_sdk.h
@@ -52,6 +52,10 @@ typedef struct FrontendClient FrontendClient;
  *
  * * The function returns an opaque pointer (handle) of the service. On error,
  * the function returns NULL.
+ *
+ * # Safety
+ *
+ * `address`, `enclave_info_path`, `as_root_ca_cert_path` should be C string (null terminated).
  */
 struct AuthenticationClient *teaclave_connect_authentication_service(const char *address,
                                                                      const char *enclave_info_path,
@@ -61,12 +65,22 @@ struct AuthenticationClient *teaclave_connect_authentication_service(const char
  * Close and free the authentication service handle, i.e., the
  * `AuthenticaionClient` type opaque pointer. The function returns 0 for
  * success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * This function is unsafe because improper use may lead to
+ * memory problems. For example, a double-free may occur if the
+ * function is called twice on the same raw pointer.
  */
 int teaclave_close_authentication_service(struct AuthenticationClient *client);
 
 /**
  * Register a new user with `user_id` and `user_password`. The function returns
  * 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * `user_id`, `user_password`, `role`, `attribute` should be C string (null terminated).
  */
 int teaclave_user_register(struct AuthenticationClient *client,
                            const char *user_id,
@@ -79,6 +93,10 @@ int teaclave_user_register(struct AuthenticationClient *client,
  * will be save in the `token` buffer, and length will be set in the
  * `token_len` argument. The function returns 0 for success. On error, the
  * function returns 1.
+ *
+ * # Safety
+ *
+ * `user_id`, `user_password` should be C string (null terminated), token and token_len should be consistent.
  */
 int teaclave_user_login(struct AuthenticationClient *client,
                         const char *user_id,
@@ -104,6 +122,10 @@ int teaclave_user_login(struct AuthenticationClient *client,
  *
  * * The function returns an opaque pointer (handle) of the service. On error,
  * the function returns NULL.
+ *
+ * # Safety
+ *
+ * All arguments should be C string (null terminated).
  */
 struct FrontendClient *teaclave_connect_frontend_service(const char *address,
                                                          const char *enclave_info_path,
@@ -113,36 +135,68 @@ struct FrontendClient *teaclave_connect_frontend_service(const char *address,
  * Close and free the frontend service handle, i.e., the `FrontendClient` type
  * opaque pointer. The function returns 0 for success. On error, the function
  * returns 1.
+ *
+ * # Safety
+ *
+ * This function is unsafe because improper use may lead to
+ * memory problems. For example, a double-free may occur if the
+ * function is called twice on the same raw pointer.
  */
 int teaclave_close_frontend_service(struct FrontendClient *client);
 
 /**
  * Set user's credential with `user_id` and `user_token`. The function returns
  * 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * `user_id` and `user_token` should be C string (null terminated).
  */
-int teaclave_frontend_set_credential(struct FrontendClient *client,
-                            const char *user_id,
-                            const char *user_token);
+int teaclave_authentication_set_credential(struct AuthenticationClient *client,
+                                           const char *user_id,
+                                           const char *user_token);
 
 /**
  * Set user's credential with `user_id` and `user_token`. The function returns
  * 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * `user_id` and `user_token` should be C string (null terminated).
  */
-int teaclave_authentication_set_credential(struct AuthenticationClient *client,
-                                const char *user_id,
-                                const char *user_token);
+int teaclave_frontend_set_credential(struct FrontendClient *client,
+                                     const char *user_id,
+                                     const char *user_token);
 
 /**
  * Invoke task with `task_id`. The function returns 0 for success. On error,
  * the function returns 1.
+ *
+ * # Safety
+ *
+ * `task_id` should be C string (null terminated).
  */
 int teaclave_invoke_task(struct FrontendClient *client, const char *task_id);
 
 /**
+ * Cancel task with `task_id`. The function returns 0 for success. On error,
+ * the function returns 1.
+ *
+ * # Safety
+ *
+ * `task_id` should be C string (null terminated).
+ */
+int teaclave_cancel_task(struct FrontendClient *client, const char *task_id);
+
+/**
  * Get task result of `task_id`. The result will be save in the `task_result`
  * buffer, and set corresponding `task_result_len` argument. Note that this is
  * a blocking function and wait for the return of the task. The function
  * returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
  */
 int teaclave_get_task_result(struct FrontendClient *client,
                              const char *task_id,
@@ -165,6 +219,10 @@ int teaclave_get_task_result(struct FrontendClient *client,
  * # Return
  *
  * The function returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
  */
 int teaclave_user_register_serialized(struct AuthenticationClient *client,
                                       const char *serialized_request,
@@ -187,6 +245,10 @@ int teaclave_user_register_serialized(struct AuthenticationClient *client,
  * # Return
  *
  * The function returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
  */
 int teaclave_user_login_serialized(struct AuthenticationClient *client,
                                    const char *serialized_request,
@@ -209,6 +271,10 @@ int teaclave_user_login_serialized(struct AuthenticationClient *client,
  * # Return
  *
  * The function returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
  */
 int teaclave_register_function_serialized(struct FrontendClient *client,
                                           const char *serialized_request,
@@ -231,6 +297,10 @@ int teaclave_register_function_serialized(struct FrontendClient *client,
  * # Return
  *
  * The function returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
  */
 int teaclave_get_function_serialized(struct FrontendClient *client,
                                      const char *serialized_request,
@@ -253,6 +323,10 @@ int teaclave_get_function_serialized(struct FrontendClient *client,
  * # Return
  *
  * The function returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
  */
 int teaclave_register_input_file_serialized(struct FrontendClient *client,
                                             const char *serialized_request,
@@ -275,6 +349,10 @@ int teaclave_register_input_file_serialized(struct FrontendClient *client,
  * # Return
  *
  * The function returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
  */
 int teaclave_register_output_file_serialized(struct FrontendClient *client,
                                              const char *serialized_request,
@@ -297,6 +375,10 @@ int teaclave_register_output_file_serialized(struct FrontendClient *client,
  * # Return
  *
  * The function returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
  */
 int teaclave_create_task_serialized(struct FrontendClient *client,
                                     const char *serialized_request,
@@ -319,6 +401,10 @@ int teaclave_create_task_serialized(struct FrontendClient *client,
  * # Return
  *
  * The function returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
  */
 int teaclave_assign_data_serialized(struct FrontendClient *client,
                                     const char *serialized_request,
@@ -341,6 +427,10 @@ int teaclave_assign_data_serialized(struct FrontendClient *client,
  * # Return
  *
  * The function returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
  */
 int teaclave_approve_task_serialized(struct FrontendClient *client,
                                      const char *serialized_request,
@@ -363,6 +453,10 @@ int teaclave_approve_task_serialized(struct FrontendClient *client,
  * # Return
  *
  * The function returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
  */
 int teaclave_invoke_task_serialized(struct FrontendClient *client,
                                     const char *serialized_request,
@@ -385,6 +479,36 @@ int teaclave_invoke_task_serialized(struct FrontendClient *client,
  * # Return
  *
  * The function returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
+ */
+int teaclave_cancel_task_serialized(struct FrontendClient *client,
+                                    const char *serialized_request,
+                                    char *serialized_response,
+                                    size_t *serialized_response_len);
+
+/**
+ * Send JSON serialized request to the service with the `client` and
+ * get the serialized response.
+ *
+ * # Arguments
+ *
+ * * `client`: service client.
+ * * `serialized_request`; JSON serialized request
+ * * `serialized_response`: buffer to store the JSON serialized response.
+ * * `serialized_response_len`: length of the allocated
+ *   `serialized_response`, will be set as the length of
+ *   `serialized_response` when return successfully.
+ *
+ * # Return
+ *
+ * The function returns 0 for success. On error, the function returns 1.
+ *
+ * # Safety
+ *
+ * Inconsistent length of allocated buffer may caused overflow.
  */
 int teaclave_get_task_serialized(struct FrontendClient *client,
                                  const char *serialized_request,
diff --git a/sdk/payload/wasm/teaclave_context/Cargo.lock b/sdk/payload/wasm/teaclave_context/Cargo.lock
new file mode 100644
index 0000000..f2bb38c
--- /dev/null
+++ b/sdk/payload/wasm/teaclave_context/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "teaclave_context"
+version = "0.2.0"
diff --git a/sdk/rust/src/bindings.rs b/sdk/rust/src/bindings.rs
index 4ca54ba..e7a7297 100644
--- a/sdk/rust/src/bindings.rs
+++ b/sdk/rust/src/bindings.rs
@@ -328,6 +328,28 @@ pub unsafe extern "C" fn teaclave_invoke_task(
     }
 }
 
+/// Cancel task with `task_id`. The function returns 0 for success. On error,
+/// the function returns 1.
+///
+/// # Safety
+///
+/// `task_id` should be C string (null terminated).
+#[no_mangle]
+pub unsafe extern "C" fn teaclave_cancel_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 = CStr::from_ptr(task_id).to_string_lossy().into_owned();
+    match client.invoke_task(&task_id) {
+        Ok(_) => 0,
+        Err(_) => 1,
+    }
+}
+
 /// Get task result of `task_id`. The result will be save in the `task_result`
 /// buffer, and set corresponding `task_result_len` argument. Note that this is
 /// a blocking function and wait for the return of the task. The function
@@ -470,6 +492,11 @@ generate_function_serialized!(
 );
 generate_function_serialized!(
     FrontendClient,
+    teaclave_cancel_task_serialized,
+    cancel_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 78d6c69..69c9f3a 100644
--- a/sdk/rust/src/lib.rs
+++ b/sdk/rust/src/lib.rs
@@ -34,10 +34,11 @@ pub use teaclave_proto::teaclave_authentication_service::{
 pub use teaclave_proto::teaclave_frontend_service::GetFunctionResponse as Function;
 pub use teaclave_proto::teaclave_frontend_service::{
     ApproveTaskRequest, ApproveTaskResponse, AssignDataRequest, AssignDataResponse,
-    CreateTaskRequest, CreateTaskResponse, GetFunctionRequest, GetFunctionResponse, GetTaskRequest,
-    GetTaskResponse, InvokeTaskRequest, InvokeTaskResponse, RegisterFunctionRequest,
-    RegisterFunctionRequestBuilder, RegisterFunctionResponse, RegisterInputFileRequest,
-    RegisterInputFileResponse, RegisterOutputFileRequest, RegisterOutputFileResponse,
+    CancelTaskRequest, CancelTaskResponse, CreateTaskRequest, CreateTaskResponse,
+    GetFunctionRequest, GetFunctionResponse, GetTaskRequest, GetTaskResponse, InvokeTaskRequest,
+    InvokeTaskResponse, RegisterFunctionRequest, RegisterFunctionRequestBuilder,
+    RegisterFunctionResponse, RegisterInputFileRequest, RegisterInputFileResponse,
+    RegisterOutputFileRequest, RegisterOutputFileResponse,
 };
 pub use teaclave_types::{
     EnclaveInfo, Executor, FileCrypto, FunctionInput, FunctionOutput, TaskResult,
@@ -498,13 +499,44 @@ impl FrontendClient {
         loop {
             let request = GetTaskRequest::new(task_id.try_into()?);
             let response = self.get_task_with_request(request)?;
-            if let TaskResult::Ok(task_outputs) = response.result {
-                return Ok(task_outputs.return_value);
+            match response.result {
+                TaskResult::NotReady => {
+                    std::thread::sleep(std::time::Duration::from_secs(1));
+                }
+                TaskResult::Ok(task_outputs) => {
+                    return Ok(task_outputs.return_value);
+                }
+                TaskResult::Err(task_error) => {
+                    return Err(anyhow::anyhow!(task_error.reason));
+                }
             }
-            let one_second = std::time::Duration::from_secs(1);
-            std::thread::sleep(one_second);
         }
     }
+
+    pub fn cancel_task_with_request(
+        &mut self,
+        request: CancelTaskRequest,
+    ) -> Result<CancelTaskResponse> {
+        let response = self.api_client.cancel_task(request)?;
+
+        Ok(response)
+    }
+
+    pub fn cancel_task_serialized(&mut self, serialized_request: &str) -> Result<String> {
+        let request: frontend_proto::CancelTaskRequest = serde_json::from_str(serialized_request)?;
+        let response: frontend_proto::CancelTaskResponse =
+            self.cancel_task_with_request(request.try_into()?)?.into();
+        let serialized_response = serde_json::to_string(&response)?;
+
+        Ok(serialized_response)
+    }
+
+    pub fn cancel_task(&mut self, task_id: &str) -> Result<()> {
+        let request = CancelTaskRequest::new(task_id.try_into()?);
+        let _ = self.cancel_task_with_request(request)?;
+
+        Ok(())
+    }
 }
 
 #[cfg(test)]
@@ -741,4 +773,42 @@ mod tests {
         client.assign_data(&task_id, None, Some(outputs)).unwrap();
         client.approve_task(&task_id).unwrap();
     }
+
+    #[test]
+    fn test_cancel_task() {
+        let enclave_info = EnclaveInfo::from_file(ENCLAVE_INFO_PATH).unwrap();
+        let bytes = fs::read(AS_ROOT_CA_CERT_PATH).unwrap();
+        let as_root_ca_cert = pem::parse(bytes).unwrap().contents;
+        let mut client =
+            AuthenticationService::connect("localhost:7776", &enclave_info, &as_root_ca_cert)
+                .unwrap();
+        let token = client.user_login(ADMIN_ID, ADMIN_PASSWORD).unwrap();
+        client.set_credential(ADMIN_ID, &token);
+        let _ = client.user_register(USER_ID, USER_PASSWORD, "PlatformAdmin", "");
+        let token = client.user_login(USER_ID, USER_PASSWORD).unwrap();
+
+        let mut client =
+            FrontendService::connect("localhost:7777", &enclave_info, &as_root_ca_cert).unwrap();
+        client.set_credential(USER_ID, &token);
+        let function_id = "function-00000000-0000-0000-0000-000000000002";
+        let function_arguments = hashmap!("arg1" => "arg1_value");
+        let outputs_ownership = hashmap!("output" => vec![USER_ID.to_string()]);
+        let task_id = client
+            .create_task(
+                &function_id,
+                Some(function_arguments),
+                "mesapy",
+                None,
+                Some(outputs_ownership),
+            )
+            .unwrap();
+
+        print!("SDK DEBUG: task created");
+
+        let result = client.cancel_task(&task_id);
+        print!("SDK DEBUG: canceled, {:?}", result);
+
+        let task = client.get_task_result(&task_id);
+        assert!(task.is_err());
+    }
 }
diff --git a/services/management/enclave/src/service.rs b/services/management/enclave/src/service.rs
index 0293450..294abe2 100644
--- a/services/management/enclave/src/service.rs
+++ b/services/management/enclave/src/service.rs
@@ -662,17 +662,24 @@ impl TeaclaveManagement for TeaclaveManagementService {
                 self.enqueue_to_db(CANCEL_QUEUE_KEY.as_bytes(), &ts)?;
             }
             _ => {
+                // early cancelation
                 // race will not affect correctness/privacy
-                let task: Task<Cancel> = ts.try_into().map_err(|e| {
+                let mut task: Task<Cancel> = ts.try_into().map_err(|e| {
                     log::warn!("Cancel state error: {:?}", e);
                     TeaclaveManagementServiceError::PermissionDenied
                 })?;
 
                 log::debug!("Canceled Task: {:?}", task);
 
+                task.update_result(TaskResult::Err(TaskFailure {
+                    reason: "Task canceled".to_string(),
+                }))
+                .map_err(|_| TeaclaveManagementServiceError::PermissionDenied)?;
                 let ts: TaskState = task.into();
                 self.write_to_db(&ts)
                     .map_err(|_| TeaclaveManagementServiceError::StorageError)?;
+
+                log::warn!("Canceled Task: writtenback");
             }
         }
 

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org