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 free_resource(gpointer key, gpointer value, gpointer user_data)
46 struct resource *res = value;
51 static void update_resource(gpointer key, gpointer value, gpointer user_data)
53 struct resource *res = value;
56 ret = update_resource_attrs(res);
58 _E("failed to update resource attributes (name:%s,id:%d)\n",
62 static void finalize_request_client(struct request_client *client)
67 if (client->resource_table)
68 g_hash_table_foreach(client->resource_table, (GHFunc)free_resource, NULL);
72 register_resource_to_client(struct request_client *client, struct resource *res)
74 g_hash_table_insert(client->resource_table, (gpointer)&res->id, (gpointer)res);
77 static struct resource *
78 get_resource_by_id(struct request_client *client, int resource_id)
82 res = g_hash_table_lookup(client->resource_table, (gpointer)&resource_id);
87 static int handle_request_create_resource(struct request_client *client, char *args)
96 * Format of REQUEST_CREATE_RESOURCE args:
99 resource_type = atoi(args);
101 res = create_resource(resource_type);
105 register_resource_to_client(client, res);
110 static int handle_request_delete_resource(struct request_client *client, char *args)
112 struct resource *res;
115 if (!client || !args)
119 * Format of REQUEST_DELETE_RESOURCE args:
122 resource_id = atoi(args);
124 res = get_resource_by_id(client, resource_id);
128 delete_resource(res);
133 static int handle_request_update_resource(struct request_client *client, char *args)
135 struct resource *res;
138 if (!client || !args)
142 * Format of REQUEST_UPDATE_RESOURCE args:
145 resource_id = atoi(args);
147 res = get_resource_by_id(client, resource_id);
151 return update_resource_attrs(res);
154 static int handle_request_get_resource_count(struct request_client *client, char *args)
158 if (!client || !args)
162 * Format of REQUEST_GET_RESOURCE_COUNT args:
165 resource_type = atoi(args);
167 return get_resource_device_count(resource_type);
170 static int handle_request_update_resource_all(struct request_client *client, char *args)
176 * Format of REQUEST_UPDATE_RESOURCE args:
179 if (client->resource_table)
180 g_hash_table_foreach(client->resource_table, (GHFunc)update_resource, NULL);
185 static int handle_request_set_resource_attr(struct request_client *client, char *args, int request_type)
187 struct resource *res;
188 int resource_id, ret;
189 u_int64_t interest_masks;
191 if (!client || !args)
195 * Format of REQUEST_SET_RESOURCE_ATTR and REQUEST_UNSET_RESOURCE_ATTR args:
196 * - <RESOURCE_ID:INTEREST_MASK>
198 if (sscanf(args, "%d:%"PRIu64, &resource_id, &interest_masks) < 2)
201 res = get_resource_by_id(client, resource_id);
205 switch (request_type) {
206 case REQUEST_SET_RESOURCE_ATTR:
207 ret = set_resource_attr_interest(res, interest_masks);
209 case REQUEST_UNSET_RESOURCE_ATTR:
210 ret = unset_resource_attr_interest(res, interest_masks);
219 static int handle_request_is_resource_attr_supported(struct request_client *client, char *args)
221 struct resource *res;
225 if (!client || !args)
229 * Format of REQUEST_IS_RESOURCE_ATTR_SUPPORTED args:
230 * - <RESOURCE_ID:RESOURCE_ATTR_ID>
232 if (sscanf(args, "%d:%"PRIu64"", &resource_id, &attr_id) < 2)
235 res = get_resource_by_id(client, resource_id);
239 return (int)is_resource_attr_supported(res, attr_id);
242 static int handle_request_set_resource_ctrl(struct request_client *client, char *args)
244 struct resource *res;
245 int resource_id, value;
248 if (!client || !args)
252 * Format of REQUEST_SET_RESOURCE_CTRL args:
253 * - <RESOURCE_ID:CONTROL_ID:CONTROL_VALUE>
255 if (sscanf(args, "%d:%"PRIu64":%d", &resource_id, &ctrl_id, &value) < 3)
258 res = get_resource_by_id(client, resource_id);
262 return set_resource_control(res, ctrl_id, (void *)(intptr_t)value);
265 static int handle_request_get_value_int(struct request_client *client, char *args, int32_t *value)
267 struct resource *res;
271 if (!client || !args)
275 * Format of REQUEST_GET_VALUE_INT args:
276 * - <RESOURCE_ID:ATTR_ID>
278 if (sscanf(args, "%d:%"PRIu64, &resource_id, &attr_id) < 2)
281 res = get_resource_by_id(client, resource_id);
285 return get_resource_attr_int(res, attr_id, value);
288 static int handle_request_get_value_int64(struct request_client *client, char *args, int64_t *value)
290 struct resource *res;
294 if (!client || !args)
298 * Format of REQUEST_GET_VALUE_INT64 args:
299 * - <RESOURCE_ID:ATTR_ID>
301 if (sscanf(args, "%d:%"PRIu64, &resource_id, &attr_id) < 2)
304 res = get_resource_by_id(client, resource_id);
308 return get_resource_attr_int64(res, attr_id, value);
312 handle_request_get_value_uint(struct request_client *client, char *args, u_int32_t *value)
314 struct resource *res;
318 if (!client || !args)
322 * Format of REQUEST_GET_VALUE_UINT args:
323 * - <RESOURCE_ID:ATTR_ID>
325 if (sscanf(args, "%d:%"PRIu64, &resource_id, &attr_id) < 2)
328 res = get_resource_by_id(client, resource_id);
332 return get_resource_attr_uint(res, attr_id, value);
336 handle_request_get_value_uint64(struct request_client *client, char *args, u_int64_t *value)
338 struct resource *res;
342 if (!client || !args)
346 * Format of REQUEST_GET_VALUE_UINT64 args:
347 * - <RESOURCE_ID:ATTR_ID>
349 if (sscanf(args, "%d:%"PRIu64, &resource_id, &attr_id) < 2)
352 res = get_resource_by_id(client, resource_id);
356 return get_resource_attr_uint64(res, attr_id, value);
359 static int handle_request_get_value_double(struct request_client *client, char *args, double *value)
361 struct resource *res;
365 if (!client || !args)
369 * Format of REQUEST_GET_VALUE_DOUBLE args:
370 * - <RESOURCE_ID:ATTR_ID>
372 if (sscanf(args, "%d:%"PRIu64, &resource_id, &attr_id) < 2)
375 res = get_resource_by_id(client, resource_id);
379 return get_resource_attr_double(res, attr_id, value);
382 static int handle_request_get_value_string(struct request_client *client, char *args, char *value)
384 struct resource *res;
388 if (!client || !args)
392 * Format of REQUEST_GET_VALUE_INT args:
393 * - <RESOURCE_ID:ATTR_ID>
395 if (sscanf(args, "%d:%"PRIu64, &resource_id, &attr_id) < 2)
398 res = get_resource_by_id(client, resource_id);
402 return get_resource_attr_string(res, attr_id, value);
406 handle_request_get_value_array(struct request_client *client, char *args, struct array_value **arr)
408 struct resource *res;
412 if (!client || !args)
416 * Format of REQUEST_GET_VALUE_ARRAY args:
417 * - <RESOURCE_ID:ATTR_ID>
419 if (sscanf(args, "%d:%"PRIu64, &resource_id, &attr_id) < 2)
422 res = get_resource_by_id(client, resource_id);
426 return get_resource_attr_array(res, attr_id, arr);
429 static int split_request_type_and_args(char *buffer, char **args)
431 char *request_type_str;
433 request_type_str = strsep(&buffer, ":");
437 return atoi(request_type_str);
440 #define ADD_RESPONSE(__buf__, __remain__, __format__, ...) { \
441 int __len__ = snprintf(__buf__, __remain__, __format__, __VA_ARGS__); \
442 __buf__ += __len__; \
443 __remain__ -= __len__; \
444 if (__remain__ < 0) \
445 _E("failed to add response"); \
448 static void handle_request(struct request_client *client, char *buffer)
450 char _response[REQUEST_BUFFER_MAX];
451 char *response = _response;
455 int buffer_len = REQUEST_BUFFER_MAX;
457 request_type = split_request_type_and_args(buffer, &args);
461 * - <REQUEST_TYPE[:REQUEST_RESULT_PAYLOAD]:REQUEST_RESULT_VALUE>
463 ADD_RESPONSE(response, buffer_len, "%d:", request_type);
465 switch (request_type) {
466 case REQUEST_CREATE_RESOURCE:
467 ret = handle_request_create_resource(client, args);
469 _D("failed to create resource");
471 case REQUEST_DELETE_RESOURCE:
472 ret = handle_request_delete_resource(client, args);
474 _E("failed to delete resource");
476 case REQUEST_UPDATE_RESOURCE:
477 ret = handle_request_update_resource(client, args);
479 _D("failed to update resource");
481 case REQUEST_GET_RESOURCE_COUNT:
482 ret = handle_request_get_resource_count(client, args);
484 _E("failed to get resource count");
486 case REQUEST_UPDATE_RESOURCE_ALL:
487 ret = handle_request_update_resource_all(client, args);
489 _E("failed to update all resources");
491 case REQUEST_SET_RESOURCE_CTRL:
492 ret = handle_request_set_resource_ctrl(client, args);
494 _D("failed to set resource control");
496 case REQUEST_SET_RESOURCE_ATTR:
497 case REQUEST_UNSET_RESOURCE_ATTR:
498 ret = handle_request_set_resource_attr(client, args, request_type);
500 _E("failed to %s attr interest",
501 request_type == REQUEST_SET_RESOURCE_ATTR
504 case REQUEST_IS_RESOURCE_ATTR_SUPPORTED:
505 ret = handle_request_is_resource_attr_supported(client, args);
507 _E("failed to check whether attr is supported or not");
509 case REQUEST_GET_VALUE_INT:
513 ret = handle_request_get_value_int(client, args, &value);
515 _D("failed to get value");
517 ADD_RESPONSE(response, buffer_len, "%d:", value);
520 case REQUEST_GET_VALUE_INT64:
524 ret = handle_request_get_value_int64(client, args, &value);
526 _D("failed to get value");
528 ADD_RESPONSE(response, buffer_len, "%"PRId64":", value);
531 case REQUEST_GET_VALUE_UINT:
535 ret = handle_request_get_value_uint(client, args, &value);
537 _D("failed to get value");
539 ADD_RESPONSE(response, buffer_len, "%u:", value);
542 case REQUEST_GET_VALUE_UINT64:
546 ret = handle_request_get_value_uint64(client, args, &value);
548 _D("failed to get value");
550 ADD_RESPONSE(response, buffer_len, "%"PRIu64":", value);
553 case REQUEST_GET_VALUE_DOUBLE:
557 ret = handle_request_get_value_double(client, args, &value);
559 _D("failed to get value");
561 ADD_RESPONSE(response, buffer_len, "%lf:", value);
564 case REQUEST_GET_VALUE_STRING:
566 char value[BUFF_MAX];
568 ret = handle_request_get_value_string(client, args, value);
570 _D("failed to get value");
572 ADD_RESPONSE(response, buffer_len, "%s:", value);
575 case REQUEST_GET_VALUE_ARRAY:
577 struct array_value *array;
580 ret = handle_request_get_value_array(client, args, &array);
582 _D("failed to get value");
584 if (array->length == 0) {
585 ADD_RESPONSE(response, buffer_len, "%d|%d|:",
586 array->type, array->length);
590 ADD_RESPONSE(response, buffer_len, "%d|%d|", array->type, array->length);
592 switch (array->type) {
594 for (i = 0; i < array->length - 1; i++)
595 ADD_RESPONSE(response, buffer_len, "%d,",
596 ((int32_t *)array->data)[i]);
597 ADD_RESPONSE(response, buffer_len, "%d:",
598 ((int32_t *)array->data)[i]);
600 case DATA_TYPE_INT64:
601 for (i = 0; i < array->length - 1; i++)
602 ADD_RESPONSE(response, buffer_len, "%"PRId64",",
603 ((int64_t *)array->data)[i]);
604 ADD_RESPONSE(response, buffer_len, "%"PRId64":",
605 ((int64_t *)array->data)[i]);
608 for (i = 0; i < array->length - 1; i++)
609 ADD_RESPONSE(response, buffer_len, "%u,",
610 ((u_int32_t *)array->data)[i]);
611 ADD_RESPONSE(response, buffer_len, "%u:",
612 ((u_int32_t *)array->data)[i]);
614 case DATA_TYPE_UINT64:
615 for (i = 0; i < array->length - 1; i++)
616 ADD_RESPONSE(response, buffer_len, "%"PRIu64",",
617 ((u_int64_t *)array->data)[i]);
618 ADD_RESPONSE(response, buffer_len, "%"PRIu64":",
619 ((u_int64_t *)array->data)[i]);
621 case DATA_TYPE_DOUBLE:
622 for (i = 0; i < array->length - 1; i++)
623 ADD_RESPONSE(response, buffer_len, "%lf,",
624 ((double *)array->data)[i]);
625 ADD_RESPONSE(response, buffer_len, "%lf:",
626 ((double *)array->data)[i]);
628 case DATA_TYPE_STRING:
629 for (i = 0; i < array->length - 1; i++)
630 ADD_RESPONSE(response, buffer_len, "%s,",
631 ((char **)array->data)[i]);
632 ADD_RESPONSE(response, buffer_len, "%s:",
633 ((char **)array->data)[i]);
636 _E("Not supported data type");
641 _E("Invliad request type: %d", request_type);
645 ADD_RESPONSE(response, buffer_len, "%d", ret);
647 if (send(client->socket_fd, _response, strlen(_response), 0) < 0)
648 _E("Failed to send respones, error: %s", strerror(errno));
651 static GList *g_request_client_head;
652 static GMutex g_server_lock;
654 static void add_client_to_list(struct request_client *client)
659 g_mutex_lock(&g_server_lock);
660 g_request_client_head =
661 g_list_append(g_request_client_head, (gpointer)client);
662 g_mutex_unlock(&g_server_lock);
665 static void remove_client_from_list(struct request_client *client)
670 g_mutex_lock(&g_server_lock);
671 g_request_client_head =
672 g_list_remove(g_request_client_head, (gpointer)client);
673 g_mutex_unlock(&g_server_lock);
676 static void destroy_request_client(struct request_client *client)
678 remove_client_from_list(client);
682 static int request_handler_func(void *data, void **result)
684 char buffer[REQUEST_BUFFER_MAX + 1];
685 struct request_client *client = (struct request_client *)data;
688 _D("Start worker thread for client-%d", client->socket_fd);
691 len = recv(client->socket_fd, buffer, REQUEST_BUFFER_MAX, 0);
693 _D("Client-%d is disconnected", client->socket_fd);
698 _E("Error occurs while receiving request: %s", strerror(errno));
703 handle_request(client, buffer);
706 finalize_request_client(client);
707 close(client->socket_fd);
708 destroy_request_client(client);
710 return THREAD_RETURN_DONE;
713 int create_request_client(int socket_fd)
715 struct request_client *client;
717 client = malloc(sizeof(struct request_client));
719 _E("Failed to allocate memory of request_client");
723 client->socket_fd = socket_fd;
724 client->resource_table = g_hash_table_new(g_int_hash, g_int_equal);
726 create_daemon_thread(&client->worker, request_handler_func, client);
728 add_client_to_list(client);