d503ab63aa5032df2fa315a426f93cbc91b82061
[platform/core/system/pass.git] / src / monitor / request-handler.c
1 /*
2  * PASS (Power Aware System Service)
3  *
4  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 /**
20  * @file        request-handler.c
21  * @brief       TBD
22  * @ingroup     TBD
23  */
24
25 #include <glib.h>
26
27 #include <util/common.h>
28 #include <util/devices.h>
29 #include <util/log.h>
30 #include <util/thread.h>
31 #include <monitor/request.h>
32 #include <monitor/monitor.h>
33
34 #include <libsyscommon/resource-manager.h>
35 #include <libsyscommon/resource-type.h>
36 #include <libsyscommon/resource-device.h>
37
38 #include <string.h>
39 #include <arpa/inet.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/un.h>
43 #include <netinet/in.h>
44 #include <sys/time.h>
45 #include <assert.h>
46 #include <fcntl.h>
47
48 #include <systemd/sd-daemon.h>
49
50 #define PENDING_MAX 3
51 #define REQUEST_SERVER_PORT 10001
52
53 struct request_client {
54         int socket_fd;
55         int nr_resources;
56         struct thread *worker;
57         GHashTable *resource_table;
58 };
59
60 struct resource_instance {
61         int id;
62         struct syscommon_resman_resource *res;
63
64         int64_t ts_start;
65         int64_t ts_end;
66 };
67
68 static int g_resource_id;
69 static bool g_request_server_run;
70 static struct thread *g_server_thread;
71
72 static void
73 register_resource_to_client(struct request_client *client, struct resource_instance *res_inst)
74 {
75         g_hash_table_insert(client->resource_table,
76                                         GINT_TO_POINTER(res_inst->id),
77                                         (gpointer)res_inst);
78 }
79
80 static void
81 unregister_resource_from_client(struct request_client *client, int resource_id)
82 {
83         g_hash_table_remove(client->resource_table, GINT_TO_POINTER(resource_id));
84 }
85
86 static struct resource_instance *
87 get_resource_instance_by_id(struct request_client *client, int resource_id)
88 {
89         return g_hash_table_lookup(client->resource_table, GINT_TO_POINTER(resource_id));
90 }
91
92 static struct syscommon_resman_resource *
93 get_resource_by_id(struct request_client *client, int resource_id)
94 {
95         struct resource_instance *res_inst = get_resource_instance_by_id(client, resource_id);
96
97         res_inst = get_resource_instance_by_id(client, resource_id);
98         if (!res_inst)
99                 return NULL;
100
101         return res_inst->res;
102 }
103
104 static int clear_sign_bit(unsigned int val)
105 {
106         return (int)((val << 1) >> 1);
107 }
108
109 static int handle_request_create_resource(struct request_client *client, char *args)
110 {
111         struct resource_instance *res_inst;
112         int resource_type, ret;
113
114         if (!client || !args) {
115                 _E("Invalid parameter\n");
116                 return -ENOENT;
117         }
118
119         res_inst = calloc(1, sizeof(struct resource_instance));
120         if (!res_inst)
121                 return -ENOMEM;
122
123         /**
124          * Format of REQUEST_CREATE_RESOURCE args:
125          *  - <RESOURCE_TYPE>
126          */
127         resource_type = atoi(args);
128
129         ret = syscommon_resman_create_resource(&res_inst->res, resource_type);
130         if (ret < 0) {
131                 _E("failed to create resource, res:type(%d)\n", resource_type);
132                 free(res_inst);
133                 return ret;
134         }
135
136         res_inst->id = clear_sign_bit(
137                         (unsigned int)__sync_fetch_and_add(&g_resource_id, 1));
138
139         register_resource_to_client(client, res_inst);
140
141         return res_inst->id;
142 }
143
144 static int handle_request_delete_resource(struct request_client *client, char *args)
145 {
146         int resource_id;
147
148         if (!client || !args) {
149                 _E("Invalid parameter\n");
150                 return -ENOENT;
151         }
152
153         /**
154          * Format of REQUEST_DELETE_RESOURCE args:
155          *  - <RESOURCE_ID>
156          */
157         resource_id = atoi(args);
158
159         unregister_resource_from_client(client, resource_id);
160
161         return 0;
162 }
163
164 inline __attribute__((always_inline)) int64_t get_time_now(void)
165 {
166         struct timeval tv;
167
168         gettimeofday(&tv, NULL);
169         return (int64_t)tv.tv_sec * 1000000 + (int64_t)tv.tv_usec;
170 }
171
172 static int handle_request_update_resource(struct request_client *client, char *args)
173 {
174         struct resource_instance *res_inst;
175         struct syscommon_resman_resource *res;
176         int resource_id;
177         int ret;
178
179         if (!client || !args) {
180                 _E("Invalid parameter\n");
181                 return -ENOENT;
182         }
183
184         /**
185          * Format of REQUEST_UPDATE_RESOURCE args:
186          *  - <RESOURCE_ID>
187          */
188         resource_id = atoi(args);
189
190         res_inst = get_resource_instance_by_id(client, resource_id);
191         if (!res_inst) {
192                 _E("failed to get resource instance, res:id(%d)\n", resource_id);
193                 return -EINVAL;
194         }
195
196         res = res_inst->res;
197
198         res_inst->ts_start = get_time_now();
199         ret = syscommon_resman_update_resource_attrs(res);
200         res_inst->ts_end = get_time_now();
201         if (ret < 0) {
202                 res_inst->ts_start = res_inst->ts_end = 0;
203                 _E("failed to update resource attributes, res:name(%s)id(%d)\n",
204                                 syscommon_resman_get_resource_name(res), resource_id);
205                 return ret;
206         }
207
208         return 0;
209 }
210
211 static int syscommon_resman_get_resource_count(int resource_type)
212 {
213         const struct syscommon_resman_resource_driver *driver;
214         int count = syscommon_resman_get_resource_device_count(resource_type);
215
216         if (count > 0)
217                 return count;
218
219         driver = syscommon_resman_find_resource_driver(resource_type);
220         if (!driver)
221                 return -EINVAL;
222
223         if (driver->flag & SYSCOMMON_RESMAN_RESOURCE_DRIVER_FLAG_COUNT_ONLY_ONE)
224                 return 1;
225         else if (driver->flag & SYSCOMMON_RESMAN_RESOURCE_DRIVER_FLAG_UNCOUNTABLE)
226                 return -EINVAL;
227
228         return 0;
229 }
230
231 static int handle_request_get_resource_count(struct request_client *client, char *args, int *value)
232 {
233         int resource_type;
234         int ret;
235
236         if (!client || !args) {
237                 _E("Invalid parameter\n");
238                 return -ENOENT;
239         }
240
241         /**
242          * Format of REQUEST_GET_RESOURCE_COUNT args:
243          *  - <RESOURCE_TYPE>
244          */
245         resource_type = atoi(args);
246
247         ret = syscommon_resman_get_resource_count(resource_type);
248         if (ret < 0) {
249                 _E("failed to get resource device count, res:type(%d)\n", resource_type);
250                 return ret;
251         }
252         *value = ret;
253
254         return 0;
255 }
256
257 static void update_resource(gpointer key, gpointer value, gpointer user_data)
258 {
259         struct resource_instance *res_inst = value;
260         struct syscommon_resman_resource *res = res_inst->res;
261         int ret;
262
263         ret = syscommon_resman_update_resource_attrs(res);
264         if (ret < 0)
265                 _E("failed to update resource attributes (name:%s,id:%d)\n",
266                                 syscommon_resman_get_resource_name(res), res_inst->id);
267 }
268
269
270 static int handle_request_update_resource_all(struct request_client *client, char *args)
271 {
272         if (!client) {
273                 _E("Invalid parameter\n");
274                 return -ENOENT;
275         }
276
277         /**
278          * Format of REQUEST_UPDATE_RESOURCE args:
279          *  - NULL
280          */
281         if (client->resource_table)
282                 g_hash_table_foreach(client->resource_table, (GHFunc)update_resource, NULL);
283
284         return 0;
285 }
286
287 static int handle_request_set_resource_attr(struct request_client *client, char *args, int request_type)
288 {
289         struct syscommon_resman_resource *res;
290         int resource_id, ret;
291         u_int64_t interest_masks;
292
293         if (!client || !args) {
294                 _E("Invalid parameter\n");
295                 return -ENOENT;
296         }
297
298         /**
299          * Format of REQUEST_SET_RESOURCE_ATTR and REQUEST_UNSET_RESOURCE_ATTR args:
300          *  - <RESOURCE_ID:INTEREST_MASK>
301          */
302         if (sscanf(args, "%d$%"PRIu64, &resource_id, &interest_masks) < 2) {
303                 _E("failed to get resource and attribute id, client(%d)\n",
304                                         client->socket_fd);
305                 return -EINVAL;
306         }
307
308         res = get_resource_by_id(client, resource_id);
309         if (!res) {
310                 _E("failed to get resource, client(%d) | res:id(%d)\n",
311                                         client->socket_fd, resource_id);
312                 return -EINVAL;
313         }
314
315         switch (request_type) {
316         case REQUEST_SET_RESOURCE_ATTR:
317                 ret = syscommon_resman_set_resource_attr_interest(res, interest_masks);
318                 if (ret < 0)
319                         _E("failed to set attribute interest, client(%d) | res:name(%s)id(%d)\n",
320                                         client->socket_fd,
321                                         syscommon_resman_get_resource_name(res), resource_id);
322                 break;
323         case REQUEST_UNSET_RESOURCE_ATTR:
324                 ret = syscommon_resman_unset_resource_attr_interest(res, interest_masks);
325                 if (ret < 0)
326                         _E("failed to unset attribute interest, client(%d) | res:name(%s)id(%d)\n",
327                                         client->socket_fd,
328                                         syscommon_resman_get_resource_name(res), resource_id);
329                 break;
330         case REQUEST_IS_RESOURCE_ATTR_SET:
331                 ret = (int)syscommon_resman_is_resource_attr_interested(res, interest_masks);
332                 break;
333         default:
334                 return -EINVAL;
335         }
336
337         return ret;
338 }
339
340 static int handle_request_set_resource_flag(struct request_client *client, char *args)
341 {
342         struct syscommon_resman_resource *res;
343         int resource_id, ret;
344         u_int64_t flag_mask;
345
346         if (!client || !args) {
347                 _E("Invalid parameter\n");
348                 return -ENOENT;
349         }
350
351         /**
352          * Format of REQUEST_SET_RESOURCE_ATTR and REQUEST_UNSET_RESOURCE_ATTR args:
353          *  - <RESOURCE_ID>
354          */
355         if (sscanf(args, "%d$%"PRIu64, &resource_id, &flag_mask) < 2) {
356                 _E("failed to get resource and flag mask, client(%d)\n",
357                                         client->socket_fd);
358                 return -EINVAL;
359         }
360
361         res = get_resource_by_id(client, resource_id);
362         if (!res) {
363                 _E("failed to get resource, client(%d) | res:id(%d)\n",
364                                         client->socket_fd, resource_id);
365                 return -EINVAL;
366         }
367
368         ret = syscommon_resman_set_resource_flag(res, flag_mask);
369         if (ret < 0) {
370                 _E("failed to set flag to %"PRIu64", client(%d) | res:name(%s)id(%d)\n",
371                                         flag_mask, client->socket_fd,
372                                         syscommon_resman_get_resource_name(res), resource_id);
373                 return ret;
374         }
375
376         return 0;
377 }
378
379 static int handle_request_is_resource_attr_supported(struct request_client *client, char *args, bool *supported)
380 {
381         struct resource *res;
382         int resource_id;
383         u_int64_t attr_id;
384
385         if (!client || !args) {
386                 _E("Invalid parameter\n");
387                 return -ENOENT;
388         }
389
390         /**
391          * Format of REQUEST_IS_RESOURCE_ATTR_SUPPORTED args:
392          *  - <RESOURCE_ID:RESOURCE_ATTR_ID>
393          */
394         if (sscanf(args, "%d$%"PRIu64"", &resource_id, &attr_id) < 2) {
395                 _E("failed to get resource and attribute id, client(%d)\n",
396                                         client->socket_fd);
397                 return -EINVAL;
398         }
399
400         res = get_resource_by_id(client, resource_id);
401         if (!res) {
402                 _E("failed to get resource, client(%d) | res:id(%d)\n",
403                                         client->socket_fd, resource_id);
404                 return -EINVAL;
405         }
406
407         return syscommon_resman_is_resource_attr_supported(res, attr_id, supported);
408 }
409
410 static int handle_request_set_resource_ctrl(struct request_client *client, char *args)
411 {
412         struct syscommon_resman_resource *res;
413         int resource_id, value, ret;
414         u_int64_t ctrl_id;
415
416         if (!client || !args) {
417                 _E("Invalid parameter\n");
418                 return -ENOENT;
419         }
420
421         /**
422          * Format of REQUEST_SET_RESOURCE_CTRL args:
423          *  - <RESOURCE_ID:CONTROL_ID:CONTROL_VALUE>
424          */
425         if (sscanf(args, "%d$%"PRIu64"$%d", &resource_id, &ctrl_id, &value) < 3) {
426                 _E("failed to get resource and control id, client(%d)\n",
427                                         client->socket_fd);
428                 return -EINVAL;
429         }
430
431         res = get_resource_by_id(client, resource_id);
432         if (!res) {
433                 _E("failed to get resource, client(%d) | res:id(%d)\n",
434                                         client->socket_fd, resource_id);
435                 return -EINVAL;
436         }
437
438         ret = syscommon_resman_set_resource_control(res, ctrl_id, (void *)(intptr_t)value);
439         if (ret < 0) {
440                 _E("failed to set resource control, client(%d) | res:name(%s)id(%d) | ctrl:name(%s)id(%"PRId64")val(%d)\n",
441                                         client->socket_fd,
442                                         syscommon_resman_get_resource_name(res), resource_id,
443                                         syscommon_resman_get_resource_control_name(res, ctrl_id), ctrl_id, value);
444                 return ret;
445         }
446
447         return 0;
448 }
449
450 static int
451 handle_request_get_json(struct request_client *client, char *args,
452                                  int request_type, char **json_string)
453 {
454         struct syscommon_resman_resource *res;
455         u_int64_t attr_id;
456         int resource_id;
457
458         if (!client) {
459                 _E("Invalid parameter\n");
460                 return -ENOENT;
461         }
462
463         /**
464          * Format of REQUEST_GET_RESOURCE_JSON args:
465          *  - <RESOURCE_ID>
466          * Format of REQUEST_GET_VALUE_JSON args:
467          *  - <RESOURCE_ID>:<ATTR_ID>
468          * Format of REQUEST_GET_RESOURCE_LIST_JSON args:
469          *  - NO ARGUMENTS
470          */
471         switch (request_type) {
472         case REQUEST_GET_RESOURCE_JSON:
473                 resource_id = atoi(args);
474                 break;
475         case REQUEST_GET_VALUE_JSON:
476                 if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2)
477                         return -EINVAL;
478                 break;
479         case REQUEST_GET_RESOURCE_LIST_JSON:
480                 goto skip_res;
481         default:
482                 return -EINVAL;
483         }
484
485         res = get_resource_by_id(client, resource_id);
486         if (!res) {
487                 _E("failed to get resource, res:id(%d)\n", resource_id);
488                 return -EINVAL;
489         }
490
491 skip_res:
492         switch (request_type) {
493         case REQUEST_GET_RESOURCE_JSON:
494                 return syscommon_resman_get_resource_attrs_json(res, json_string);
495         case REQUEST_GET_VALUE_JSON:
496                 return syscommon_resman_get_resource_attr_json(res, attr_id, json_string);
497         case REQUEST_GET_RESOURCE_LIST_JSON:
498                 return syscommon_resman_get_resource_list_json(json_string);
499         default:
500                 return -EINVAL;
501         }
502 }
503
504 static int handle_request_get_value_int(struct request_client *client, char *args, int32_t *value)
505 {
506         struct syscommon_resman_resource *res;
507         int resource_id, ret;
508         u_int64_t attr_id;
509
510         if (!client || !args) {
511                 _E("Invalid parameter\n");
512                 return -ENOENT;
513         }
514
515         /**
516          * Format of REQUEST_GET_VALUE_INT args:
517          *  - <RESOURCE_ID:ATTR_ID>
518          */
519         if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
520                 _E("failed to get resource and attribute id, client(%d)\n",
521                                         client->socket_fd);
522                 return -EINVAL;
523         }
524
525         res = get_resource_by_id(client, resource_id);
526         if (!res) {
527                 _E("failed to get resource, client(%d) | res:id(%d)\n",
528                                         client->socket_fd, resource_id);
529                 return -EINVAL;
530         }
531
532         ret = syscommon_resman_get_resource_attr_int(res, attr_id, value);
533         if (ret < 0) {
534                 _E("failed to get int value, client(%d) | res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
535                                 client->socket_fd,
536                                 syscommon_resman_get_resource_name(res), resource_id,
537                                 syscommon_resman_get_resource_attr_name(res, attr_id), attr_id);
538                 return ret;
539         }
540
541         return 0;
542 }
543
544 static int handle_request_get_value_int64(struct request_client *client, char *args, int64_t *value)
545 {
546         struct syscommon_resman_resource *res;
547         int resource_id, ret;
548         u_int64_t attr_id;
549
550         if (!client || !args) {
551                 _E("Invalid parameter\n");
552                 return -ENOENT;
553         }
554
555         /**
556          * Format of REQUEST_GET_VALUE_INT64 args:
557          *  - <RESOURCE_ID:ATTR_ID>
558          */
559         if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
560                 _E("failed to get resource and attribute id, client(%d)\n",
561                                 client->socket_fd);
562                 return -EINVAL;
563         }
564
565         res = get_resource_by_id(client, resource_id);
566         if (!res) {
567                 _E("failed to get resource, client(%d) | res:id(%d)\n",
568                                 client->socket_fd, resource_id);
569                 return -EINVAL;
570         }
571
572         ret = syscommon_resman_get_resource_attr_int64(res, attr_id, value);
573         if (ret < 0) {
574                 _E("failed to get int64 value, client(%d) | res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
575                                 client->socket_fd,
576                                 syscommon_resman_get_resource_name(res), resource_id,
577                                 syscommon_resman_get_resource_attr_name(res, attr_id), attr_id);
578                 return ret;
579         }
580
581         return 0;
582 }
583
584 static int
585 handle_request_get_value_uint(struct request_client *client, char *args, u_int32_t *value)
586 {
587         struct syscommon_resman_resource *res;
588         int resource_id, ret;
589         u_int64_t attr_id;
590
591         if (!client || !args) {
592                 _E("Invalid parameter\n");
593                 return -ENOENT;
594         }
595
596         /**
597          * Format of REQUEST_GET_VALUE_UINT args:
598          *  - <RESOURCE_ID:ATTR_ID>
599          */
600         if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
601                 _E("failed to get resource and attribute id, client(%d)\n",
602                                 client->socket_fd);
603                 return -EINVAL;
604         }
605
606         res = get_resource_by_id(client, resource_id);
607         if (!res) {
608                 _E("failed to get resource, client(%d) | res:id(%d)\n",
609                                 client->socket_fd, resource_id);
610                 return -EINVAL;
611         }
612
613         ret = syscommon_resman_get_resource_attr_uint(res, attr_id, value);
614         if (ret < 0) {
615                 _E("failed to get uint value, client(%d) | res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
616                                 client->socket_fd,
617                                 syscommon_resman_get_resource_name(res), resource_id,
618                                 syscommon_resman_get_resource_attr_name(res, attr_id), attr_id);
619                 return ret;
620         }
621
622         return 0;
623 }
624
625 static int
626 handle_request_get_value_uint64(struct request_client *client, char *args, u_int64_t *value)
627 {
628         struct syscommon_resman_resource *res;
629         int resource_id, ret;
630         u_int64_t attr_id;
631
632         if (!client || !args) {
633                 _E("Invalid parameter\n");
634                 return -ENOENT;
635         }
636
637         /**
638          * Format of REQUEST_GET_VALUE_UINT64 args:
639          *  - <RESOURCE_ID:ATTR_ID>
640          */
641         if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
642                 _E("failed to get resource and attribute id, client(%d)\n",
643                                 client->socket_fd);
644                 return -EINVAL;
645         }
646
647         res = get_resource_by_id(client, resource_id);
648         if (!res) {
649                 _E("failed to get resource, client(%d) | res:id(%d)\n",
650                                 client->socket_fd, resource_id);
651                 return -EINVAL;
652         }
653
654         ret = syscommon_resman_get_resource_attr_uint64(res, attr_id, value);
655         if (ret < 0) {
656                 _E("failed to get uint64 value, client(%d) | res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
657                                 client->socket_fd,
658                                 syscommon_resman_get_resource_name(res), resource_id,
659                                 syscommon_resman_get_resource_attr_name(res, attr_id), attr_id);
660                 return ret;
661         }
662
663         return 0;
664 }
665
666 static int handle_request_get_value_double(struct request_client *client, char *args, double *value)
667 {
668         struct syscommon_resman_resource *res;
669         int resource_id, ret;
670         u_int64_t attr_id;
671
672         if (!client || !args) {
673                 _E("Invalid parameter\n");
674                 return -ENOENT;
675         }
676
677         /**
678          * Format of REQUEST_GET_VALUE_DOUBLE args:
679          *  - <RESOURCE_ID:ATTR_ID>
680          */
681         if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
682                 _E("failed to get resource and attribute id, client(%d)\n",
683                                 client->socket_fd);
684                 return -EINVAL;
685         }
686
687         res = get_resource_by_id(client, resource_id);
688         if (!res) {
689                 _E("failed to get resource, client(%d) | res:id(%d)\n",
690                                 client->socket_fd, resource_id);
691                 return -EINVAL;
692         }
693
694         ret = syscommon_resman_get_resource_attr_double(res, attr_id, value);
695         if (ret < 0) {
696                 _E("failed to get double value,  client(%d) | res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
697                                 client->socket_fd,
698                                 syscommon_resman_get_resource_name(res), resource_id,
699                                 syscommon_resman_get_resource_attr_name(res, attr_id), attr_id);
700                 return ret;
701         }
702
703         return 0;
704 }
705
706 static int handle_request_get_value_string(struct request_client *client, char *args, char *value)
707 {
708         struct syscommon_resman_resource *res;
709         int resource_id, ret;
710         u_int64_t attr_id;
711
712         if (!client || !args) {
713                 _E("Invalid parameter\n");
714                 return -ENOENT;
715         }
716
717         /**
718          * Format of REQUEST_GET_VALUE_INT args:
719          *  - <RESOURCE_ID:ATTR_ID>
720          */
721         if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
722                 _E("failed to get resource and attribute id, client(%d)\n",
723                                 client->socket_fd);
724                 return -EINVAL;
725         }
726
727         res = get_resource_by_id(client, resource_id);
728         if (!res) {
729                 _E("failed to get resource, client(%d) | res:id(%d)\n",
730                                 client->socket_fd, resource_id);
731                 return -EINVAL;
732         }
733
734         ret = syscommon_resman_get_resource_attr_string(res, attr_id, value);
735         if (ret < 0) {
736                 _E("failed to get string value, client(%d) | res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
737                                 client->socket_fd,
738                                 syscommon_resman_get_resource_name(res), resource_id,
739                                 syscommon_resman_get_resource_attr_name(res, attr_id), attr_id);
740                 return ret;
741         }
742
743         return 0;
744 }
745
746 static int
747 handle_request_get_value_array(struct request_client *client, char *args, struct syscommon_resman_array_value **arr)
748 {
749         struct syscommon_resman_resource *res;
750         int resource_id, ret;
751         u_int64_t attr_id;
752
753         if (!client || !args) {
754                 _E("Invalid parameter\n");
755                 return -ENOENT;
756         }
757
758         /**
759          * Format of REQUEST_GET_VALUE_ARRAY args:
760          *  - <RESOURCE_ID:ATTR_ID>
761          */
762         if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
763                 _E("failed to get resource and attribute id, client(%d)\n",
764                                 client->socket_fd);
765                 return -EINVAL;
766         }
767
768         res = get_resource_by_id(client, resource_id);
769         if (!res) {
770                 _E("failed to get resource, client(%d) | res:id(%d)\n",
771                                 client->socket_fd, resource_id);
772                 return -EINVAL;
773         }
774
775         ret = syscommon_resman_get_resource_attr_array(res, attr_id, arr);
776         if (ret < 0) {
777                 _E("failed to get array value, client(%d) | (res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
778                                 client->socket_fd,
779                                 syscommon_resman_get_resource_name(res), resource_id,
780                                 syscommon_resman_get_resource_attr_name(res, attr_id), attr_id);
781                 return ret;
782         }
783
784         return 0;
785 }
786
787 static int syscommon_resman_get_resource_ts(struct resource_instance *inst, int64_t *ts_start, int64_t *ts_end)
788 {
789         if (!inst)
790                 return -EINVAL;
791
792         *ts_start = inst->ts_start;
793         *ts_end = inst->ts_end;
794
795         return 0;
796 }
797
798 static int
799 handle_request_get_resource_ts(struct request_client *client, char *args,
800                                int64_t *start, int64_t *end)
801 {
802         struct resource_instance *res_inst;
803         int resource_id, ret;
804
805         if (!client || !args) {
806                 _E("Invalid parameter\n");
807                 return -ENOENT;
808         }
809
810         /**
811          * Format of REQUEST_GET_RESOURCE_TS args:
812          *  - <RESOURCE_ID>
813          */
814         resource_id = atoi(args);
815
816         res_inst = get_resource_by_id(client, resource_id);
817         if (!res_inst) {
818                 _E("failed to get resource, client(%d) | res:id(%d)\n",
819                                 client->socket_fd, resource_id);
820                 return -EINVAL;
821         }
822
823         ret = syscommon_resman_get_resource_ts(res_inst, start, end);
824         if (ret < 0) {
825                 _E("failed to get timestamp value, client(%d) | res:name(%s)id(%d)\n",
826                                 client->socket_fd,
827                                 syscommon_resman_get_resource_name(res_inst->res), resource_id);
828                 return ret;
829         }
830
831         return 0;
832 }
833
834 static int split_request_type_and_args(char *buffer, char **args)
835 {
836         char *request_type_str;
837
838         request_type_str = strsep(&buffer, "$");
839
840         *args = buffer;
841
842         return atoi(request_type_str);
843 }
844
845 #define ADD_RESPONSE(__buf__, __remain__, __format__, ...)      { \
846         int __len__ = snprintf(__buf__, __remain__, __format__, __VA_ARGS__); \
847         __buf__ += __len__;  \
848         __remain__ -= __len__; \
849         if (__remain__ < 0) \
850                 _E("failed to add response"); \
851 } \
852
853 static int handle_request(struct request_client *client, char *request)
854 {
855         char *response, *response_entry, *args;
856         int request_type, buffer_len, ret;
857         char err_buf[BUFF_MAX];
858
859         request_type = split_request_type_and_args(request, &args);
860
861         switch (request_type) {
862         case REQUEST_GET_RESOURCE_JSON:
863         case REQUEST_GET_VALUE_JSON:
864         case REQUEST_GET_VALUE_ARRAY:
865         case REQUEST_GET_RESOURCE_LIST_JSON:
866                 buffer_len = HUGE_BUFF_MAX + 1;
867                 break;
868         default:
869                 buffer_len = GENERIC_BUFF_MAX + 1;
870         }
871
872         response_entry = response = malloc(buffer_len);
873         if (!response_entry)
874                 return -ENOMEM;
875
876         /**
877          * Format of response
878          *  - <REQUEST_TYPE[:REQUEST_RESULT_PAYLOAD]:REQUEST_RESULT_VALUE>
879          */
880         ADD_RESPONSE(response, buffer_len, "%d$", request_type);
881
882         switch (request_type) {
883         case REQUEST_CREATE_RESOURCE:
884                 ret = handle_request_create_resource(client, args);
885                 break;
886         case REQUEST_DELETE_RESOURCE:
887                 ret = handle_request_delete_resource(client, args);
888                 break;
889         case REQUEST_UPDATE_RESOURCE:
890                 ret = handle_request_update_resource(client, args);
891                 break;
892         case REQUEST_SET_RESOURCE_FLAG:
893                 ret = handle_request_set_resource_flag(client, args);
894                 break;
895         case REQUEST_GET_RESOURCE_COUNT:
896                 {
897                         int32_t value;
898
899                         ret = handle_request_get_resource_count(client, args, &value);
900
901                         ADD_RESPONSE(response, buffer_len, "%d$", value);
902                 }
903                 break;
904         case REQUEST_UPDATE_RESOURCE_ALL:
905                 ret = handle_request_update_resource_all(client, args);
906                 break;
907         case REQUEST_SET_RESOURCE_CTRL:
908                 ret = handle_request_set_resource_ctrl(client, args);
909                 break;
910         case REQUEST_SET_RESOURCE_ATTR:
911         case REQUEST_UNSET_RESOURCE_ATTR:
912         case REQUEST_IS_RESOURCE_ATTR_SET:
913                 ret = handle_request_set_resource_attr(client, args, request_type);
914                 break;
915         case REQUEST_IS_RESOURCE_ATTR_SUPPORTED:
916                 {
917                         bool supported;
918
919                         ret = handle_request_is_resource_attr_supported(client, args, &supported);
920
921                         ADD_RESPONSE(response, buffer_len, "%u$", (u_int32_t)supported);
922                 }
923                 break;
924         case REQUEST_GET_RESOURCE_JSON:
925         case REQUEST_GET_VALUE_JSON:
926         case REQUEST_GET_RESOURCE_LIST_JSON:
927                 {
928                         char *json_string;
929
930                         ret = handle_request_get_json(client, args, request_type, &json_string);
931
932                         ADD_RESPONSE(response, buffer_len, "%s$", json_string);
933
934                         free(json_string);
935                 }
936                 break;
937         case REQUEST_GET_VALUE_INT:
938                 {
939                         int32_t value;
940
941                         ret = handle_request_get_value_int(client, args, &value);
942
943                         ADD_RESPONSE(response, buffer_len, "%d$", value);
944                 }
945                 break;
946         case REQUEST_GET_VALUE_INT64:
947                 {
948                         int64_t value;
949
950                         ret = handle_request_get_value_int64(client, args, &value);
951
952                         ADD_RESPONSE(response, buffer_len, "%"PRId64"$", value);
953                 }
954                 break;
955         case REQUEST_GET_VALUE_UINT:
956                 {
957                         u_int32_t value;
958
959                         ret = handle_request_get_value_uint(client, args, &value);
960
961                         ADD_RESPONSE(response, buffer_len, "%u$", value);
962                 }
963                 break;
964         case REQUEST_GET_VALUE_UINT64:
965                 {
966                         u_int64_t value;
967
968                         ret = handle_request_get_value_uint64(client, args, &value);
969
970                         ADD_RESPONSE(response, buffer_len, "%"PRIu64"$", value);
971                 }
972                 break;
973         case REQUEST_GET_VALUE_DOUBLE:
974                 {
975                         double value;
976
977                         ret = handle_request_get_value_double(client, args, &value);
978
979                         ADD_RESPONSE(response, buffer_len, "%lf$", value);
980                 }
981                 break;
982         case REQUEST_GET_VALUE_STRING:
983                 {
984                         char value[BUFF_MAX];
985
986                         ret = handle_request_get_value_string(client, args, value);
987
988                         ADD_RESPONSE(response, buffer_len, "%s$", value);
989                 }
990                 break;
991         case REQUEST_GET_VALUE_ARRAY:
992                 {
993                         struct syscommon_resman_array_value *array;
994                         int i;
995
996                         ret = handle_request_get_value_array(client, args, &array);
997
998                         if (array->length == 0) {
999                                 ADD_RESPONSE(response, buffer_len, "%d|%d|$",
1000                                                 array->type, array->length);
1001                                 break;
1002                         }
1003
1004                         ADD_RESPONSE(response, buffer_len, "%d|%d|", array->type, array->length);
1005
1006                         switch (array->type) {
1007                         case SYSCOMMON_RESMAN_DATA_TYPE_INT:
1008                                 for (i = 0; i < array->length - 1; i++)
1009                                         ADD_RESPONSE(response, buffer_len, "%d,",
1010                                                         ((int32_t *)array->data)[i]);
1011                                 ADD_RESPONSE(response, buffer_len, "%d$",
1012                                                 ((int32_t *)array->data)[i]);
1013                                 break;
1014                         case SYSCOMMON_RESMAN_DATA_TYPE_INT64:
1015                                 for (i = 0; i < array->length - 1; i++)
1016                                         ADD_RESPONSE(response, buffer_len, "%"PRId64",",
1017                                                         ((int64_t *)array->data)[i]);
1018                                 ADD_RESPONSE(response, buffer_len, "%"PRId64"$",
1019                                                 ((int64_t *)array->data)[i]);
1020                                 break;
1021                         case SYSCOMMON_RESMAN_DATA_TYPE_UINT:
1022                                 for (i = 0; i < array->length - 1; i++)
1023                                         ADD_RESPONSE(response, buffer_len, "%u,",
1024                                                         ((u_int32_t *)array->data)[i]);
1025                                 ADD_RESPONSE(response, buffer_len, "%u$",
1026                                                 ((u_int32_t *)array->data)[i]);
1027                                 break;
1028                         case SYSCOMMON_RESMAN_DATA_TYPE_UINT64:
1029                                 for (i = 0; i < array->length - 1; i++)
1030                                         ADD_RESPONSE(response, buffer_len, "%"PRIu64",",
1031                                                         ((u_int64_t *)array->data)[i]);
1032                                 ADD_RESPONSE(response, buffer_len, "%"PRIu64"$",
1033                                                 ((u_int64_t *)array->data)[i]);
1034                                 break;
1035                         case SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE:
1036                                 for (i = 0; i < array->length - 1; i++)
1037                                         ADD_RESPONSE(response, buffer_len, "%lf,",
1038                                                         ((double *)array->data)[i]);
1039                                 ADD_RESPONSE(response, buffer_len, "%lf$",
1040                                                 ((double *)array->data)[i]);
1041                                 break;
1042                         case SYSCOMMON_RESMAN_DATA_TYPE_STRING:
1043                                 for (i = 0; i < array->length - 1; i++)
1044                                         ADD_RESPONSE(response, buffer_len, "%s,",
1045                                                         ((char **)array->data)[i]);
1046                                 ADD_RESPONSE(response, buffer_len, "%s$",
1047                                                 ((char **)array->data)[i]);
1048                                 break;
1049                         default:
1050                                 _E("Not supported data type");
1051                         }
1052                 }
1053                 break;
1054         case REQUEST_GET_RESOURCE_TS:
1055                 {
1056                         int64_t start, end;
1057
1058                         ret = handle_request_get_resource_ts(client, args, &start, &end);
1059
1060                         ADD_RESPONSE(response, buffer_len, "%"PRId64"$%"PRId64"$", start, end);
1061                 }
1062                 break;
1063         default:
1064                 _E("Invliad request type: %d", request_type);
1065                 ret = -EINVAL;
1066                 break;
1067         }
1068         ADD_RESPONSE(response, buffer_len, "%d", ret);
1069
1070         if (send(client->socket_fd, response_entry, strlen(response_entry), 0) < 0) {
1071                 strerror_r(errno, err_buf, BUFF_MAX);
1072                 _E("Failed to send respones, errno: %d, error: %s", errno, err_buf);
1073         }
1074
1075         free(response_entry);
1076
1077         return 0;
1078 }
1079
1080 static GList *g_request_client_head;
1081 static GMutex g_server_lock;
1082
1083 static void add_client_to_list(struct request_client *client)
1084 {
1085         if (!client)
1086                 return;
1087
1088         g_mutex_lock(&g_server_lock);
1089         g_request_client_head =
1090                         g_list_append(g_request_client_head, (gpointer)client);
1091         g_mutex_unlock(&g_server_lock);
1092 }
1093
1094 static void remove_client_from_list(struct request_client *client)
1095 {
1096         if (!client)
1097                 return;
1098
1099         g_mutex_lock(&g_server_lock);
1100         g_request_client_head =
1101                         g_list_remove(g_request_client_head, (gpointer)client);
1102         g_mutex_unlock(&g_server_lock);
1103 }
1104
1105 static void destroy_request_client(struct request_client *client)
1106 {
1107         remove_client_from_list(client);
1108         free(client);
1109 }
1110
1111 static int request_handler_func(void *data, void **result)
1112 {
1113         char request[GENERIC_BUFF_MAX + 1];
1114         struct request_client *client = (struct request_client *)data;
1115         int len, ret;
1116         char err_buf[BUFF_MAX];
1117
1118         _D("Client-%d is connected", client->socket_fd);
1119
1120         while (1) {
1121                 len = recv(client->socket_fd, request, GENERIC_BUFF_MAX, 0);
1122                 if (len == 0)
1123                         break;
1124
1125                 if (len < 0) {
1126                         strerror_r(errno, err_buf, BUFF_MAX);
1127                         _E("Error occurs while receiving request: errno: %d, error: %s",
1128                                         errno, err_buf);
1129                         break;
1130                 }
1131
1132                 request[len] = '\0';
1133                 ret = handle_request(client, request);
1134                 if (ret < 0)
1135                         break;
1136         }
1137
1138         _D("Client-%d is disconnected", client->socket_fd);
1139         g_hash_table_destroy(client->resource_table);
1140         close(client->socket_fd);
1141         destroy_request_client(client);
1142
1143         return THREAD_RETURN_DONE;
1144 }
1145
1146 static void delete_resource_instance(struct resource_instance *res_inst)
1147 {
1148         if (!res_inst)
1149                 return;
1150
1151         syscommon_resman_delete_resource(res_inst->res);
1152
1153         free(res_inst);
1154 }
1155
1156 static int create_request_client(int socket_fd)
1157 {
1158         struct request_client *client;
1159
1160         client = malloc(sizeof(struct request_client));
1161         if (!client) {
1162                 _E("Failed to allocate memory of request_client");
1163                 return -ENOMEM;
1164         }
1165
1166         client->socket_fd = socket_fd;
1167         client->resource_table =
1168                 g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
1169                                       (GDestroyNotify)delete_resource_instance);
1170
1171         create_daemon_thread(&client->worker, request_handler_func, client);
1172
1173         add_client_to_list(client);
1174
1175         return 0;
1176 }
1177
1178 static int init_unix_socket(int *sock, struct sockaddr_un *address, int *addrlen)
1179 {
1180         const char *server_unix_socket_path = "/run/.pass-resource-monitor.socket";
1181         int opt = true;
1182         int n = sd_listen_fds(0);
1183         int fd;
1184         int file_mode;
1185
1186         if (!sock || !address || !addrlen)
1187                 return -EINVAL;
1188
1189         bzero(address, sizeof(*address));
1190         address->sun_family = AF_UNIX;
1191         strncpy(address->sun_path, server_unix_socket_path, sizeof(address->sun_path));
1192         address->sun_path[sizeof(address->sun_path) - 1] = '\0';
1193
1194         /* use the existing systemd unix socket */
1195         if (n > 0) {
1196                 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
1197                         if (sd_is_socket_unix(fd, SOCK_STREAM, 1, server_unix_socket_path, 0) > 0) {
1198                                 *sock = fd;
1199                                 *addrlen = sizeof(*address);
1200                                 return 0;
1201                         }
1202                 }
1203         }
1204
1205         /* make a new unix socket */
1206         *sock = socket(AF_UNIX, SOCK_STREAM, 0);
1207         if (*sock < 0) {
1208                 _E("Failed to initialize socket");
1209                 goto error_out;
1210         }
1211
1212         if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR,
1213                         (char *)&opt, sizeof(opt)) < 0) {
1214                 _E("Failed to setsockopt");
1215                 goto error_out_close;
1216         }
1217
1218         if (!access(server_unix_socket_path, F_OK))
1219                 unlink(server_unix_socket_path);
1220
1221         if (bind(*sock, (struct sockaddr *)address, sizeof(*address)) < 0) {
1222                 _E("Failed to bind");
1223                 goto error_out_close;
1224         }
1225
1226         file_mode = (S_IRWXU | S_IRWXG | S_IRWXO);
1227         if (chmod(server_unix_socket_path, file_mode) < 0) {
1228                 _E("Failed to change the file mode of %s", server_unix_socket_path);
1229                 goto error_out_close;
1230         }
1231
1232         if (listen(*sock, PENDING_MAX) < 0) {
1233                 _E("Failed to begin listenning");
1234                 goto error_out_close;
1235         }
1236
1237         *addrlen = sizeof(*address);
1238
1239         return 0;
1240
1241 error_out_close:
1242         close(*sock);
1243 error_out:
1244         bzero(address, sizeof(*address));
1245
1246         return -EIO;
1247 }
1248
1249 int init_ip_socket(int *sock, struct sockaddr_in *address, int *addrlen)
1250 {
1251         int opt = true;
1252
1253         if (!sock || !address || !addrlen)
1254                 return -EINVAL;
1255
1256         *sock = socket(AF_INET, SOCK_STREAM, 0);
1257         if (*sock < 0) {
1258                 _E("Failed to initialize TCP/IP socket");
1259                 goto error_out;
1260         }
1261
1262         if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR,
1263                         (char *)&opt, sizeof(opt)) < 0) {
1264                 _E("Failed to setsockopt for TCP/IP socket");
1265                 goto error_out_close;
1266         }
1267
1268         bzero(address, sizeof(*address));
1269         address->sin_family = AF_INET;
1270         address->sin_addr.s_addr = INADDR_ANY;
1271         address->sin_port = htons(REQUEST_SERVER_PORT);
1272
1273         if (bind(*sock, (struct sockaddr *)address, sizeof(*address)) < 0) {
1274                 _E("Failed to bind for TCP/IP socket");
1275                 goto error_out_close;
1276         }
1277
1278         if (listen(*sock, PENDING_MAX) < 0) {
1279                 _E("Failed to begin listenning for TCP/IP socket");
1280                 goto error_out_close;
1281         }
1282
1283         *addrlen = sizeof(*address);
1284
1285         return 0;
1286
1287 error_out_close:
1288         close(*sock);
1289 error_out:
1290         return -EIO;
1291 }
1292
1293 static void init_resource_id(void)
1294 {
1295         int val;
1296         struct timeval tv;
1297
1298         /*
1299          * Initial g_resource_id is set by a combination of
1300          * tv_sec and tv_usec values of gettimeofday().
1301          * It ensures that PASS assigns a unique resource id
1302          * for each create_resource request.
1303          *
1304          * Even PASS is restarted, a newly initialized value
1305          * of g_resource_id reflects the current value of
1306          * gettimeofday(). Thus, the uniqueness in resource
1307          * id is kept unless the number of created resources
1308          * crosses the time consumed (in msecs) before
1309          * restarted.
1310          */
1311         gettimeofday(&tv, NULL);
1312         val = tv.tv_sec * 1000 + tv.tv_usec / 1000;
1313         g_resource_id = clear_sign_bit(val);
1314 }
1315
1316 static int request_server_func(void *ctx, void **result)
1317 {
1318         struct sockaddr_un unix_address;
1319         struct sockaddr_in ip_address;
1320         struct timeval wait;
1321         int server_unix_socket;
1322         int server_ip_socket = 0;
1323         int unix_addrlen;
1324         int ip_addrlen;
1325         int ret;
1326         fd_set fds;
1327
1328         if (!g_request_server_run)
1329                 return THREAD_RETURN_DONE;
1330
1331         init_resource_id();
1332
1333         /* 0. initialize server socket */
1334         ret = init_unix_socket(&server_unix_socket, &unix_address, &unix_addrlen);
1335         if (ret < 0)
1336                 goto error_out;
1337
1338         while (g_request_server_run) {
1339                 FD_ZERO(&fds);
1340                 FD_SET(server_unix_socket, &fds);
1341                 if (server_ip_socket)
1342                         FD_SET(server_ip_socket, &fds);
1343
1344                 wait.tv_sec = 1;
1345                 wait.tv_usec = 0;
1346
1347                 ret = select(FD_SETSIZE, &fds, NULL, NULL, &wait);
1348                 if (ret < 0) {
1349                         _E("failed to select");
1350                         goto error_out_close;
1351                 }
1352
1353                 if (FD_ISSET(server_unix_socket, &fds)) {
1354                         int new_socket = accept(server_unix_socket, (struct sockaddr *)&unix_address,
1355                                         (socklen_t *)&unix_addrlen);
1356
1357                         if (new_socket < 0) {
1358                                 _E("Failed to accept");
1359                                 goto error_out_close;
1360                         }
1361
1362                         create_request_client(new_socket);
1363                 }
1364
1365                 if (server_ip_socket && FD_ISSET(server_ip_socket, &fds)) {
1366                         int new_socket = accept(server_ip_socket, (struct sockaddr *)&ip_address,
1367                                         (socklen_t *)&ip_addrlen);
1368
1369                         if (new_socket < 0) {
1370                                 _E("Failed to accept");
1371                                 goto error_out_close;
1372                         }
1373
1374                         create_request_client(new_socket);
1375                 }
1376
1377                 if (!server_ip_socket && (monitor_get_debug_mode() == TRUE)) {
1378                         /*
1379                          * FIXME:
1380                          * server_ip_socket activation can be deferred since it
1381                          * will be done after timeout of select is expired. So,
1382                          * when the timeout is extended, this activation should be
1383                          * done by other ways in order to prevent unacceptable
1384                          * delays.
1385                          */
1386                         ret = init_ip_socket(&server_ip_socket, &ip_address, &ip_addrlen);
1387                         if (ret < 0)
1388                                 goto error_out_close_server_unix_socket;
1389                 } else if (server_ip_socket && (monitor_get_debug_mode() == FALSE)) {
1390                         close(server_ip_socket);
1391                         server_ip_socket = 0;
1392                 }
1393         }
1394
1395         close(server_unix_socket);
1396         if (server_ip_socket)
1397                 close(server_ip_socket);
1398
1399         return THREAD_RETURN_DONE;
1400
1401 error_out_close:
1402         if (server_ip_socket)
1403                 close(server_ip_socket);
1404 error_out_close_server_unix_socket:
1405         close(server_unix_socket);
1406 error_out:
1407
1408         return THREAD_RETURN_ERROR;
1409 }
1410
1411 int request_server_init(void)
1412 {
1413         g_request_server_run = true;
1414         if (create_daemon_thread(&g_server_thread, request_server_func, NULL))
1415                 _E("Failed to create request_server_thread ");
1416
1417         return 0;
1418 }
1419
1420 void request_server_exit(void)
1421 {
1422         g_request_server_run = false;
1423         destroy_thread(g_server_thread);
1424 }