1 /*******************************************************************************
2 * Copyright 2020 Samsung Electronics All Rights Reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 *******************************************************************************/
18 #include "orchestration_dbus_server.h"
24 #include "gdbus_interface.h"
26 static _gdbus_interface _gdbus;
28 static guint owner_id;
29 static GDBusConnection *_gdbus_conn;
30 static GDBusNodeInfo *introspection_data = NULL;
32 request_service_func _request_service_cb = NULL;
33 request_service_on_device_func _request_service_on_device_cb = NULL;
34 update_key_pair_func _update_key_pair_cb = NULL;
35 get_device_list_func _get_device_list_cb = NULL;
36 read_device_capability_func _read_device_capability_cb = NULL;
37 write_device_capability_func _write_device_capability_cb = NULL;
39 #define _ORCHESTRATION_BUS_NAME "org.tizen.orchestration"
40 #define _ORCHESTRATION_OBJECT_PATH "/org/tizen/orchestration"
43 static int _request_service(GVariant *parameters, int origin_client_pid);
44 static int _request_service_on_device(GVariant *parameters, int origin_client_pid);
45 static int _update_key_pair(GVariant *parameters, int origin_client_pid);
46 static int _get_device_list(GVariant *parameters, int origin_client_pid, char **ipaddr_list, char **message);
47 static int _read_device_capability(GVariant *parameters, int origin_client_pid, char **capability, char **message);
48 static int _write_device_capability(GVariant *parameters, int origin_client_pid, char **write_result);
49 static int get_process_name_by_pid(char* process_name, int pid);
50 static int get_pid_with_connection(const gchar* sender);
51 static int _get_sync(void);
52 static int _set_node_info_new_for_xml(void);
53 static int _connection_register_object(void);
54 static int _own_name_on_connection(void);
55 static int orch_dbus_initialize(void);
56 static void _handle_method_call(
57 GDBusConnection *connection,
59 const gchar *object_path,
60 const gchar *interface_name,
61 const gchar *method_name,
63 GDBusMethodInvocation *invocation,
66 static const GDBusInterfaceVTable _interface_vtable =
73 /* Introspection data for the service we are exporting */
74 static gchar introspection_xml[] =
76 " <interface name='org.tizen.orchestration.agent'>"
77 " <method name='request_service'>"
78 " <arg type='s' name='app_name' direction='in'/>"
79 " <arg type='i' name='self_select' direction='in'/>"
80 " <arg type='a(ss)' name='service_info' direction='in'/>"
81 " <arg type='i' name='count' direction='in'/>"
82 " <arg type='i' name='client_pid' direction='in'/>"
83 " <arg type='i' name='return_value' direction='out'/>"
85 " <method name='request_service_on_device'>"
86 " <arg type='s' name='app_name' direction='in'/>"
87 " <arg type='i' name='self_select' direction='in'/>"
88 " <arg type='a(ss)' name='service_info' direction='in'/>"
89 " <arg type='s' name='ip' direction='in'/>"
90 " <arg type='i' name='count' direction='in'/>"
91 " <arg type='i' name='client_pid' direction='in'/>"
92 " <arg type='i' name='return_value' direction='out'/>"
94 " <method name='update_key_pair'>"
95 " <arg type='s' name='id' direction='in'/>"
96 " <arg type='s' name='key' direction='in'/>"
97 " <arg type='i' name='client_pid' direction='in'/>"
98 " <arg type='i' name='return_value' direction='out'/>"
100 " <method name='get_device_list'>"
101 " <arg type='s' name='service_name' direction='in'/>"
102 " <arg type='s' name='exec_type' direction='in'/>"
103 " <arg type='i' name='client_pid' direction='in'/>"
104 " <arg type='(asis)' name='return_value' direction='out'/>"
106 " <method name='read_capability'>"
107 " <arg type='s' name='ip' direction='in'/>"
108 " <arg type='i' name='client_pid' direction='in'/>"
109 " <arg type='(ss)' name='return_value' direction='out'/>"
111 " <method name='write_capability'>"
112 " <arg type='s' name='capability' direction='in'/>"
113 " <arg type='i' name='client_pid' direction='in'/>"
114 " <arg type='i' name='return_value' direction='out'/>"
118 /* ---------------------------------------------------------------------------------------------------- */
120 #define _FREEDESKTOP_BUS_NAME "org.freedesktop.DBus"
121 #define _FREEDESKTOP_OBJECT_PATH "/org/freedesktop/DBus"
122 #define _FREEDESKTOP_INTERFACE "org.freedesktop.DBus"
123 #define _FREEDESKTOP_GETPROCESSID_METHOD "GetConnectionUnixProcessID"
125 void set_default_dbus_interface(void)
127 _gdbus.get_sync = g_bus_get_sync;
128 _gdbus.own_name_on_connection = g_bus_own_name_on_connection;
129 _gdbus.unown_name = g_bus_unown_name;
130 _gdbus.node_info_new_for_xml = g_dbus_node_info_new_for_xml;
131 _gdbus.node_info_unref = g_dbus_node_info_unref;
132 _gdbus.connection_register_object = g_dbus_connection_register_object;
133 _gdbus.error_free = g_error_free;
134 _gdbus.invocation_return_value = g_dbus_method_invocation_return_value;
135 _gdbus.connection_call_sync = g_dbus_connection_call_sync;
138 int orchestration_server_initialize(dbus_funcs cb)
140 int result = ORCH_ERROR_NONE;
142 if (cb.request_service_f == NULL || cb.update_key_pair_f == NULL) {
143 result = ORCH_ERROR_INVALID_PARAMETER;
144 printf("request_service_cb is null\n");
147 _request_service_cb = cb.request_service_f;
148 _request_service_on_device_cb = cb.request_service_on_device_f;
149 _update_key_pair_cb = cb.update_key_pair_f;
150 _get_device_list_cb = cb.get_device_list_f;
151 _read_device_capability_cb = cb.read_device_capability_f;
152 _write_device_capability_cb = cb.write_device_capability_f;
155 result = orch_dbus_initialize();
156 if (result != ORCH_ERROR_NONE)
158 printf("orch_dbus_initialize is failed\n");
167 void orchestration_server_finish(void)
171 _gdbus.unown_name(owner_id);
173 if (introspection_data)
175 _gdbus.node_info_unref(introspection_data);
177 printf("orchestration_server_finish\n");
180 static int orch_dbus_initialize(void)
184 result = _get_sync();
185 if (result != ORCH_ERROR_NONE)
187 printf("Failed to _dbus_init\n");
191 result = _set_node_info_new_for_xml();
192 if (result != ORCH_ERROR_NONE)
194 printf("Failed to _set_node_info_new_for_xml\n");
198 result = _connection_register_object();
199 if (result != ORCH_ERROR_NONE)
201 printf("Failed to _connection_register_object\n");
205 result = _own_name_on_connection();
206 if (result != ORCH_ERROR_NONE)
208 printf("Failed to _dbus_own_name_onconnection\n");
216 static void _handle_method_call(
217 GDBusConnection *connection,
219 const gchar *object_path,
220 const gchar *interface_name,
221 const gchar *method_name,
222 GVariant *parameters,
223 GDBusMethodInvocation *invocation,
226 int ret = ORCH_ERROR_NONE;
228 printf("method name :: %s\n", method_name);
230 if (sender != NULL && method_name != NULL) {
231 int origin_client_pid;
232 origin_client_pid = get_pid_with_connection(sender);
233 if (origin_client_pid < 0) {
234 DEBUG("get_pid_with_connection error!!\n");
237 if (g_strcmp0(method_name, "request_service") == 0)
239 DEBUG("receive method request_service\n");
240 ret = _request_service(parameters, origin_client_pid);
241 _gdbus.invocation_return_value(invocation, g_variant_new("(i)", ret));
243 else if (g_strcmp0(method_name, "request_service_on_device") == 0)
245 DEBUG("receive method request_service_on_device\n");
246 ret = _request_service_on_device(parameters, origin_client_pid);
247 _gdbus.invocation_return_value(invocation, g_variant_new("(i)", ret));
249 else if (g_strcmp0(method_name, "update_key_pair") == 0)
251 DEBUG("receive method update key pair\n");
252 ret = _update_key_pair(parameters, origin_client_pid);
253 _gdbus.invocation_return_value(invocation, g_variant_new("(i)", ret));
255 else if (g_strcmp0(method_name, "get_device_list") == 0)
257 DEBUG("receive get_device_list \n");
258 char *ipaddr_list = NULL, *ipaddr_listcopy = NULL, **ipaddr = NULL, *message = NULL;
259 int num_ip = 0, count = 0;
260 ret = _get_device_list(parameters, origin_client_pid, &ipaddr_list, &message);
263 // find count of IP addr
264 ipaddr_listcopy = strdup(ipaddr_list);
265 char *str = ipaddr_listcopy;
267 while ((token = strtok_r(str, ",", &str)))
275 ipaddr = (char**) malloc(sizeof(char *) * count);
278 while ((token = strtok_r(str, ",", &str)))
280 char *addr = (char*) malloc(sizeof(char) * (strlen(token) + 1));
283 strncpy(addr, token, strlen(token));
284 addr[strlen(token)] = '\0';
285 ipaddr[num_ip] = addr;
290 free(ipaddr_listcopy);
294 GVariantBuilder *builder;
297 builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
298 for (int i = 0; i < count; i++)
300 g_variant_builder_add (builder, "s", ipaddr[i]);
302 value = g_variant_new ("((asis))", builder, num_ip, strdup(message));
303 g_variant_builder_unref (builder);
305 _gdbus.invocation_return_value(invocation, value);
306 for (int i = 0; i < num_ip; i++)
313 else if (g_strcmp0(method_name, "read_capability") == 0)
315 printf("read device capability \n");
316 char *capability = NULL, *message = NULL;
317 ret = _read_device_capability(parameters, origin_client_pid, &capability, &message);
320 value = g_variant_new("((ss))", strdup(capability), strdup(message));
322 _gdbus.invocation_return_value(invocation, value);
327 else if (g_strcmp0(method_name, "write_capability") == 0)
329 DEBUG("write device capability \n");
331 char *write_ret = NULL;
332 ret = _write_device_capability(parameters, origin_client_pid, &write_ret);
333 _gdbus.invocation_return_value(invocation, g_variant_new("(i)", ret));
341 if (ret == ORCH_ERROR_NONE)
343 printf("Orchestration service Success, method name : %s\n", method_name);
347 printf("Orchestration service fail, method name : %s\n", method_name);
350 ret = ORCH_ERROR_INVALID_PARAMETER;
351 _gdbus.invocation_return_value(invocation, g_variant_new("(i)", ret));
355 static int _get_sync(void)
357 GError *error = NULL;
358 if (_gdbus_conn == NULL)
360 _gdbus_conn = _gdbus.get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
361 if (_gdbus_conn == NULL)
365 printf("Failed to get dbus [%s]\n", error->message);
366 _gdbus.error_free(error);
368 return ORCH_ERROR_DBUS_FAILURE;
371 return ORCH_ERROR_NONE;
374 static int _own_name_on_connection(void)
376 int result = ORCH_ERROR_NONE;
378 owner_id = _gdbus.own_name_on_connection(_gdbus_conn,
379 _ORCHESTRATION_BUS_NAME,
380 G_BUS_NAME_OWNER_FLAGS_NONE,
387 printf("Failed to own name on connection\n");
388 result = ORCH_ERROR_DBUS_FAILURE;
393 static int _set_node_info_new_for_xml(void)
395 int result = ORCH_ERROR_NONE;
396 GError *error = NULL;
398 introspection_data = _gdbus.node_info_new_for_xml(introspection_xml, &error);
399 if (!introspection_data)
401 printf("g_dbus_node_info_new_for_xml is failed\n");
404 printf("g_dbus_node_info_new_for_xml err [%s]\n", error->message);
405 _gdbus.error_free(error);
407 result = ORCH_ERROR_DBUS_FAILURE;
412 static int _connection_register_object(void)
414 int result = ORCH_ERROR_NONE;
415 guint orch_registration_id;
417 orch_registration_id = _gdbus.connection_register_object(_gdbus_conn,
418 _ORCHESTRATION_OBJECT_PATH,
419 introspection_data->interfaces[0],
425 if (orch_registration_id == 0)
427 printf("Failed to g_dbus_connection_register_object\n");
428 result = ORCH_ERROR_DBUS_FAILURE;
433 static int _read_device_capability(GVariant *parameters, int origin_client_pid, char **capability, char **message)
435 int result = ORCH_ERROR_NONE;
442 return ORCH_ERROR_INVALID_PARAMETER;
445 g_variant_get(parameters, "(si)", &ip, &client_pid);
446 DEBUG("\t client_pid = %d\n", client_pid);
448 if (origin_client_pid != client_pid) {
449 DEBUG("not matched clinet_pid from client and dbus, origin_client_pid(%d), client_pid(%d)\n", origin_client_pid, client_pid);
452 DeviceCapability* device_capability = _read_device_capability_cb(ip);
453 if (device_capability)
455 *capability = strdup(device_capability->CapabilityJson);
456 *message = strdup(device_capability->Message);
458 free(device_capability->CapabilityJson);
459 free(device_capability->Message);
460 free(device_capability);
465 static int _write_device_capability(GVariant *parameters, int origin_client_pid, char **write_ret)
467 int result = ORCH_ERROR_NONE;
474 return ORCH_ERROR_INVALID_PARAMETER;
477 g_variant_get(parameters, "(si)", &capability, &client_pid);
478 DEBUG("\t client_pid = %d\n", client_pid);
480 char *ret = _write_device_capability_cb(capability);
483 *write_ret = strdup(ret);
489 static int _get_device_list(GVariant *parameters, int origin_client_pid, char **ipaddr_list, char **message)
491 int result = ORCH_ERROR_NONE;
499 return ORCH_ERROR_INVALID_PARAMETER;
502 g_variant_get(parameters, "(ssi)", &service_name, &exec_type, &client_pid);
503 DEBUG("\t client_pid = %d\n", client_pid);
504 DEBUG("\t service_name = %s\n", service_name);
505 DEBUG("\t exec_type = %s\n", exec_type);
507 if (origin_client_pid != client_pid) {
508 DEBUG("not matched clinet_pid from client and dbus, origin_client_pid(%d), client_pid(%d)\n", origin_client_pid, client_pid);
511 DeviceList *devices_list = _get_device_list_cb(service_name, exec_type);
514 *ipaddr_list = strdup(devices_list->Endpoints);
515 *message = strdup(devices_list->Message);
517 free(devices_list->Endpoints);
518 free(devices_list->Message);
524 static int _request_service(GVariant *parameters, int origin_client_pid)
526 int result = ORCH_ERROR_NONE;
533 RequestServiceInfo service_info[MAX_SVC_INFO_NUM] = {NULL, };
537 return ORCH_ERROR_INVALID_PARAMETER;
540 g_variant_get(parameters, "(sia(ss)ii)", &app_name, &self_select, &iter, &count, &client_pid);
542 DEBUG("[orchestration dbus_interface] _request_service\n");
543 DEBUG("\t app_name = %s\n", app_name);
544 DEBUG("\t self_select = %s\n", self_select ? "true" : "false");
545 DEBUG("\t count = %d\n", count);
546 DEBUG("\t client_pid = %d\n", client_pid);
548 for (int i = 0; i < count; i++) {
549 if (g_variant_iter_loop (iter, "(ss)", &service_info[i].ExecutionType, &service_info[i].ExeCmd)) {
550 DEBUG("\t service_info[%d].ExecutionType = %s\n", i, service_info[i].ExecutionType);
551 DEBUG("\t service_info[%d].ExeCmd = %s\n", i, service_info[i].ExeCmd);
553 DEBUG("\t no more items to iterate!!!\n");
557 g_variant_iter_free (iter);
559 if (g_strcmp0(app_name, "") == 0)
560 return ORCH_ERROR_INVALID_PARAMETER;
562 if (origin_client_pid != client_pid) {
563 DEBUG("not matched clinet_pid from client and dbus, origin_client_pid(%d), client_pid(%d)\n", origin_client_pid, client_pid);
566 char process_name[128] = {0, };
567 const char unknown[] = "Unknown";
568 if (get_process_name_by_pid(process_name, origin_client_pid) != 0) {
569 DEBUG("could not get Process name");
570 strncpy(process_name, unknown, strlen(unknown));
573 result = _request_service_cb(app_name, self_select, service_info, count, process_name);
578 static int _request_service_on_device(GVariant *parameters, int origin_client_pid)
580 int result = ORCH_ERROR_NONE;
587 RequestServiceInfo service_info[MAX_SVC_INFO_NUM] = {NULL, };
592 return ORCH_ERROR_INVALID_PARAMETER;
595 g_variant_get(parameters, "(sia(ss)sii)", &app_name, &self_select, &iter, &ip, &count, &client_pid);
597 DEBUG("[orchestration dbus_interface] _request_service\n");
598 DEBUG("\t app_name = %s\n", app_name);
599 DEBUG("\t self_select = %s\n", self_select ? "true" : "false");
600 DEBUG("\t Device IP addr = %s \n", ip);
601 DEBUG("\t count = %d\n", count);
602 DEBUG("\t client_pid = %d\n", client_pid);
604 for (int i = 0; i < count; i++) {
605 if (g_variant_iter_loop (iter, "(ss)", &service_info[i].ExecutionType, &service_info[i].ExeCmd)) {
606 DEBUG("\t service_info[%d].ExecutionType = %s\n", i, service_info[i].ExecutionType);
607 DEBUG("\t service_info[%d].ExeCmd = %s\n", i, service_info[i].ExeCmd);
609 DEBUG("\t no more items to iterate!!!\n");
613 g_variant_iter_free (iter);
615 if (g_strcmp0(app_name, "") == 0)
616 return ORCH_ERROR_INVALID_PARAMETER;
618 if (origin_client_pid != client_pid) {
619 DEBUG("not matched clinet_pid from client and dbus, origin_client_pid(%d), client_pid(%d)\n", origin_client_pid, client_pid);
622 char process_name[128] = {0, };
623 const char unknown[] = "Unknown";
624 if (get_process_name_by_pid(process_name, origin_client_pid) != 0) {
625 DEBUG("could not get Process name");
626 strncpy(process_name, unknown, strlen(unknown));
629 result = _request_service_on_device_cb(app_name, self_select, service_info, ip, count, process_name);
634 static int _update_key_pair(GVariant *parameters, int origin_client_pid)
636 int result = ORCH_ERROR_NONE;
643 return ORCH_ERROR_INVALID_PARAMETER;
646 g_variant_get(parameters, "(ssi)", &id, &key, &client_pid);
648 DEBUG("[orchestration dbus_interface] _update_key_pair\n");
650 if (id == NULL || key == NULL) {
651 return ORCH_ERROR_INVALID_PARAMETER;
654 DEBUG("\t id = %s\n", id);
655 DEBUG("\t key = %s\n", key);
656 DEBUG("\t client_pid = %d\n", client_pid);
658 if (origin_client_pid != client_pid) {
659 DEBUG("not matched clinet_pid from client and dbus, origin_client_pid(%d), client_pid(%d)\n", origin_client_pid, client_pid);
662 char process_name[128] = {0, };
663 const char unknown[] = "Unknown";
664 if (get_process_name_by_pid(process_name, origin_client_pid) != 0) {
665 DEBUG("could not get Process name");
666 strncpy(process_name, unknown, strlen(unknown));
669 result = _update_key_pair_cb(id, key, process_name);
674 static int get_process_name_by_pid(char* process_name, int pid) {
675 char fname[1024] = {0, };
676 char line[1024] = {0, };
677 ssize_t fname_len = snprintf(NULL, 0, "/proc/%d/status", pid);
679 snprintf(fname, fname_len + 1, "/proc/%d/status", pid);
680 FILE *fp = fopen(fname, "r");
682 DEBUG("%d Process not found!!!\n", pid);
686 fgets(line, 1024, fp);
687 if (strstr(line, "Name:") != NULL) {
689 char *ptr = strchr(line, ':');
692 if (*ptr == '\n' || *ptr == '\0')
694 if (*ptr != ' ' && *ptr != '\t')
695 process_name[index++] = *ptr;
697 process_name[index] = '\0';
698 printf("process_name = %s\n", process_name);
703 printf("%d Process status have no Process name!!\n", pid);
708 static int get_pid_with_connection(const gchar* sender) {
709 int origin_client_pid;
710 GError *error = NULL;
711 GVariant * connection;
713 connection = g_variant_new ("(s)", sender);
716 _gdbus.connection_call_sync (_gdbus_conn,
717 _FREEDESKTOP_BUS_NAME,
718 _FREEDESKTOP_OBJECT_PATH,
719 _FREEDESKTOP_INTERFACE,
720 _FREEDESKTOP_GETPROCESSID_METHOD,
723 G_DBUS_CALL_FLAGS_NONE,
728 g_variant_get(result, "(u)", &origin_client_pid);
729 DEBUG("origin_client_pid: %d\n", origin_client_pid);
732 g_variant_unref (result);
735 DEBUG("Failed to call remote method - %i : %s\n", error->code, error->message);
736 g_error_free (error);
738 g_object_unref (_gdbus_conn);
742 return origin_client_pid;