dbus ws: add reply error and send signal [1/1]

PD#SWPL-187465

Problem:
add reply error and send signal

Solution:
add reply error and send signal

Verify:
local

Change-Id: Ibc481165c911ab7fcdf061a4bc7068491bfee01a
Signed-off-by: Daogao Xu <daogao.xu@amlogic.com>
diff --git a/aml_dbus_ws_br/jsonrpc-dbus.c b/aml_dbus_ws_br/jsonrpc-dbus.c
index f9cc25e..fd4dfc2 100644
--- a/aml_dbus_ws_br/jsonrpc-dbus.c
+++ b/aml_dbus_ws_br/jsonrpc-dbus.c
@@ -73,7 +73,7 @@
 
 struct dbus_object_method {
   struct dbus_object_method *next;
-  sd_bus_message *reply;
+  sd_bus_message *msg_call;
   struct dbus_maches *match;
   uint64_t cookie;
 };
@@ -642,9 +642,8 @@
   struct dbus_maches *c = (struct dbus_maches *)userdata;
   struct json_rpc_handle *jrpc = c->jrpc;
   uint64_t cookie = 0LL;
-  sd_bus_message *reply = NULL;
-  if (sd_bus_message_get_cookie(m, &cookie) < 0 || sd_bus_message_new_method_return(m, &reply) < 0) {
-    lwsl_info("object msg fail to get cookie or reply\n");
+  if (sd_bus_message_get_cookie(m, &cookie) < 0) {
+    lwsl_info("object msg fail to get cookie\n");
     return 0;
   }
   int len = jrpc_append_reply(jrpc,
@@ -661,7 +660,7 @@
   struct dbus_object_method *om = malloc(sizeof(*om));
   om->next = jrpc->pending_object_call;
   om->cookie = cookie;
-  om->reply = reply;
+  om->msg_call = sd_bus_message_ref(m);
   om->match = c;
   jrpc->pending_object_call = om;
   return 1;
@@ -689,39 +688,52 @@
 
 static int json_rpc_call_send_reply(struct json_rpc_handle *jrpc, uint64_t id, struct json_value_base *params) {
   struct json_value_base *jv_cookie = lws_json_object_get(params, "cookie");
-  struct json_value_base *jv_sig = lws_json_object_get(params, "signature");
-  struct json_value_base *jv_data = lws_json_object_get(params, "data");
-  if (jv_cookie == NULL || jv_cookie->type != json_vt_string) {
+  if (jv_cookie == NULL || jv_cookie->type != json_vt_string)
     goto not_found;
+  uint64_t cookie = strtoull(JV_CAST(string, jv_cookie)->val, NULL, 0);
+  struct dbus_object_method *om = jrpc->pending_object_call, *prev = NULL;
+  for (; om && om->cookie != cookie; prev = om, om = om->next)
+    ;
+  if (om == NULL)
+    goto not_found;
+  if (prev)
+    prev->next = om->next;
+  else
+    jrpc->pending_object_call = om->next;
+  int r;
+  sd_bus_message *reply = NULL;
+  struct json_value_base *jv_error = lws_json_object_get(params, "error");
+  sd_bus_error err;
+  if (jv_error && jv_error->type == json_vt_string) {
+    struct json_value_base *jv_msg = lws_json_object_get(params, "message");
+    const char *err_name = JV_CAST(string, jv_error)->val;
+    const char *err_msg = (jv_msg && jv_msg->type == json_vt_string) ? JV_CAST(string, jv_msg)->val : NULL;
+    err = SD_BUS_ERROR_MAKE_CONST(err_name, err_msg);
+    r = sd_bus_message_new_method_error(om->msg_call, &reply, &err);
   } else {
-    uint64_t cookie = strtoull(JV_CAST(string, jv_cookie)->val, NULL, 0);
-    struct dbus_object_method *om = jrpc->pending_object_call, *prev = NULL;
-    for (; om && om->cookie != cookie; prev = om, om = om->next)
-      ;
-    if (om == NULL)
-      goto not_found;
-    if (prev)
-      prev->next = om->next;
-    else
-      jrpc->pending_object_call = om->next;
-    int r;
-    if (jv_sig && jv_sig->type == json_vt_string && jv_data) {
+    r = sd_bus_message_new_method_return(om->msg_call, &reply);
+    struct json_value_base *jv_sig = lws_json_object_get(params, "signature");
+    struct json_value_base *jv_data = lws_json_object_get(params, "data");
+    if (r >= 0 && jv_sig && jv_sig->type == json_vt_string && jv_data) {
       const char *sig = JV_CAST(string, jv_sig)->val;
-      r = msg_from_json(om->reply, sig, jv_data);
+      r = msg_from_json(reply, sig, jv_data);
       if (r < 0) {
         lwsl_warn("fail to create dbus message with sig %s from json (%d %s):\n", sig, r, strerror(-r));
         lws_json_val_dump(stderr, jv_data, 0);
-        goto param_error;
       }
     }
-    r = sd_bus_send(jrpc->bus, om->reply, NULL);
-    if (r < 0)
-      json_rpc_reply_error(jrpc, id, -32603, strerror(-r));
-    else
-      json_rpc_reply_simple(jrpc, id, "%d", 0);
-    sd_bus_message_unref(om->reply);
-    free(om);
   }
+  sd_bus_message_unref(om->msg_call);
+  if (r >= 0 && reply) {
+    r = sd_bus_send(jrpc->bus, reply, NULL);
+  }
+  if (reply)
+    sd_bus_message_unref(reply);
+  if (r < 0)
+    json_rpc_reply_error(jrpc, id, -32603, strerror(-r));
+  else
+    json_rpc_reply_simple(jrpc, id, "%d", 0);
+  free(om);
   return 0;
 not_found:
   json_rpc_reply_error(jrpc, id, -32603, "sendReply cookie not found");
@@ -731,6 +743,46 @@
   return 0;
 }
 
+static int json_rpc_call_send_signal(struct json_rpc_handle *jrpc, uint64_t id, struct json_value_base *params) {
+  char errmsg[256];
+  struct json_value_base *jv_path = lws_json_object_get(params, "path");
+  struct json_value_base *jv_intf = lws_json_object_get(params, "interface");
+  struct json_value_base *jv_mem = lws_json_object_get(params, "member");
+  if (jv_path == NULL || jv_path->type != json_vt_string || jv_intf == NULL || jv_intf->type != json_vt_string ||
+      jv_mem == NULL || jv_mem->type != json_vt_string) {
+    goto param_error;
+  }
+  sd_bus_message *m = NULL;
+  int r = sd_bus_message_new_signal(jrpc->bus, &m, JV_CAST(string, jv_path)->val, JV_CAST(string, jv_intf)->val,
+                                    JV_CAST(string, jv_mem)->val);
+  if (r < 0) {
+    goto param_error;
+  }
+  struct json_value_base *jv_sig = lws_json_object_get(params, "signature");
+  struct json_value_base *jv_data = lws_json_object_get(params, "data");
+  if (jv_sig && jv_sig->type == json_vt_string && jv_data) {
+    const char *sig = JV_CAST(string, jv_sig)->val;
+    r = msg_from_json(m, sig, jv_data);
+    if (r < 0) {
+      lwsl_warn("fail to create dbus message with sig %s from json (%d %s):\n", sig, r, strerror(-r));
+      lws_json_val_dump(stderr, jv_data, 0);
+    }
+  }
+  if (r >= 0 && m) {
+    r = sd_bus_send(jrpc->bus, m, NULL);
+  }
+  if (m)
+    sd_bus_message_unref(m);
+  if (r < 0)
+    json_rpc_reply_error(jrpc, id, -32603, strerror(-r));
+  else
+    json_rpc_reply_simple(jrpc, id, "%d", 0);
+  return 0;
+param_error:
+  json_rpc_reply_error(jrpc, id, -32603, "sendSignal must provide valid path interface member");
+  return 0;
+}
+
 static int json_rpc_call_remove_match(struct json_rpc_handle *jrpc, uint64_t id, uint64_t seq) {
   struct dbus_maches *c = jrpc->matches, *prev = NULL;
   for (; c && c->seq != seq; prev = c, c = c->next)
@@ -787,6 +839,8 @@
     return json_rpc_call_remove_match(jrpc, id_val, JV_CAST(int, params)->val);
   } else if (strcmp(method_str, "sendReply") == 0 && params) {
     return json_rpc_call_send_reply(jrpc, id_val, params);
+  } else if (strcmp(method_str, "sendSignal") == 0 && params) {
+    return json_rpc_call_send_signal(jrpc, id_val, params);
   }
 
   char *dst = strtok_r(method_str, " ", &savedptr);
@@ -856,8 +910,8 @@
   }
   for (struct dbus_object_method *c = jrpc->pending_object_call, *n; c; c = n) {
     n = c->next;
-    if (c->reply)
-      sd_bus_message_unref(c->reply);
+    if (c->msg_call)
+      sd_bus_message_unref(c->msg_call);
     free(c);
   }
   free(jrpc);