2 * PASS (Power Aware System Service)
4 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * @file request-handler-thread.c
27 #include <util/common.h>
29 #include <util/resource.h>
30 #include <util/thread.h>
31 #include <util/device-notifier.h>
32 #include <util/devices.h>
33 #include <util/request.h>
34 #include <util/request-handler.h>
37 #include <arpa/inet.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
44 static void update_resource(gpointer key, gpointer value, gpointer user_data)
46 struct resource *res = value;
49 ret = update_resource_attrs(res);
51 _E("failed to update resource attributes (name:%s,id:%d)\n",
52 get_resource_name(res),
53 get_resource_id(res));
57 register_resource_to_client(struct request_client *client, struct resource *res)
59 g_hash_table_insert(client->resource_table,
60 GINT_TO_POINTER(get_resource_id(res)),
65 unregister_resource_from_client(struct request_client *client, int resource_id)
67 g_hash_table_remove(client->resource_table, GINT_TO_POINTER(resource_id));
70 static struct resource *
71 get_resource_by_id(struct request_client *client, int resource_id)
73 return g_hash_table_lookup(client->resource_table, GINT_TO_POINTER(resource_id));
76 static int handle_request_create_resource(struct request_client *client, char *args)
81 if (!client || !args) {
82 _E("Invalid parameter\n");
87 * Format of REQUEST_CREATE_RESOURCE args:
90 resource_type = atoi(args);
92 res = create_resource(resource_type);
94 _E("failed to create resource, res:type(%d)\n", resource_type);
98 register_resource_to_client(client, res);
100 return get_resource_id(res);
103 static int handle_request_delete_resource(struct request_client *client, char *args)
107 if (!client || !args) {
108 _E("Invalid parameter\n");
113 * Format of REQUEST_DELETE_RESOURCE args:
116 resource_id = atoi(args);
118 unregister_resource_from_client(client, resource_id);
123 static int handle_request_update_resource(struct request_client *client, char *args)
125 struct resource *res;
129 if (!client || !args) {
130 _E("Invalid parameter\n");
135 * Format of REQUEST_UPDATE_RESOURCE args:
138 resource_id = atoi(args);
140 res = get_resource_by_id(client, resource_id);
142 _E("failed to get resource, res:id(%d)\n", resource_id);
146 ret = update_resource_attrs(res);
148 _E("failed to update resource attributes, res:name(%s)id(%d)\n",
149 get_resource_name(res), resource_id);
156 static int handle_request_get_resource_count(struct request_client *client, char *args)
161 if (!client || !args) {
162 _E("Invalid parameter\n");
167 * Format of REQUEST_GET_RESOURCE_COUNT args:
170 resource_type = atoi(args);
172 ret = get_resource_device_count(resource_type);
174 _E("failed to get resource device count, res:type(%d)\n", resource_type);
181 static int handle_request_update_resource_all(struct request_client *client, char *args)
184 _E("Invalid parameter\n");
189 * Format of REQUEST_UPDATE_RESOURCE args:
192 if (client->resource_table)
193 g_hash_table_foreach(client->resource_table, (GHFunc)update_resource, NULL);
198 static int handle_request_set_resource_attr(struct request_client *client, char *args, int request_type)
200 struct resource *res;
201 int resource_id, ret;
202 u_int64_t interest_masks;
204 if (!client || !args) {
205 _E("Invalid parameter\n");
210 * Format of REQUEST_SET_RESOURCE_ATTR and REQUEST_UNSET_RESOURCE_ATTR args:
211 * - <RESOURCE_ID:INTEREST_MASK>
213 if (sscanf(args, "%d$%"PRIu64, &resource_id, &interest_masks) < 2) {
214 _E("failed to get resource and attribute id, client(%d)\n",
219 res = get_resource_by_id(client, resource_id);
221 _E("failed to get resource, client(%d) | res:name(%s)id(%d)\n",
223 get_resource_name(res), resource_id);
227 switch (request_type) {
228 case REQUEST_SET_RESOURCE_ATTR:
229 ret = set_resource_attr_interest(res, interest_masks);
231 _E("failed to set attribute interest, client(%d) | res:name(%s)id(%d)\n",
233 get_resource_name(res), resource_id);
235 case REQUEST_UNSET_RESOURCE_ATTR:
236 ret = unset_resource_attr_interest(res, interest_masks);
238 _E("failed to unset attribute interest, client(%d) | res:name(%s)id(%d)\n",
240 get_resource_name(res), resource_id);
249 static int handle_request_is_resource_attr_supported(struct request_client *client, char *args)
251 struct resource *res;
255 if (!client || !args) {
256 _E("Invalid parameter\n");
261 * Format of REQUEST_IS_RESOURCE_ATTR_SUPPORTED args:
262 * - <RESOURCE_ID:RESOURCE_ATTR_ID>
264 if (sscanf(args, "%d$%"PRIu64"", &resource_id, &attr_id) < 2) {
265 _E("failed to get resource and attribute id, client(%d)\n",
270 res = get_resource_by_id(client, resource_id);
272 _E("failed to get resource, client(%d) | res:id(%d)\n",
273 client->socket_fd, resource_id);
277 return (int)is_resource_attr_supported(res, attr_id);
280 static int handle_request_set_resource_ctrl(struct request_client *client, char *args)
282 struct resource *res;
283 int resource_id, value, ret;
286 if (!client || !args) {
287 _E("Invalid parameter\n");
292 * Format of REQUEST_SET_RESOURCE_CTRL args:
293 * - <RESOURCE_ID:CONTROL_ID:CONTROL_VALUE>
295 if (sscanf(args, "%d$%"PRIu64"$%d", &resource_id, &ctrl_id, &value) < 3) {
296 _E("failed to get resource and control id, client(%d)\n",
301 res = get_resource_by_id(client, resource_id);
303 _E("failed to get resource, client(%d) | res:id(%d)\n",
304 client->socket_fd, resource_id);
308 ret = set_resource_control(res, ctrl_id, (void *)(intptr_t)value);
310 _E("failed to set resource control, client(%d) | res:name(%s)id(%d) | ctrl:name(%s)id(%"PRId64")val(%d)\n",
312 get_resource_name(res), resource_id,
313 get_resource_control_name(res, ctrl_id), ctrl_id, value);
321 handle_request_get_json(struct request_client *client, char *args,
322 int request_type, char **json_string)
324 struct resource *res;
329 _E("Invalid parameter\n");
334 * Format of REQUEST_GET_RESOURCE_JSON args:
336 * Format of REQUEST_GET_VALUE_JSON args:
337 * - <RESOURCE_ID>:<ATTR_ID>
338 * Format of REQUEST_GET_RESOURCE_LIST_JSON args:
341 switch (request_type) {
342 case REQUEST_GET_RESOURCE_JSON:
343 resource_id = atoi(args);
345 case REQUEST_GET_VALUE_JSON:
346 if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2)
349 case REQUEST_GET_RESOURCE_LIST_JSON:
355 res = get_resource_by_id(client, resource_id);
357 _E("failed to get resource, res:id(%d)\n", resource_id);
362 switch (request_type) {
363 case REQUEST_GET_RESOURCE_JSON:
364 return get_resource_attrs_json(res, json_string);
365 case REQUEST_GET_VALUE_JSON:
366 return get_resource_attr_json(res, attr_id, json_string);
367 case REQUEST_GET_RESOURCE_LIST_JSON:
368 return get_resource_list_json(json_string);
374 static int handle_request_get_value_int(struct request_client *client, char *args, int32_t *value)
376 struct resource *res;
377 int resource_id, ret;
380 if (!client || !args) {
381 _E("Invalid parameter\n");
386 * Format of REQUEST_GET_VALUE_INT args:
387 * - <RESOURCE_ID:ATTR_ID>
389 if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
390 _E("failed to get resource and attribute id, client(%d)\n",
395 res = get_resource_by_id(client, resource_id);
397 _E("failed to get resource, client(%d) | res:id(%d)\n",
398 client->socket_fd, resource_id);
402 ret = get_resource_attr_int(res, attr_id, value);
404 _E("failed to get int value, client(%d) | res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
406 get_resource_name(res), resource_id,
407 get_resource_attr_name(res, attr_id), attr_id);
414 static int handle_request_get_value_int64(struct request_client *client, char *args, int64_t *value)
416 struct resource *res;
417 int resource_id, ret;
420 if (!client || !args) {
421 _E("Invalid parameter\n");
426 * Format of REQUEST_GET_VALUE_INT64 args:
427 * - <RESOURCE_ID:ATTR_ID>
429 if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
430 _E("failed to get resource and attribute id, client(%d)\n",
435 res = get_resource_by_id(client, resource_id);
437 _E("failed to get resource, client(%d) | res:id(%d)\n",
438 client->socket_fd, resource_id);
442 ret = get_resource_attr_int64(res, attr_id, value);
444 _E("failed to get int64 value, client(%d) | res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
446 get_resource_name(res), resource_id,
447 get_resource_attr_name(res, attr_id), attr_id);
455 handle_request_get_value_uint(struct request_client *client, char *args, u_int32_t *value)
457 struct resource *res;
458 int resource_id, ret;
461 if (!client || !args) {
462 _E("Invalid parameter\n");
467 * Format of REQUEST_GET_VALUE_UINT args:
468 * - <RESOURCE_ID:ATTR_ID>
470 if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
471 _E("failed to get resource and attribute id, client(%d)\n",
476 res = get_resource_by_id(client, resource_id);
478 _E("failed to get resource, client(%d) | res:id(%d)\n",
479 client->socket_fd, resource_id);
483 ret = get_resource_attr_uint(res, attr_id, value);
485 _E("failed to get uint value, client(%d) | res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
487 get_resource_name(res), resource_id,
488 get_resource_attr_name(res, attr_id), attr_id);
496 handle_request_get_value_uint64(struct request_client *client, char *args, u_int64_t *value)
498 struct resource *res;
499 int resource_id, ret;
502 if (!client || !args) {
503 _E("Invalid parameter\n");
508 * Format of REQUEST_GET_VALUE_UINT64 args:
509 * - <RESOURCE_ID:ATTR_ID>
511 if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
512 _E("failed to get resource and attribute id, client(%d)\n",
517 res = get_resource_by_id(client, resource_id);
519 _E("failed to get resource, client(%d) | res:id(%d)\n",
520 client->socket_fd, resource_id);
524 ret = get_resource_attr_uint64(res, attr_id, value);
526 _E("failed to get uint64 value, client(%d) | res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
528 get_resource_name(res), resource_id,
529 get_resource_attr_name(res, attr_id), attr_id);
536 static int handle_request_get_value_double(struct request_client *client, char *args, double *value)
538 struct resource *res;
539 int resource_id, ret;
542 if (!client || !args) {
543 _E("Invalid parameter\n");
548 * Format of REQUEST_GET_VALUE_DOUBLE args:
549 * - <RESOURCE_ID:ATTR_ID>
551 if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
552 _E("failed to get resource and attribute id, client(%d)\n",
557 res = get_resource_by_id(client, resource_id);
559 _E("failed to get resource, client(%d) | res:id(%d)\n",
560 client->socket_fd, resource_id);
564 ret = get_resource_attr_double(res, attr_id, value);
566 _E("failed to get double value, client(%d) | res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
568 get_resource_name(res), resource_id,
569 get_resource_attr_name(res, attr_id), attr_id);
576 static int handle_request_get_value_string(struct request_client *client, char *args, char *value)
578 struct resource *res;
579 int resource_id, ret;
582 if (!client || !args) {
583 _E("Invalid parameter\n");
588 * Format of REQUEST_GET_VALUE_INT args:
589 * - <RESOURCE_ID:ATTR_ID>
591 if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
592 _E("failed to get resource and attribute id, client(%d)\n",
597 res = get_resource_by_id(client, resource_id);
599 _E("failed to get resource, client(%d) | res:id(%d)\n",
600 client->socket_fd, resource_id);
604 ret = get_resource_attr_string(res, attr_id, value);
606 _E("failed to get string value, client(%d) | res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
608 get_resource_name(res), resource_id,
609 get_resource_attr_name(res, attr_id), attr_id);
617 handle_request_get_value_array(struct request_client *client, char *args, struct array_value **arr)
619 struct resource *res;
620 int resource_id, ret;
623 if (!client || !args) {
624 _E("Invalid parameter\n");
629 * Format of REQUEST_GET_VALUE_ARRAY args:
630 * - <RESOURCE_ID:ATTR_ID>
632 if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) {
633 _E("failed to get resource and attribute id, client(%d)\n",
638 res = get_resource_by_id(client, resource_id);
640 _E("failed to get resource, client(%d) | res:id(%d)\n",
641 client->socket_fd, resource_id);
645 ret = get_resource_attr_array(res, attr_id, arr);
647 _E("failed to get array value, client(%d) | (res:name(%s)id(%d) | attr:name(%s)id(%"PRId64")\n",
649 get_resource_name(res), resource_id,
650 get_resource_attr_name(res, attr_id), attr_id);
658 handle_request_get_resource_ts(struct request_client *client, char *args,
659 int64_t *start, int64_t *end)
661 struct resource *res;
662 int resource_id, ret;
664 if (!client || !args) {
665 _E("Invalid parameter\n");
670 * Format of REQUEST_GET_RESOURCE_TS args:
673 resource_id = atoi(args);
675 res = get_resource_by_id(client, resource_id);
677 _E("failed to get resource, client(%d) | res:id(%d)\n",
678 client->socket_fd, resource_id);
682 ret = get_resource_ts(res, start, end);
684 _E("failed to get timestamp value, client(%d) | res:name(%s)id(%d)\n",
686 get_resource_name(res), resource_id);
693 static int split_request_type_and_args(char *buffer, char **args)
695 char *request_type_str;
697 request_type_str = strsep(&buffer, "$");
701 return atoi(request_type_str);
704 #define ADD_RESPONSE(__buf__, __remain__, __format__, ...) { \
705 int __len__ = snprintf(__buf__, __remain__, __format__, __VA_ARGS__); \
706 __buf__ += __len__; \
707 __remain__ -= __len__; \
708 if (__remain__ < 0) \
709 _E("failed to add response"); \
712 static int handle_request(struct request_client *client, char *request)
714 char *response, *response_entry, *args;
715 int request_type, buffer_len, ret;
716 char err_buf[BUFF_MAX];
718 request_type = split_request_type_and_args(request, &args);
720 switch (request_type) {
721 case REQUEST_GET_RESOURCE_JSON:
722 case REQUEST_GET_VALUE_JSON:
723 case REQUEST_GET_VALUE_ARRAY:
724 case REQUEST_GET_RESOURCE_LIST_JSON:
725 buffer_len = HUGE_BUFF_MAX + 1;
728 buffer_len = GENERIC_BUFF_MAX + 1;
731 response_entry = response = malloc(buffer_len);
737 * - <REQUEST_TYPE[:REQUEST_RESULT_PAYLOAD]:REQUEST_RESULT_VALUE>
739 ADD_RESPONSE(response, buffer_len, "%d$", request_type);
741 switch (request_type) {
742 case REQUEST_CREATE_RESOURCE:
743 ret = handle_request_create_resource(client, args);
745 case REQUEST_DELETE_RESOURCE:
746 ret = handle_request_delete_resource(client, args);
748 case REQUEST_UPDATE_RESOURCE:
749 ret = handle_request_update_resource(client, args);
751 case REQUEST_GET_RESOURCE_COUNT:
752 ret = handle_request_get_resource_count(client, args);
754 case REQUEST_UPDATE_RESOURCE_ALL:
755 ret = handle_request_update_resource_all(client, args);
757 case REQUEST_SET_RESOURCE_CTRL:
758 ret = handle_request_set_resource_ctrl(client, args);
760 case REQUEST_SET_RESOURCE_ATTR:
761 case REQUEST_UNSET_RESOURCE_ATTR:
762 ret = handle_request_set_resource_attr(client, args, request_type);
764 case REQUEST_IS_RESOURCE_ATTR_SUPPORTED:
765 ret = handle_request_is_resource_attr_supported(client, args);
767 case REQUEST_GET_RESOURCE_JSON:
768 case REQUEST_GET_VALUE_JSON:
769 case REQUEST_GET_RESOURCE_LIST_JSON:
773 ret = handle_request_get_json(client, args, request_type, &json_string);
775 ADD_RESPONSE(response, buffer_len, "%s$", json_string);
780 case REQUEST_GET_VALUE_INT:
784 ret = handle_request_get_value_int(client, args, &value);
786 ADD_RESPONSE(response, buffer_len, "%d$", value);
789 case REQUEST_GET_VALUE_INT64:
793 ret = handle_request_get_value_int64(client, args, &value);
795 ADD_RESPONSE(response, buffer_len, "%"PRId64"$", value);
798 case REQUEST_GET_VALUE_UINT:
802 ret = handle_request_get_value_uint(client, args, &value);
804 ADD_RESPONSE(response, buffer_len, "%u$", value);
807 case REQUEST_GET_VALUE_UINT64:
811 ret = handle_request_get_value_uint64(client, args, &value);
813 ADD_RESPONSE(response, buffer_len, "%"PRIu64"$", value);
816 case REQUEST_GET_VALUE_DOUBLE:
820 ret = handle_request_get_value_double(client, args, &value);
822 ADD_RESPONSE(response, buffer_len, "%lf$", value);
825 case REQUEST_GET_VALUE_STRING:
827 char value[BUFF_MAX];
829 ret = handle_request_get_value_string(client, args, value);
831 ADD_RESPONSE(response, buffer_len, "%s$", value);
834 case REQUEST_GET_VALUE_ARRAY:
836 struct array_value *array;
839 ret = handle_request_get_value_array(client, args, &array);
841 if (array->length == 0) {
842 ADD_RESPONSE(response, buffer_len, "%d|%d|$",
843 array->type, array->length);
847 ADD_RESPONSE(response, buffer_len, "%d|%d|", array->type, array->length);
849 switch (array->type) {
851 for (i = 0; i < array->length - 1; i++)
852 ADD_RESPONSE(response, buffer_len, "%d,",
853 ((int32_t *)array->data)[i]);
854 ADD_RESPONSE(response, buffer_len, "%d$",
855 ((int32_t *)array->data)[i]);
857 case DATA_TYPE_INT64:
858 for (i = 0; i < array->length - 1; i++)
859 ADD_RESPONSE(response, buffer_len, "%"PRId64",",
860 ((int64_t *)array->data)[i]);
861 ADD_RESPONSE(response, buffer_len, "%"PRId64"$",
862 ((int64_t *)array->data)[i]);
865 for (i = 0; i < array->length - 1; i++)
866 ADD_RESPONSE(response, buffer_len, "%u,",
867 ((u_int32_t *)array->data)[i]);
868 ADD_RESPONSE(response, buffer_len, "%u$",
869 ((u_int32_t *)array->data)[i]);
871 case DATA_TYPE_UINT64:
872 for (i = 0; i < array->length - 1; i++)
873 ADD_RESPONSE(response, buffer_len, "%"PRIu64",",
874 ((u_int64_t *)array->data)[i]);
875 ADD_RESPONSE(response, buffer_len, "%"PRIu64"$",
876 ((u_int64_t *)array->data)[i]);
878 case DATA_TYPE_DOUBLE:
879 for (i = 0; i < array->length - 1; i++)
880 ADD_RESPONSE(response, buffer_len, "%lf,",
881 ((double *)array->data)[i]);
882 ADD_RESPONSE(response, buffer_len, "%lf$",
883 ((double *)array->data)[i]);
885 case DATA_TYPE_STRING:
886 for (i = 0; i < array->length - 1; i++)
887 ADD_RESPONSE(response, buffer_len, "%s,",
888 ((char **)array->data)[i]);
889 ADD_RESPONSE(response, buffer_len, "%s$",
890 ((char **)array->data)[i]);
893 _E("Not supported data type");
897 case REQUEST_GET_RESOURCE_TS:
901 ret = handle_request_get_resource_ts(client, args, &start, &end);
903 ADD_RESPONSE(response, buffer_len, "%"PRId64"$%"PRId64"$", start, end);
907 _E("Invliad request type: %d", request_type);
911 ADD_RESPONSE(response, buffer_len, "%d", ret);
913 if (send(client->socket_fd, response_entry, strlen(response_entry), 0) < 0) {
914 strerror_r(errno, err_buf, BUFF_MAX);
915 _E("Failed to send respones, errno: %d, error: %s", errno, err_buf);
918 free(response_entry);
923 static GList *g_request_client_head;
924 static GMutex g_server_lock;
926 static void add_client_to_list(struct request_client *client)
931 g_mutex_lock(&g_server_lock);
932 g_request_client_head =
933 g_list_append(g_request_client_head, (gpointer)client);
934 g_mutex_unlock(&g_server_lock);
937 static void remove_client_from_list(struct request_client *client)
942 g_mutex_lock(&g_server_lock);
943 g_request_client_head =
944 g_list_remove(g_request_client_head, (gpointer)client);
945 g_mutex_unlock(&g_server_lock);
948 static void destroy_request_client(struct request_client *client)
950 remove_client_from_list(client);
954 static int request_handler_func(void *data, void **result)
956 char request[GENERIC_BUFF_MAX + 1];
957 struct request_client *client = (struct request_client *)data;
959 char err_buf[BUFF_MAX];
961 _D("Client-%d is connected", client->socket_fd);
964 len = recv(client->socket_fd, request, GENERIC_BUFF_MAX, 0);
969 strerror_r(errno, err_buf, BUFF_MAX);
970 _E("Error occurs while receiving request: errno: %d, error: %s",
976 ret = handle_request(client, request);
981 _D("Client-%d is disconnected", client->socket_fd);
982 g_hash_table_destroy(client->resource_table);
983 close(client->socket_fd);
984 destroy_request_client(client);
986 return THREAD_RETURN_DONE;
989 int create_request_client(int socket_fd)
991 struct request_client *client;
993 client = malloc(sizeof(struct request_client));
995 _E("Failed to allocate memory of request_client");
999 client->socket_fd = socket_fd;
1000 client->resource_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1001 NULL, (GDestroyNotify)delete_resource);
1003 create_daemon_thread(&client->worker, request_handler_func, client);
1005 add_client_to_list(client);