2 * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd 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.
18 #include <sys/types.h>
33 #include <bundle_internal.h>
34 #include <tzplatform_config.h>
35 #include <systemd/sd-login.h>
38 #include <aul_app_com.h>
40 #include "amd_config.h"
42 #include "amd_request.h"
43 #include "amd_app_status.h"
44 #include "amd_cynara.h"
45 #include "amd_socket.h"
46 #include "aul_svc_priv_key.h"
47 #include "amd_signal.h"
48 #include "amd_login_monitor.h"
51 #define PENDING_REQUEST_TIMEOUT 5000 /* msec */
52 #define SYSTEM_REQUEST_TIMEOUT 90000 /* msec */
53 #define PENDING_MESSAGE_MAX_CNT 100
56 static GIOChannel *amd_io;
58 static GHashTable *pending_table;
59 static GHashTable *__dispatch_table;
80 unsigned char data[1];
90 void (*extra_free_cb)(void *data);
93 static gboolean __timeout_pending_item(gpointer user_data);
94 static gboolean __dispatch_request(gpointer data);
95 static gboolean __timeout_request(gpointer data);
97 static void __free_reply_info(gpointer data)
99 struct reply_info *reply = (struct reply_info *)data;
104 if (reply->extra && reply->extra_free_cb)
105 reply->extra_free_cb(reply->extra);
109 g_source_remove(reply->timer);
113 static gboolean __timeout_reply(gpointer data)
115 struct reply_info *reply = (struct reply_info *)data;
120 _request_reply_remove(reply->pid, reply);
121 _send_result_to_client(reply->clifd, reply->result);
124 __free_reply_info(reply);
129 static struct reply_info *__create_reply_info(guint interval, pid_t pid,
130 int result, int cmd, int clifd, void *extra,
131 void (*extra_free_cb)(void *data))
133 struct reply_info *reply;
135 reply = malloc(sizeof(struct reply_info));
142 reply->result = result;
144 reply->clifd = clifd;
145 reply->timer = g_timeout_add(interval, __timeout_reply, reply);
146 reply->extra = extra;
147 reply->extra_free_cb = extra_free_cb;
152 static void __free_request(gpointer data)
154 request_h req = (request_h)data;
162 g_source_remove(req->timer);
164 bundle_free(req->kb);
169 static void __free_pending_item(gpointer user_data)
171 struct pending_item *item = (struct pending_item *)user_data;
176 if (item->reply_list)
177 g_list_free_full(item->reply_list, __free_reply_info);
178 if (item->pending_list)
179 g_list_free_full(item->pending_list, __free_request);
180 if (g_main_context_find_source_by_user_data(NULL, item))
181 g_source_remove(item->timer);
185 static void __timeout_pending_reply(gpointer data, gpointer user_data)
187 struct reply_info *reply = (struct reply_info *)data;
192 _send_result_to_client(reply->clifd, reply->result);
196 static void __timeout_pending_request(gpointer data, gpointer user_data)
198 request_h req = (request_h)data;
203 _request_send_result(req, -EAGAIN);
206 static gboolean __timeout_pending_item(gpointer user_data)
208 struct pending_item *item = (struct pending_item *)user_data;
213 g_list_foreach(item->reply_list, __timeout_pending_reply, NULL);
214 g_list_foreach(item->pending_list, __timeout_pending_request, NULL);
215 g_hash_table_remove(pending_table, GINT_TO_POINTER(item->pid));
220 static void __flush_pending_reply_list(GList **reply_list, bool is_dead)
223 struct reply_info *reply;
225 if (reply_list == NULL)
228 iter = g_list_first(*reply_list);
230 reply = (struct reply_info *)iter->data;
231 iter = g_list_next(iter);
235 if (reply->cmd == APP_TERM_BY_PID_SYNC_WITHOUT_RESTART ||
236 reply->cmd == APP_TERM_BY_PID_SYNC) {
243 *reply_list = g_list_remove(*reply_list, reply);
244 _send_result_to_client(reply->clifd, reply->result);
246 __free_reply_info(reply);
250 static void __flush_pending_request_list(GList **pending_list)
255 if (pending_list == NULL)
258 iter = g_list_first(*pending_list);
260 req = (request_h)iter->data;
261 iter = g_list_next(iter);
265 *pending_list = g_list_remove(*pending_list, req);
267 g_source_remove(req->timer);
270 g_idle_add(__dispatch_request, req);
274 int _request_flush_pending_request(int pid)
276 struct pending_item *item;
278 item = (struct pending_item *)g_hash_table_lookup(pending_table,
279 GINT_TO_POINTER(pid));
283 __flush_pending_reply_list(&item->reply_list, true);
284 __timeout_pending_item((gpointer)item);
289 int _request_reply_for_pending_request(int pid)
291 struct pending_item *item;
293 _app_status_publish_status(pid, STATUS_LAUNCHING);
295 item = (struct pending_item *)g_hash_table_lookup(pending_table,
296 GINT_TO_POINTER(pid));
300 __flush_pending_reply_list(&item->reply_list, false);
301 __flush_pending_request_list(&item->pending_list);
306 static request_h __get_request(int clifd, app_pkt_t *pkt,
310 const char *target_uid;
312 req = (request_h)malloc(sizeof(struct request_s) + pkt->len);
316 g_get_current_time(&req->start);
325 memcpy(req->data, pkt->data, pkt->len + 1);
327 if (pkt->opt & AUL_SOCK_BUNDLE) {
328 req->kb = bundle_decode(pkt->data, pkt->len);
329 if (req->kb == NULL) {
334 target_uid = bundle_get_val(req->kb, AUL_K_TARGET_UID);
335 if (target_uid && isdigit(target_uid[0]))
336 req->t_uid = atoi(target_uid);
347 static gboolean __timeout_request(gpointer data)
349 request_h req = (request_h)data;
350 struct pending_item *item;
355 item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(req->t_pid));
357 item->pending_list = g_list_remove(item->pending_list, req);
360 _request_send_result(req, -EAGAIN);
367 static app_status_h __get_app_status(request_h req, const char *appid)
370 app_status_h app_status;
373 const char *comp_type;
376 case APP_RESUME_BY_PID:
377 case APP_TERM_BY_PID:
378 case APP_TERM_BY_PID_WITHOUT_RESTART:
379 case APP_KILL_BY_PID:
380 case APP_TERM_REQ_BY_PID:
381 case APP_TERM_BY_PID_ASYNC:
382 case APP_TERM_BGAPP_BY_PID:
383 case APP_PAUSE_BY_PID:
384 case APP_TERM_BY_PID_SYNC:
385 case APP_TERM_BY_PID_SYNC_WITHOUT_RESTART:
388 app_status = _app_status_find(pid);
390 case APP_START_ASYNC:
391 case APP_START_RES_ASYNC:
392 ai = _appinfo_find(_request_get_target_uid(req), appid);
393 comp_type = _appinfo_get_value(ai, AIT_COMPTYPE);
394 if (comp_type && (strcmp(comp_type, APP_TYPE_WIDGET) == 0 ||
395 strcmp(comp_type, APP_TYPE_WATCH) == 0)) {
396 app_status = _app_status_find_with_org_caller(appid,
397 _request_get_target_uid(req),
398 _request_get_pid(req));
400 app_status = _app_status_find_by_appid(appid,
401 _request_get_target_uid(req));
405 app_status = _app_status_find_by_appid(appid,
406 _request_get_target_uid(req));
410 if (app_status == NULL)
413 status = _app_status_get_status(app_status);
414 if (status == STATUS_DYING)
420 static int __check_request(request_h req)
423 struct pending_item *item;
424 app_status_h app_status;
427 if (req->opt & AUL_SOCK_NOREPLY)
428 close(_request_remove_fd(req));
430 if ((req->opt & AUL_SOCK_QUEUE) == 0)
436 appid = bundle_get_val(req->kb, AUL_K_APPID);
440 app_status = __get_app_status(req, appid);
441 if (app_status == NULL)
444 if (_app_status_socket_exists(app_status))
447 pid = _app_status_get_pid(app_status);
448 item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
452 if (!_app_status_is_starting(app_status)) {
454 _W("%s(%d) is waiting to be started.", appid, pid);
455 req->timer = g_timeout_add(PENDING_REQUEST_TIMEOUT,
456 __timeout_request, req);
459 item->pending_list = g_list_append(item->pending_list, req);
464 static int __check_target_user(request_h req)
471 if (req->t_uid >= REGULAR_UID_MIN) {
472 state = _login_monitor_get_uid_state(req->t_uid);
473 if (state == UID_STATE_ONLINE || state == UID_STATE_ACTIVE)
479 r = _login_monitor_get_uids(&uids);
483 for (i = 0; i < r; i++) {
484 state = _login_monitor_get_uid_state(uids[i]);
485 if (state == UID_STATE_ONLINE || state == UID_STATE_ACTIVE) {
486 req->t_uid = uids[i];
492 if (req->t_uid < REGULAR_UID_MIN)
498 static gboolean __dispatch_request(gpointer data)
500 request_h req = (request_h)data;
501 request_cmd_dispatch *dispatcher;
506 if (req->cmd < 0 || req->cmd >= APP_CMD_MAX) {
511 dispatcher = g_hash_table_lookup(__dispatch_table,
512 GINT_TO_POINTER(req->cmd));
514 if (dispatcher->callback(req) != 0)
515 _E("callback returns FALSE : %d", req->cmd);
517 _E("Invalid request or not supported command");
525 static guint __get_pending_interval(GTimeVal *start, GTimeVal *end)
531 sec = (end->tv_sec - start->tv_sec) * 1000;
532 usec = (end->tv_usec - start->tv_usec) / 1000;
533 interval = sec + usec;
534 if (interval >= PENDING_REQUEST_TIMEOUT)
537 return PENDING_REQUEST_TIMEOUT - interval;
540 int _request_reply_reset_pending_timer(request_h req, unsigned int interval, int pid)
542 struct pending_item *item;
545 item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
547 _W("pending item doesn't exist - pid(%d)", pid);
552 g_source_remove(item->timer);
555 g_get_current_time(&end);
556 interval = __get_pending_interval(_request_get_start_time(req), &end);
559 item->timer = g_timeout_add(interval, __timeout_pending_item, item);
564 int _request_reply_append(int pid, void *reply)
566 struct pending_item *item;
568 item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
570 item = calloc(1, sizeof(struct pending_item));
576 g_hash_table_insert(pending_table, GINT_TO_POINTER(pid),
580 g_source_remove(item->timer);
585 item->reply_list = g_list_append(item->reply_list, reply);
590 int _request_reply_remove(int pid, void *reply)
592 struct pending_item *item;
594 item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
596 item->reply_list = g_list_remove(item->reply_list, reply);
601 request_reply_h _request_reply_create_full(request_h req, pid_t pid, int result,
602 int cmd, void *extra, void (*extra_free_cb)(void *data))
604 request_reply_h reply;
605 unsigned int interval;
607 int clifd = _request_remove_fd(req);
609 g_get_current_time(&end);
610 interval = __get_pending_interval(_request_get_start_time(req), &end);
611 reply = __create_reply_info(interval, pid, result, cmd, clifd, extra,
615 _send_result_to_client(clifd, -1);
622 int _request_reply_foreach_extra(int pid, int (*callback)(void *data))
624 struct pending_item *item;
626 struct reply_info *info;
628 item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
632 iter = item->reply_list;
635 if (!callback(info->extra))
637 iter = g_list_next(iter);
643 int _request_usr_init(uid_t uid)
648 struct pending_item *item;
650 _noti_send("request.user_init", uid, 0, NULL, NULL);
651 item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(getpid()));
652 if (item == NULL || item->pending_list == NULL)
655 iter = g_list_first(item->pending_list);
657 req = (request_h)iter->data;
658 iter = g_list_next(iter);
663 if (req->t_uid < REGULAR_UID_MIN)
666 if (req->t_uid == uid) {
667 g_source_remove(req->timer);
669 item->pending_list = g_list_remove(item->pending_list,
672 r = __check_request(req);
674 g_idle_add(__dispatch_request, (gpointer)req);
683 static void __cynara_response_callback(enum amd_cynara_res res, request_h req)
687 if (res == AMD_CYNARA_ALLOWED) {
688 ret = __check_request(req);
690 _request_send_result(req, ret);
693 } else if (ret > 0) {
696 __dispatch_request((gpointer)req);
698 _E("request has been denied by cynara");
699 ret = -EILLEGALACCESS;
700 _request_send_result(req, ret);
707 static gboolean __request_handler(GIOChannel *io, GIOCondition cond,
710 int fd = g_io_channel_unix_get_fd(io);
717 struct pending_item *item;
719 pkt = aul_sock_recv_pkt(fd, &clifd, &cr);
725 req = __get_request(clifd, pkt, cr);
733 if (req->uid >= REGULAR_UID_MIN) {
734 if (req->uid != req->t_uid) {
735 _E("request has been deined - uid(%d), target_uid(%d)",
736 req->uid, req->t_uid);
737 ret = -EILLEGALACCESS;
738 _request_send_result(req, ret);
743 ret = _cynara_check_privilege(req, __cynara_response_callback);
745 _E("request has been denied by cynara");
746 ret = -EILLEGALACCESS;
747 _request_send_result(req, ret);
750 } else if (ret == AMD_CYNARA_UNKNOWN) {
754 ret = __check_target_user(req);
755 if (ret < 0 && (req->cmd == APP_START_ASYNC ||
756 req->cmd == APP_START_RES_ASYNC)) {
757 item = g_hash_table_lookup(pending_table,
758 GINT_TO_POINTER(getpid()));
760 item = calloc(1, sizeof(struct pending_item));
763 _request_send_result(req, ret);
767 item->pid = getpid();
768 g_hash_table_insert(pending_table,
769 GINT_TO_POINTER(getpid()),
773 len = g_list_length(item->pending_list);
774 if (len <= PENDING_MESSAGE_MAX_CNT) {
775 _D("user not logged");
776 _request_send_result(req, 0);
777 req->t_pid = getpid();
778 req->timer = g_timeout_add(
779 SYSTEM_REQUEST_TIMEOUT,
780 __timeout_request, req);
781 item->pending_list = g_list_append(
782 item->pending_list, req);
788 ret = __check_request(req);
790 _request_send_result(req, ret);
793 } else if (ret > 0) {
797 __dispatch_request((gpointer)req);
802 int _request_get_fd(request_h req)
807 int _request_get_pid(request_h req)
812 pid_t _request_get_target_pid(request_h req)
817 bundle *_request_get_bundle(request_h req)
822 int _request_get_len(request_h req)
827 unsigned char *_request_get_raw(request_h req)
832 GTimeVal *_request_get_start_time(request_h req)
837 request_h _request_create_local(int cmd, uid_t uid, int pid, bundle *kb)
841 req = (request_h)malloc(sizeof(struct request_s));
847 g_get_current_time(&req->start);
856 req->opt = AUL_SOCK_NONE;
857 req->kb = bundle_dup(kb);
862 void _request_free_local(request_h req)
868 bundle_free(req->kb);
873 int _request_get_cmd(request_h req)
878 int _request_set_cmd(request_h req, int cmd)
885 int _request_remove_fd(request_h req)
894 uid_t _request_get_target_uid(request_h req)
899 uid_t _request_get_uid(request_h req)
904 int _request_send_raw(request_h req, int cmd, unsigned char *data, int len)
906 return aul_sock_send_raw_with_fd(_request_remove_fd(req), cmd, data,
907 len, AUL_SOCK_NOREPLY);
910 int _request_send_result(request_h req, int res)
912 if (req->clifd && (req->opt & AUL_SOCK_NOREPLY))
913 close(_request_remove_fd(req));
915 _send_result_to_client(_request_remove_fd(req), res);
920 int _request_register_cmds(const request_cmd_dispatch *cmds, int cnt)
924 if (cnt <= 0 || !__dispatch_table || !cmds)
927 for (i = 0; i < cnt; i++) {
928 g_hash_table_insert(__dispatch_table,
929 GINT_TO_POINTER(cmds[i].cmd),
930 (gpointer)(&cmds[i]));
936 int _request_init(void)
939 pending_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
940 NULL, __free_pending_item);
941 if (pending_table == NULL) {
942 _E("Failed to create pending table");
947 amd_fd = _create_sock_activation();
949 _D("Create server socket without socket activation");
950 amd_fd = _create_server_sock();
952 _E("Create server socket failed.");
958 amd_io = g_io_channel_unix_new(amd_fd);
959 if (amd_io == NULL) {
960 _E("Failed to create gio channel");
965 amd_wid = g_io_add_watch(amd_io, G_IO_IN, __request_handler, NULL);
967 _E("Failed to add gio watch");
972 __dispatch_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
978 void _request_fini(void)
982 g_source_remove(amd_wid);
987 g_io_channel_unref(amd_io);
997 g_hash_table_destroy(pending_table);
998 pending_table = NULL;
1001 if (__dispatch_table) {
1002 g_hash_table_destroy(__dispatch_table);
1003 __dispatch_table = NULL;