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