ares test
[scm/test.git] / src / lib / amd_request.c
1 /*
2  * Copyright (c) 2015 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #define _GNU_SOURCE
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <dirent.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <dlfcn.h>
27 #include <poll.h>
28 #include <ctype.h>
29 #include <glib.h>
30 #include <gio/gio.h>
31 #include <aul.h>
32 #include <bundle.h>
33 #include <bundle_internal.h>
34 #include <tzplatform_config.h>
35 #include <systemd/sd-login.h>
36 #include <aul_sock.h>
37 #include <aul_svc.h>
38 #include <aul_app_com.h>
39
40 #include "amd_config.h"
41 #include "amd_util.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"
49 #include "amd_noti.h"
50
51 #define PENDING_REQUEST_TIMEOUT 5000 /* msec */
52 #define SYSTEM_REQUEST_TIMEOUT 90000 /* msec */
53 #define PENDING_MESSAGE_MAX_CNT 100
54
55 static int amd_fd;
56 static GIOChannel *amd_io;
57 static guint amd_wid;
58 static GHashTable *pending_table;
59 static GHashTable *__dispatch_table;
60
61 struct pending_item {
62         int pid;
63         guint timer;
64         GList *pending_list;
65         GList *reply_list;
66 };
67
68 struct request_s {
69         GTimeVal start;
70         guint timer;
71         int cmd;
72         int clifd;
73         pid_t pid;
74         pid_t t_pid;
75         uid_t uid;
76         uid_t t_uid;
77         bundle *kb;
78         int len;
79         int opt;
80         unsigned char data[1];
81 };
82
83 struct reply_info {
84         guint timer;
85         pid_t pid;
86         int result;
87         int cmd;
88         int clifd;
89         void *extra;
90         void (*extra_free_cb)(void *data);
91 };
92
93 static gboolean __timeout_pending_item(gpointer user_data);
94 static gboolean __dispatch_request(gpointer data);
95 static gboolean __timeout_request(gpointer data);
96
97 static void __free_reply_info(gpointer data)
98 {
99         struct reply_info *reply = (struct reply_info *)data;
100
101         if (reply == NULL)
102                 return;
103
104         if (reply->extra && reply->extra_free_cb)
105                 reply->extra_free_cb(reply->extra);
106         if (reply->clifd)
107                 close(reply->clifd);
108         if (reply->timer)
109                 g_source_remove(reply->timer);
110         free(reply);
111 }
112
113 static gboolean __timeout_reply(gpointer data)
114 {
115         struct reply_info *reply = (struct reply_info *)data;
116
117         if (reply == NULL)
118                 return FALSE;
119
120         _request_reply_remove(reply->pid, reply);
121         _send_result_to_client(reply->clifd, reply->result);
122         reply->clifd = 0;
123         reply->timer = 0;
124         __free_reply_info(reply);
125
126         return FALSE;
127 }
128
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))
132 {
133         struct reply_info *reply;
134
135         reply = malloc(sizeof(struct reply_info));
136         if (reply == NULL) {
137                 _E("Out of memory");
138                 return NULL;
139         }
140
141         reply->pid = pid;
142         reply->result = result;
143         reply->cmd = cmd;
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;
148
149         return reply;
150 }
151
152 static void __free_request(gpointer data)
153 {
154         request_h req = (request_h)data;
155
156         if (req == NULL)
157                 return;
158
159         if (req->clifd)
160                 close(req->clifd);
161         if (req->timer)
162                 g_source_remove(req->timer);
163         if (req->kb)
164                 bundle_free(req->kb);
165
166         free(req);
167 }
168
169 static void __free_pending_item(gpointer user_data)
170 {
171         struct pending_item *item = (struct pending_item *)user_data;
172
173         if (item == NULL)
174                 return;
175
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);
182         free(item);
183 }
184
185 static void __timeout_pending_reply(gpointer data, gpointer user_data)
186 {
187         struct reply_info *reply = (struct reply_info *)data;
188
189         if (reply == NULL)
190                 return;
191
192         _send_result_to_client(reply->clifd, reply->result);
193         reply->clifd = 0;
194 }
195
196 static void __timeout_pending_request(gpointer data, gpointer user_data)
197 {
198         request_h req = (request_h)data;
199
200         if (req == NULL)
201                 return;
202
203         _request_send_result(req, -EAGAIN);
204 }
205
206 static gboolean __timeout_pending_item(gpointer user_data)
207 {
208         struct pending_item *item = (struct pending_item *)user_data;
209
210         if (item == NULL)
211                 return FALSE;
212
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));
216
217         return FALSE;
218 }
219
220 static void __flush_pending_reply_list(GList **reply_list, bool is_dead)
221 {
222         GList *iter;
223         struct reply_info *reply;
224
225         if (reply_list == NULL)
226                 return;
227
228         iter = g_list_first(*reply_list);
229         while (iter) {
230                 reply = (struct reply_info *)iter->data;
231                 iter = g_list_next(iter);
232                 if (reply == NULL)
233                         continue;
234
235                 if (reply->cmd == APP_TERM_BY_PID_SYNC_WITHOUT_RESTART ||
236                                 reply->cmd == APP_TERM_BY_PID_SYNC) {
237                         if (!is_dead)
238                                 continue;
239
240                         reply->result = 0;
241                 }
242
243                 *reply_list = g_list_remove(*reply_list, reply);
244                 _send_result_to_client(reply->clifd, reply->result);
245                 reply->clifd = 0;
246                 __free_reply_info(reply);
247         }
248 }
249
250 static void __flush_pending_request_list(GList **pending_list)
251 {
252         GList *iter;
253         request_h req;
254
255         if (pending_list == NULL)
256                 return;
257
258         iter = g_list_first(*pending_list);
259         while (iter) {
260                 req = (request_h)iter->data;
261                 iter = g_list_next(iter);
262                 if (req == NULL)
263                         continue;
264
265                 *pending_list = g_list_remove(*pending_list, req);
266                 if (req->timer) {
267                         g_source_remove(req->timer);
268                         req->timer = 0;
269                 }
270                 g_idle_add(__dispatch_request, req);
271         }
272 }
273
274 int _request_flush_pending_request(int pid)
275 {
276         struct pending_item *item;
277
278         item = (struct pending_item *)g_hash_table_lookup(pending_table,
279                         GINT_TO_POINTER(pid));
280         if (item == NULL)
281                 return -1;
282
283         __flush_pending_reply_list(&item->reply_list, true);
284         __timeout_pending_item((gpointer)item);
285
286         return 0;
287 }
288
289 int _request_reply_for_pending_request(int pid)
290 {
291         struct pending_item *item;
292
293         _app_status_publish_status(pid, STATUS_LAUNCHING);
294
295         item = (struct pending_item *)g_hash_table_lookup(pending_table,
296                         GINT_TO_POINTER(pid));
297         if (item == NULL)
298                 return -1;
299
300         __flush_pending_reply_list(&item->reply_list, false);
301         __flush_pending_request_list(&item->pending_list);
302
303         return 0;
304 }
305
306 static request_h __get_request(int clifd, app_pkt_t *pkt,
307                 struct ucred cr)
308 {
309         request_h req;
310         const char *target_uid;
311
312         req = (request_h)malloc(sizeof(struct request_s) + pkt->len);
313         if (req == NULL)
314                 return NULL;
315
316         g_get_current_time(&req->start);
317         req->timer = 0;
318         req->clifd = clifd;
319         req->pid = cr.pid;
320         req->t_pid = 0;
321         req->uid = cr.uid;
322         req->cmd = pkt->cmd;
323         req->len = pkt->len;
324         req->opt = pkt->opt;
325         memcpy(req->data, pkt->data, pkt->len + 1);
326
327         if (pkt->opt & AUL_SOCK_BUNDLE) {
328                 req->kb = bundle_decode(pkt->data, pkt->len);
329                 if (req->kb == NULL) {
330                         free(req);
331                         return NULL;
332                 }
333
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);
337                 else
338                         req->t_uid = cr.uid;
339         } else {
340                 req->kb = NULL;
341                 req->t_uid = cr.uid;
342         }
343
344         return req;
345 }
346
347 static gboolean __timeout_request(gpointer data)
348 {
349         request_h req = (request_h)data;
350         struct pending_item *item;
351
352         if (req == NULL)
353                 return FALSE;
354
355         item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(req->t_pid));
356         if (item)
357                 item->pending_list = g_list_remove(item->pending_list, req);
358
359         if (req->clifd)
360                 _request_send_result(req, -EAGAIN);
361         req->timer = 0;
362         __free_request(req);
363
364         return FALSE;
365 }
366
367 static app_status_h __get_app_status(request_h req, const char *appid)
368 {
369         int pid;
370         app_status_h app_status;
371         int status;
372         struct appinfo *ai;
373         const char *comp_type;
374
375         switch (req->cmd) {
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:
386                 /* get pid */
387                 pid = atoi(appid);
388                 app_status = _app_status_find(pid);
389                 break;
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));
399                 } else {
400                         app_status = _app_status_find_by_appid(appid,
401                                         _request_get_target_uid(req));
402                 }
403                 break;
404         default:
405                 app_status = _app_status_find_by_appid(appid,
406                                 _request_get_target_uid(req));
407                 break;
408         }
409
410         if (app_status == NULL)
411                 return NULL;
412
413         status = _app_status_get_status(app_status);
414         if (status == STATUS_DYING)
415                 return NULL;
416
417         return app_status;
418 }
419
420 static int __check_request(request_h req)
421 {
422         int pid;
423         struct pending_item *item;
424         app_status_h app_status;
425         const char *appid;
426
427         if (req->opt & AUL_SOCK_NOREPLY)
428                 close(_request_remove_fd(req));
429
430         if ((req->opt & AUL_SOCK_QUEUE) == 0)
431                 return 0;
432
433         if (req->kb == NULL)
434                 return -1;
435
436         appid = bundle_get_val(req->kb, AUL_K_APPID);
437         if (appid == NULL)
438                 return -1;
439
440         app_status = __get_app_status(req, appid);
441         if (app_status == NULL)
442                 return 0;
443
444         if (_app_status_socket_exists(app_status))
445                 return 0;
446
447         pid = _app_status_get_pid(app_status);
448         item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
449         if (item == NULL)
450                 return 0;
451
452         if (!_app_status_is_starting(app_status)) {
453                 req->t_pid = pid;
454                 _W("%s(%d) is waiting to be started.", appid, pid);
455                 req->timer = g_timeout_add(PENDING_REQUEST_TIMEOUT,
456                                 __timeout_request, req);
457         }
458
459         item->pending_list = g_list_append(item->pending_list, req);
460
461         return 1;
462 }
463
464 static int __check_target_user(request_h req)
465 {
466         int r;
467         uid_t *uids;
468         int i;
469         uid_state state;
470
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)
474                         return 0;
475
476                 return -1;
477         }
478
479         r = _login_monitor_get_uids(&uids);
480         if (r <= 0)
481                 return -1;
482
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];
487                         break;
488                 }
489         }
490         free(uids);
491
492         if (req->t_uid < REGULAR_UID_MIN)
493                 return -1;
494
495         return 0;
496 }
497
498 static gboolean __dispatch_request(gpointer data)
499 {
500         request_h req = (request_h)data;
501         request_cmd_dispatch *dispatcher;
502
503         if (req == NULL)
504                 return FALSE;
505
506         if (req->cmd < 0 || req->cmd >= APP_CMD_MAX) {
507                 __free_request(req);
508                 return FALSE;
509         }
510
511         dispatcher = g_hash_table_lookup(__dispatch_table,
512                         GINT_TO_POINTER(req->cmd));
513         if (dispatcher) {
514                 if (dispatcher->callback(req) != 0)
515                         _E("callback returns FALSE : %d", req->cmd);
516         } else {
517                 _E("Invalid request or not supported command");
518         }
519
520         __free_request(req);
521
522         return FALSE;
523 }
524
525 static guint __get_pending_interval(GTimeVal *start, GTimeVal *end)
526 {
527         guint sec;
528         guint usec;
529         guint interval;
530
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)
535                 return 0;
536
537         return PENDING_REQUEST_TIMEOUT - interval;
538 }
539
540 int _request_reply_reset_pending_timer(request_h req, unsigned int interval, int pid)
541 {
542         struct pending_item *item;
543         GTimeVal end;
544
545         item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
546         if (item == NULL) {
547                 _W("pending item doesn't exist - pid(%d)", pid);
548                 return -1;
549         }
550
551         if (item->timer)
552                 g_source_remove(item->timer);
553
554         if (interval <= 0) {
555                 g_get_current_time(&end);
556                 interval = __get_pending_interval(_request_get_start_time(req), &end);
557         }
558
559         item->timer = g_timeout_add(interval, __timeout_pending_item, item);
560
561         return 0;
562 }
563
564 int _request_reply_append(int pid, void *reply)
565 {
566         struct pending_item *item;
567
568         item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
569         if (item == NULL) {
570                 item = calloc(1, sizeof(struct pending_item));
571                 if (item == NULL) {
572                         _E("Out of memory");
573                         return -1;
574                 }
575                 item->pid = pid;
576                 g_hash_table_insert(pending_table, GINT_TO_POINTER(pid),
577                                 item);
578         } else {
579                 if (item->timer) {
580                         g_source_remove(item->timer);
581                         item->timer = 0;
582                 }
583         }
584
585         item->reply_list = g_list_append(item->reply_list, reply);
586
587         return 0;
588 }
589
590 int _request_reply_remove(int pid, void *reply)
591 {
592         struct pending_item *item;
593
594         item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
595         if (item)
596                 item->reply_list = g_list_remove(item->reply_list, reply);
597
598         return 0;
599 }
600
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))
603 {
604         request_reply_h reply;
605         unsigned int interval;
606         GTimeVal end;
607         int clifd = _request_remove_fd(req);
608
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,
612                         extra_free_cb);
613
614         if (reply == NULL) {
615                 _send_result_to_client(clifd, -1);
616                 return NULL;
617         }
618
619         return reply;
620 }
621
622 int _request_reply_foreach_extra(int pid, int (*callback)(void *data))
623 {
624         struct pending_item *item;
625         GList *iter;
626         struct reply_info *info;
627
628         item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
629         if (!item)
630                 return -1;
631
632         iter = item->reply_list;
633         while (iter) {
634                 info = iter->data;
635                 if (!callback(info->extra))
636                         info->extra = NULL;
637                 iter = g_list_next(iter);
638         }
639
640         return 0;
641 }
642
643 int _request_usr_init(uid_t uid)
644 {
645         GList *iter;
646         request_h req;
647         int r;
648         struct pending_item *item;
649
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)
653                 return 0;
654
655         iter = g_list_first(item->pending_list);
656         while (iter) {
657                 req = (request_h)iter->data;
658                 iter = g_list_next(iter);
659                 if (req == NULL)
660                         continue;
661
662                 req->t_pid = 0;
663                 if (req->t_uid < REGULAR_UID_MIN)
664                         req->t_uid = uid;
665
666                 if (req->t_uid == uid) {
667                         g_source_remove(req->timer);
668                         req->timer = 0;
669                         item->pending_list = g_list_remove(item->pending_list,
670                                         req);
671
672                         r = __check_request(req);
673                         if (r == 0)
674                                 g_idle_add(__dispatch_request, (gpointer)req);
675                         else if (r < 0)
676                                 __free_request(req);
677                 }
678         }
679
680         return 0;
681 }
682
683 static void __cynara_response_callback(enum amd_cynara_res res, request_h req)
684 {
685         int ret;
686
687         if (res == AMD_CYNARA_ALLOWED) {
688                 ret = __check_request(req);
689                 if (ret < 0) {
690                         _request_send_result(req, ret);
691                         __free_request(req);
692                         return;
693                 } else if (ret > 0) {
694                         return;
695                 }
696                 __dispatch_request((gpointer)req);
697         } else {
698                 _E("request has been denied by cynara");
699                 ret = -EILLEGALACCESS;
700                 _request_send_result(req, ret);
701                 __free_request(req);
702         }
703
704         return;
705 }
706
707 static gboolean __request_handler(GIOChannel *io, GIOCondition cond,
708                 gpointer data)
709 {
710         int fd = g_io_channel_unix_get_fd(io);
711         app_pkt_t *pkt;
712         int ret;
713         int clifd;
714         struct ucred cr;
715         request_h req;
716         int len;
717         struct pending_item *item;
718
719         pkt = aul_sock_recv_pkt(fd, &clifd, &cr);
720         if (pkt == NULL) {
721                 _E("recv error");
722                 return TRUE;
723         }
724
725         req = __get_request(clifd, pkt, cr);
726         if (req == NULL) {
727                 close(clifd);
728                 free(pkt);
729                 return TRUE;
730         }
731         free(pkt);
732
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);
739                         __free_request(req);
740                         return TRUE;
741                 }
742
743                 ret = _cynara_check_privilege(req, __cynara_response_callback);
744                 if (ret < 0) {
745                         _E("request has been denied by cynara");
746                         ret = -EILLEGALACCESS;
747                         _request_send_result(req, ret);
748                         __free_request(req);
749                         return TRUE;
750                 } else if (ret == AMD_CYNARA_UNKNOWN) {
751                         return TRUE;
752                 }
753         } else {
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()));
759                         if (item == NULL) {
760                                 item = calloc(1, sizeof(struct pending_item));
761                                 if (item == NULL) {
762                                         _E("Out of memory");
763                                         _request_send_result(req, ret);
764                                         __free_request(req);
765                                         return TRUE;
766                                 }
767                                 item->pid = getpid();
768                                 g_hash_table_insert(pending_table,
769                                                 GINT_TO_POINTER(getpid()),
770                                                 item);
771                         }
772
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);
783                                 return TRUE;
784                         }
785                 }
786         }
787
788         ret = __check_request(req);
789         if (ret < 0) {
790                 _request_send_result(req, ret);
791                 __free_request(req);
792                 return TRUE;
793         } else if (ret > 0) {
794                 return TRUE;
795         }
796
797         __dispatch_request((gpointer)req);
798
799         return TRUE;
800 }
801
802 int _request_get_fd(request_h req)
803 {
804         return req->clifd;
805 }
806
807 int _request_get_pid(request_h req)
808 {
809         return req->pid;
810 }
811
812 pid_t _request_get_target_pid(request_h req)
813 {
814         return req->t_pid;
815 }
816
817 bundle *_request_get_bundle(request_h req)
818 {
819         return req->kb;
820 }
821
822 int _request_get_len(request_h req)
823 {
824         return req->len;
825 }
826
827 unsigned char *_request_get_raw(request_h req)
828 {
829         return req->data;
830 }
831
832 GTimeVal *_request_get_start_time(request_h req)
833 {
834         return &req->start;
835 }
836
837 request_h _request_create_local(int cmd, uid_t uid, int pid, bundle *kb)
838 {
839         request_h req;
840
841         req = (request_h)malloc(sizeof(struct request_s));
842         if (req == NULL) {
843                 _E("out of memory");
844                 return NULL;
845         }
846
847         g_get_current_time(&req->start);
848         req->timer = 0;
849         req->clifd = -1;
850         req->pid = pid;
851         req->t_pid = 0;
852         req->uid = getuid();
853         req->t_uid = uid;
854         req->cmd = cmd;
855         req->len = 0;
856         req->opt = AUL_SOCK_NONE;
857         req->kb = bundle_dup(kb);
858
859         return req;
860 }
861
862 void _request_free_local(request_h req)
863 {
864         if (req == NULL)
865                 return;
866
867         if (req->kb)
868                 bundle_free(req->kb);
869
870         free(req);
871 }
872
873 int _request_get_cmd(request_h req)
874 {
875         return req->cmd;
876 }
877
878 int _request_set_cmd(request_h req, int cmd)
879 {
880         req->cmd = cmd;
881
882         return 0;
883 }
884
885 int _request_remove_fd(request_h req)
886 {
887         int r = req->clifd;
888
889         req->clifd = 0;
890
891         return r;
892 }
893
894 uid_t _request_get_target_uid(request_h req)
895 {
896         return req->t_uid;
897 }
898
899 uid_t _request_get_uid(request_h req)
900 {
901         return req->uid;
902 }
903
904 int _request_send_raw(request_h req, int cmd, unsigned char *data, int len)
905 {
906         return aul_sock_send_raw_with_fd(_request_remove_fd(req), cmd, data,
907                         len, AUL_SOCK_NOREPLY);
908 }
909
910 int _request_send_result(request_h req, int res)
911 {
912         if (req->clifd && (req->opt & AUL_SOCK_NOREPLY))
913                 close(_request_remove_fd(req));
914         else if (req->clifd)
915                 _send_result_to_client(_request_remove_fd(req), res);
916
917         return 0;
918 }
919
920 int _request_register_cmds(const request_cmd_dispatch *cmds, int cnt)
921 {
922         int i;
923
924         if (cnt <= 0 || !__dispatch_table || !cmds)
925                 return -1;
926
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]));
931         }
932
933         return 0;
934 }
935
936 int _request_init(void)
937 {
938         _D("request init");
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");
943                 _request_fini();
944                 return -1;
945         }
946
947         amd_fd = _create_sock_activation();
948         if (amd_fd == -1) {
949                 _D("Create server socket without socket activation");
950                 amd_fd = _create_server_sock();
951                 if (amd_fd == -1) {
952                         _E("Create server socket failed.");
953                         _request_fini();
954                         return -1;
955                 }
956         }
957
958         amd_io = g_io_channel_unix_new(amd_fd);
959         if (amd_io == NULL) {
960                 _E("Failed to create gio channel");
961                 _request_fini();
962                 return -1;
963         }
964
965         amd_wid = g_io_add_watch(amd_io, G_IO_IN, __request_handler, NULL);
966         if (amd_wid == 0) {
967                 _E("Failed to add gio watch");
968                 _request_fini();
969                 return -1;
970         }
971
972         __dispatch_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
973                         NULL, NULL);
974
975         return 0;
976 }
977
978 void _request_fini(void)
979 {
980         _D("request fini");
981         if (amd_wid) {
982                 g_source_remove(amd_wid);
983                 amd_wid = 0;
984         }
985
986         if (amd_io) {
987                 g_io_channel_unref(amd_io);
988                 amd_io = NULL;
989         }
990
991         if (amd_fd > 0) {
992                 close(amd_fd);
993                 amd_fd = 0;
994         }
995
996         if (pending_table) {
997                 g_hash_table_destroy(pending_table);
998                 pending_table = NULL;
999         }
1000
1001         if (__dispatch_table) {
1002                 g_hash_table_destroy(__dispatch_table);
1003                 __dispatch_table = NULL;
1004         }
1005 }