af4ae9a636176cea9b7cf461002b61e333d67789
[platform/core/multimedia/mmsvc-core.git] / core / src / muse_core.c
1 /*
2  * muse-core
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: YoungHun Kim <yh8004.kim@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include "muse_core_internal.h"
23 #include <json.h>
24 #include <sys/mman.h>
25
26 #undef LOG_TAG
27 #define LOG_TAG                                                         "MUSED_CORE"
28
29 #define STR_TIME_FORMAT                                         "%m-%d %H:%M:%S"
30 #define MUSE_MIN_SEC_VALUE                                      60
31 #define MUSE_HOUR_MIN_VALUE                                     60
32 #define MUSE_DAY_HOUR_VALUE                                     24
33
34 #define MUSE_WATCHDOG_CHECK_PERIOD                      10
35 #define MUSE_WATCHDOG_CHECK_COUNT                       3
36 #define MUSE_WATCHDOG_TIMER_PERIOD                      5
37
38 static const char *msg_type[] = { "normal type", "fds type" };
39
40 static GMutex msg_lock;
41 static GMutex msg_ipc_lock;
42
43 static GMutex fd_state_lock;
44 static GHashTable *fd_state_table;
45
46 static int _muse_get_valid_fd_count(int *fds);
47 static void _muse_msg_json_set_error(muse_core_msg_parse_err_e *err, int jerr);
48 static json_object *_muse_msg_json_tokener_parse_len(const char *str, int *len, muse_core_msg_parse_err_e *err);
49 static gboolean _muse_msg_is_mem_ptr_valid(gpointer ptr);
50 static void _muse_msg_json_factory_args(json_object *jobj, va_list ap);
51 static json_object *_muse_msg_json_find_obj(json_object *jobj, const char *find_key);
52 static gboolean _muse_msg_json_get_obj_value(json_object *obj, muse_core_msg_type_e m_type, void *data);
53
54 #ifdef MUSE_GCOV_TEST
55 void muse_core_gcov_flush(void)
56 {
57         __gcov_flush();
58 }
59
60 void muse_core_setenv(const char *name, const char *value, int replace)
61 {
62         setenv(name, value, replace);
63 }
64 #endif
65
66 static int _muse_get_valid_fd_count(int *fds)
67 {
68         int idx;
69         for (idx = 0; idx < MUSE_NUM_FD; idx++) {
70                 if (fds[idx] == MUSE_ERR)
71                         break;
72         }
73         return idx;
74 }
75
76 static void _muse_msg_json_set_error(muse_core_msg_parse_err_e *err, int jerr)
77 {
78         if (err) {
79                 switch (jerr) {
80                 case json_tokener_success:
81                         *err = MUSE_MSG_PARSE_ERROR_NONE;
82                         break;
83                 case json_tokener_continue:
84                         *err = MUSE_MSG_PARSE_ERROR_CONTINUE;
85                         break;
86                 default:
87                         *err = MUSE_MSG_PARSE_ERROR_OTHER;
88                         break;
89                 }
90         }
91 }
92
93 static json_object *_muse_msg_json_tokener_parse_len(const char *str, int *len, muse_core_msg_parse_err_e *err)
94 {
95         struct json_tokener *tok = NULL;
96         struct json_object *obj = NULL;
97         int str_len = 0;
98
99         muse_return_val_if_fail(str, NULL);
100
101         tok = json_tokener_new();
102
103         if (!tok) {
104                 LOGE("tokener creation error");
105                 goto out;
106         }
107
108         str_len = strlen(str);
109         obj = json_tokener_parse_ex(tok, str, str_len);
110
111         if (!obj) {
112                 LOGE("parsing error : [length : %d] %s", str_len, str);
113                 goto out;
114         }
115
116         if (len)
117                 *len = tok->char_offset;
118
119         if (tok->err != json_tokener_success) {
120                 LOGE("Json Error(%d) : %s", tok->err, json_tokener_error_desc(tok->err));
121                 json_object_put(obj);
122                 obj = NULL;
123         }
124         _muse_msg_json_set_error(err, tok->err);
125
126 out:
127         if (tok)
128                 json_tokener_free(tok);
129
130         return obj;
131 }
132
133 static gboolean _muse_msg_is_mem_ptr_valid(gpointer ptr)
134 {
135         size_t page_size = sysconf(_SC_PAGESIZE);
136         gpointer base = (gpointer)((size_t)ptr / page_size * page_size);
137
138         return msync(base, page_size, MS_ASYNC) == 0;
139 }
140
141 static void _muse_msg_json_factory_args(json_object *jobj, va_list ap)
142 {
143         int type, len, idx;
144         char *name;
145         int *value;
146         json_object *jarr;
147
148         while ((type = va_arg(ap, int)) != 0) {
149                 name = va_arg(ap, char *);
150                 switch (type) {
151                 case MUSE_TYPE_INT:
152                         json_object_object_add(jobj, name, json_object_new_int(va_arg(ap, int32_t)));
153                         break;
154                 case MUSE_TYPE_INT64:
155                         json_object_object_add(jobj, name, json_object_new_int64(va_arg(ap, int64_t)));
156                         break;
157                 case MUSE_TYPE_POINTER:
158                         if (sizeof(intptr_t) == 8)
159                                 json_object_object_add(jobj, name, json_object_new_int64(va_arg(ap, intptr_t)));
160                         else
161                                 json_object_object_add(jobj, name, json_object_new_int(va_arg(ap, intptr_t)));
162                         break;
163                 case MUSE_TYPE_DOUBLE:
164                         json_object_object_add(jobj, name, json_object_new_double(va_arg(ap, double)));
165                         break;
166                 case MUSE_TYPE_STRING:
167                         json_object_object_add(jobj, name, json_object_new_string(va_arg(ap, char *)));
168                         break;
169                 case MUSE_TYPE_ARRAY:
170                         len = va_arg(ap, int);
171                         value = va_arg(ap, int *);
172                         jarr = json_object_new_array();
173
174                         for (idx = 0; idx < len; idx++)
175                                 json_object_array_add(jarr, json_object_new_int(value[idx]));
176                         json_object_object_add(jobj, name, jarr);
177                         break;
178                 default:
179                         LOGE("Unexpected type");
180                 }
181         }
182 }
183
184 static json_object *_muse_msg_json_find_obj(json_object *jobj, const char *find_key)
185 {
186         size_t key_len = 0;
187
188         muse_return_val_if_fail(jobj, NULL);
189
190         muse_return_val_if_fail(find_key, NULL);
191
192         key_len = strlen(find_key);
193
194         json_object_object_foreach(jobj, key, val) {
195                 if (strlen(key) == key_len && !memcmp(key, find_key, key_len))
196                         return val;
197         }
198
199         return NULL;
200 }
201
202 static gboolean _muse_msg_json_get_obj_value(json_object *obj, muse_core_msg_type_e m_type, void *data)
203 {
204         int j_type, idx, len;
205         int *int_data;
206         const char *src = NULL;
207
208         muse_return_val_if_fail(obj, FALSE);
209         muse_return_val_if_fail(data, FALSE);
210
211         j_type = json_object_get_type(obj);
212         switch (j_type) {
213         case json_type_null:
214                 LOGD("json_type_null");
215                 break;
216         case json_type_double:
217                 *(double *)data = json_object_get_double(obj);
218                 break;
219         case json_type_int:
220                 if (m_type == MUSE_TYPE_ANY || m_type == MUSE_TYPE_INT) {
221                         *(int32_t *)data = json_object_get_int(obj);
222                 } else if (m_type == MUSE_TYPE_INT64) {
223                         *(int64_t *)data = json_object_get_int64(obj);
224                 } else if (m_type == MUSE_TYPE_POINTER) {
225                         if (!_muse_msg_is_mem_ptr_valid(obj)) {
226                                 LOGE("memory pointer is not valid");
227                                 return FALSE;
228                         }
229                         if (sizeof(intptr_t) == 8)
230                                 *(intptr_t *)data = json_object_get_int64(obj);
231                         else
232                                 *(intptr_t *)data = json_object_get_int(obj);
233                 } else if (m_type == MUSE_TYPE_DOUBLE) {
234                         *(double *)data = json_object_get_double(obj);
235                 }
236                 break;
237         case json_type_object:
238                 break;
239         case json_type_string:
240                 src = json_object_get_string(obj);
241                 muse_return_val_if_fail(src, FALSE);
242                 g_strlcpy((gchar *)data, src, MUSE_MSG_MAX_LENGTH);
243                 break;
244         case json_type_array:
245                 int_data = (int *)data;
246                 len = json_object_array_length(obj);
247                 for (idx = 0; idx < len; idx++)
248                         int_data[idx] = json_object_get_int(json_object_array_get_idx(obj, idx));
249                 break;
250         default:
251                 LOGE("The value (%d) of json type is invalid", j_type);
252                 break;
253         }
254
255         return TRUE;
256 }
257
258 void muse_core_log_cmd_info(char *cmd)
259 {
260         FILE *fp;
261         char buf[MUSE_MSG_LEN_MAX];
262
263         muse_return_if_fail(cmd);
264
265         fp = popen(cmd, "r");
266
267         if (fp) {
268                 while (fgets(buf, MUSE_MSG_LEN_MAX, fp))
269                         LOGW("%s", buf);
270
271                 if (pclose(fp) == -1)
272                         LOGE("Fail to pclose");
273         }
274 }
275
276 bool muse_server_is_ready(void)
277 {
278         return access(MUSE_SERVER_READY, F_OK) == 0;
279 }
280
281 int muse_core_connection_close(int sock_fd)
282 {
283         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
284         g_autoptr(GMutexLocker) locker = NULL;
285
286         if (!muse_core_fd_is_valid(sock_fd)) {
287                 LOGE("[%d] invalid socket", sock_fd);
288                 return MM_ERROR_INVALID_ARGUMENT;
289         }
290
291         if (shutdown(sock_fd, SHUT_RDWR) == MUSE_ERR) {
292                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
293                 LOGE("[%d] failed to shutdown [error %s %d]", sock_fd, err_msg, errno);
294         }
295
296         if (close(sock_fd) == MUSE_ERR) {
297                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
298                 LOGE("[%d] failed to close [error %s %d]", sock_fd, err_msg, errno);
299         }
300
301         muse_core_dump_fd_state(sock_fd);
302
303         locker = g_mutex_locker_new(&fd_state_lock);
304
305         if (!g_hash_table_remove(fd_state_table, GINT_TO_POINTER(sock_fd)))
306                 LOGW("fail : remove fd %d from table[%p]", sock_fd, fd_state_table);
307
308         return MM_ERROR_NONE;
309 }
310
311 int muse_core_set_nonblocking(int fd, bool value)
312 {
313         int flags = fcntl(fd, F_GETFL, NULL);
314         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
315
316         if (flags >= 0) {
317                 flags = value ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK);
318                 if (fcntl(fd, F_SETFL, flags) == -1) {
319                         strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
320                         LOGE("fcntl (%d, F_SETFL, %d) [error %s %d]", fd, flags, err_msg, errno);
321                         return MM_ERROR_FILE_INTERNAL;
322                 } else {
323                         LOGD("fcntl (%d, F_SETFL)", fd);
324                 }
325         } else {
326                 LOGE("failed to get flags for %d", fd);
327                 return MM_ERROR_FILE_INTERNAL;
328         }
329
330         return MM_ERROR_NONE;
331 }
332
333 int muse_core_set_socket_timeout(int sock_fd, int timeout_sec)
334 {
335         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
336         struct timeval tv;
337
338         LOGD("Enter");
339
340         tv.tv_sec = timeout_sec;
341         tv.tv_usec = 0L;
342
343         if (setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, (void *)&tv, (socklen_t)sizeof(tv)) == MUSE_ERR) {
344                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
345                 LOGE("[%d] Failed to set socket send timeout option [error %s %d]", sock_fd, err_msg, errno);
346                 return MM_ERROR_UNKNOWN;
347         }
348
349         if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, (socklen_t)sizeof(tv)) == MUSE_ERR) {
350                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
351                 LOGE("[%d] Failed to set socket recv timeout option [error %s %d]", sock_fd, err_msg, errno);
352                 return MM_ERROR_UNKNOWN;
353         }
354
355         LOGD("Leave");
356
357         return MM_ERROR_NONE;
358 }
359
360 bool muse_core_fd_is_valid(int fd)
361 {
362         muse_core_update_fd_state(fd);
363         return (fcntl(fd, F_GETFL) != MUSE_ERR || errno != EBADF) && (fd > STDERR_FILENO);
364 }
365
366 void muse_core_fd_close(int fd)
367 {
368         if (!muse_core_fd_is_valid(fd)) {
369                 LOGW("%d is invalid fd", fd);
370                 return;
371         }
372
373         close(fd);
374 }
375
376 /* message */
377 int muse_core_msg_send(int sock_fd, const char *msg)
378 {
379         muse_return_val_if_fail(msg, MM_ERROR_INVALID_ARGUMENT);
380         return muse_core_msg_send_fd(sock_fd, NULL, msg);
381 }
382
383 int muse_core_msg_send_fd(int sock_fd, int *fds, const char *buf)
384 {
385         int ret = MM_ERROR_NONE;
386         muse_msg_info_t msg_info = {0,};
387         struct cmsghdr *cptr;
388         struct msghdr msg;
389         struct iovec iov;
390         char data[CMSG_SPACE(sizeof(int) * MUSE_NUM_FD)];
391         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
392         int *fdptr;
393         int fd_cnt = 0;
394         g_autoptr(GMutexLocker) locker = NULL;
395
396         muse_return_val_if_fail(buf, MM_ERROR_INVALID_ARGUMENT);
397         muse_return_val_if_fail(muse_core_fd_is_valid(sock_fd), MM_ERROR_INVALID_ARGUMENT);
398
399         if (!fds)
400                 msg_info.type = MUSE_MSG_TYPE_NORMAL;
401         else
402                 msg_info.type = MUSE_MSG_TYPE_FDS;
403
404         msg_info.marker = MUSE_MSG_HEAD;
405         msg_info.size = strlen(buf);
406
407         locker = g_mutex_locker_new(&msg_ipc_lock);
408
409         ret = send(sock_fd, &msg_info, sizeof(muse_msg_info_t), 0);
410         if (ret != sizeof(muse_msg_info_t)) {
411                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
412                 LOGE("[fd : %d] msg info [type : %s size : %zu] send failed : %d [error %s %d]",
413                                 sock_fd, msg_type[msg_info.type], msg_info.size, ret, err_msg, errno);
414
415                 return ret;
416         }
417
418         if (msg_info.type == MUSE_MSG_TYPE_NORMAL) {
419                 ret = send(sock_fd, buf, msg_info.size, 0);
420                 if (ret != (int)msg_info.size) {
421                         strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
422                         LOGE("[%s] send failed : %d [error %s %d]", buf, ret, err_msg, errno);
423                 }
424
425                 return ret;
426         }
427
428         /* MUSE_MSG_TYPE_FDS */
429         memset(&iov, 0, sizeof(iov));
430         iov.iov_base = (void *)buf;
431         iov.iov_len = msg_info.size;
432
433         memset(&msg, 0, sizeof(msg));
434         msg.msg_name = NULL;
435         msg.msg_namelen = 0;
436         msg.msg_iov = &iov;
437         msg.msg_iovlen = 1;
438
439         msg.msg_control = data;
440         msg.msg_controllen = sizeof(data);
441
442         cptr = CMSG_FIRSTHDR(&msg);
443         if (cptr) {
444                 fd_cnt = _muse_get_valid_fd_count(fds);
445                 cptr->cmsg_len = CMSG_LEN(sizeof(int) * fd_cnt);
446                 cptr->cmsg_level = SOL_SOCKET;
447                 cptr->cmsg_type = SCM_RIGHTS;
448                 fdptr = (int *)CMSG_DATA(cptr);
449
450                 memcpy(fdptr, fds, sizeof(int) * fd_cnt);
451
452                 /* the value of msg_controllen increases after memcpy so reassigns the original value */
453                 msg.msg_controllen = cptr->cmsg_len;
454         }
455
456         if ((ret = sendmsg(sock_fd, &msg, 0)) == SEND_FAIL) {
457                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
458                 LOGE("[%d] fail to send msg - [error %s %d]", sock_fd, err_msg, errno);
459         }
460
461         return ret;
462 }
463
464 int muse_core_msg_recv(int sock_fd, char *msg, int msg_len)
465 {
466         muse_return_val_if_fail(msg, MM_ERROR_INVALID_ARGUMENT);
467         return muse_core_msg_recv_fd(sock_fd, msg, msg_len, NULL);
468 }
469
470 int muse_core_msg_recv_fd(int sock_fd, char *buf, int buf_len, int *out_fd)
471 {
472         int ret = 0;
473         int pid;
474         struct cmsghdr *cptr;
475         struct msghdr msg;
476         struct iovec iov;
477         muse_msg_info_t msg_info = {0,};
478         char data[CMSG_SPACE(sizeof(int) * MUSE_NUM_FD)];
479         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
480
481         muse_return_val_if_fail(buf, MM_ERROR_INVALID_ARGUMENT);
482         muse_return_val_if_fail(muse_core_fd_is_valid(sock_fd), MM_ERROR_INVALID_ARGUMENT);
483
484         /* get the msg type and length */
485         if (!muse_core_msg_recv_len(sock_fd, (char *)&msg_info, sizeof(muse_msg_info_t))) {
486                 pid = (int)getpid();
487                 LOGE("[pid : %d] [fd : %d] msg info receive failed", pid, sock_fd);
488                 muse_core_log_process_thread_info(pid);
489                 return RECV_FAIL;
490         }
491
492         if (msg_info.size > 0 && buf_len < (int)msg_info.size) {
493                 LOGE("stack overflow caution !! [recv buf's length (%d) must be larger than msg's length (%zu)", buf_len, msg_info.size);
494                 return RECV_FAIL;
495         }
496
497         if (msg_info.marker != MUSE_MSG_HEAD) {
498                 LOGE("invalid marker 0x%x", msg_info.marker);
499                 return RECV_FAIL;
500         }
501
502         if (msg_info.type == MUSE_MSG_TYPE_NORMAL) {
503                 if (!muse_core_msg_recv_len(sock_fd, buf, msg_info.size)) {
504                         LOGE("msg receive failed");
505                         return RECV_FAIL;
506                 }
507
508                 ret = msg_info.size;
509         } else {
510                 memset(&iov, 0, sizeof(iov));
511                 iov.iov_base = (void *)buf;
512                 iov.iov_len = msg_info.size;
513
514                 memset(&msg, 0, sizeof(msg));
515                 msg.msg_name = NULL;
516                 msg.msg_namelen = 0;
517                 msg.msg_iov = &iov;
518                 msg.msg_iovlen = 1;
519                 msg.msg_control = data;
520                 msg.msg_controllen = sizeof(data);
521
522                 if ((ret = recvmsg(sock_fd, &msg, 0)) == RECV_FAIL) {
523                         strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
524                         LOGE("fail to receive msg [error %s %d]", err_msg, errno);
525                         return ret;
526                 }
527
528                 if (out_fd) {
529                         cptr = CMSG_FIRSTHDR(&msg);
530                         if (cptr)
531                                 memcpy(out_fd, CMSG_DATA(cptr), cptr->cmsg_len - CMSG_LEN(0));
532                 }
533         }
534
535         buf[ret] = '\0';
536
537         return ret;
538 }
539
540 char *muse_core_msg_new(int api, ...)
541 {
542         json_object *jobj;
543         const char *jsonMsg;
544         char *sndMsg;
545         va_list ap;
546
547         jobj = json_object_new_object();
548
549         muse_return_val_if_fail(jobj, NULL);
550
551         json_object_object_add(jobj, MSG_KEY_API, json_object_new_int(api));
552
553         va_start(ap, api);
554         _muse_msg_json_factory_args(jobj, ap);
555         va_end(ap);
556
557         jsonMsg = json_object_to_json_string(jobj);
558         sndMsg = g_strdup(jsonMsg);
559
560         if (api == API_CREATE)
561                 SECURE_LOGD("%s", sndMsg);
562
563         json_object_put(jobj);
564
565         return sndMsg;
566 }
567
568 bool muse_core_msg_deserialize(const char *key, char *buf, int *parse_len,
569                 muse_core_msg_parse_err_e *err, muse_core_msg_type_e m_type, void *data)
570 {
571         json_object *obj = NULL, *jobj = NULL;
572         bool ret = false;
573         g_autoptr(GMutexLocker) locker = NULL;
574
575         muse_return_val_if_fail(key, false);
576         muse_return_val_if_fail(buf, false);
577         muse_return_val_if_fail(m_type >= MUSE_TYPE_INT && m_type < MUSE_TYPE_MAX, false);
578         muse_return_val_if_fail(data, false);
579
580         locker = g_mutex_locker_new(&msg_lock);
581
582         jobj = _muse_msg_json_tokener_parse_len(buf, parse_len, err);
583         if (!jobj) {
584                 LOGE("jobj is NULL");
585                 return false;
586         }
587
588         obj = _muse_msg_json_find_obj(jobj, key);
589         if (!obj) {
590                 LOGE("\"%s\" key is not founded", key);
591                 json_object_put(jobj);
592                 return false;
593         }
594
595         ret = (bool)_muse_msg_json_get_obj_value(obj, m_type, data);
596
597         json_object_put(jobj);
598
599         return ret;
600 }
601
602 void muse_core_msg_free(char *msg)
603 {
604         MUSE_G_FREE(msg);
605 }
606
607 void *muse_core_msg_object_new(char *str, int *parse_len, muse_core_msg_parse_err_e *err)
608 {
609         muse_return_val_if_fail(str, NULL);
610
611         g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&msg_lock);
612
613         return (void *)_muse_msg_json_tokener_parse_len(str, parse_len, err);
614 }
615
616 bool muse_core_msg_object_get_value(const char *key, void *jobj, muse_core_msg_type_e m_type, void *data)
617 {
618         json_object *obj;
619         g_autoptr(GMutexLocker) locker = NULL;
620
621         muse_return_val_if_fail(key, false);
622         muse_return_val_if_fail(jobj, false);
623         muse_return_val_if_fail(data, false);
624         muse_return_val_if_fail(m_type >= MUSE_TYPE_INT && m_type < MUSE_TYPE_MAX, false);
625
626         locker = g_mutex_locker_new(&msg_lock);
627
628         obj = _muse_msg_json_find_obj((json_object *)jobj, key);
629         if (!obj) {
630                 LOGE("\"%s\" key is not found", key);
631                 return false;
632         }
633
634         return (bool)_muse_msg_json_get_obj_value(obj, m_type, data);
635 }
636
637 void muse_core_msg_object_free(void *jobj)
638 {
639         muse_return_if_fail(jobj);
640
641         g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&msg_lock);
642
643         json_object_put((json_object *)jobj);
644 }
645
646 bool muse_core_msg_recv_len(int fd, char *buf, int msg_len)
647 {
648         int offset = 0;
649         int recv_len = 0;
650         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
651
652         if (!muse_core_fd_is_valid(fd) || !buf || msg_len <= 0) {
653                 LOGE("invalid param : fd %d, buf %p, msg_len %d", fd, buf, msg_len);
654                 return false;
655         }
656
657         do {
658                 recv_len = recv(fd, buf + offset, msg_len - offset, 0);
659                 if (recv_len < 0) {
660                         strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
661                         LOGE("[%d] recv failed [error %s %d]", fd, err_msg, errno);
662                         return false;
663                 } else if (recv_len == 0) {
664                         LOGD("[%d] EOF", fd);
665                         return false;
666                 }
667
668                 offset += recv_len;
669         } while (offset < msg_len);
670
671         if (offset != msg_len) {
672                 LOGE("invalid length received : try %d -> result %d", msg_len, offset);
673                 return false;
674         }
675
676         return true;
677 }
678
679 void muse_core_change_time_format(int val, char *time_buf)
680 {
681         int sec, min, hour, day;
682
683         muse_return_if_fail(time_buf);
684
685         min = val / MUSE_MIN_SEC_VALUE;
686         hour = min / MUSE_HOUR_MIN_VALUE;
687         day = hour / MUSE_DAY_HOUR_VALUE;
688
689         sec = val % MUSE_MIN_SEC_VALUE;
690         min = min % MUSE_HOUR_MIN_VALUE;
691         hour = hour % MUSE_DAY_HOUR_VALUE;
692
693         snprintf(time_buf, MUSE_MSG_TIME_LEN, "%dd %dh %dm %ds", day, hour, min, sec);
694 }
695
696 void muse_core_dump_fd_state(int fd)
697 {
698         int sec = 0;
699         char time_buf[MUSE_MSG_TIME_LEN];
700
701         g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&fd_state_lock);
702
703         sec = GPOINTER_TO_INT(g_hash_table_lookup(fd_state_table, GINT_TO_POINTER(fd)));
704         muse_core_change_time_format(sec, time_buf);
705         LOGI("[%d] %s", fd, time_buf);
706 }
707
708 void muse_core_update_fd_state(int fd)
709 {
710         struct timespec tv;
711
712         g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&fd_state_lock);
713
714         if (!fd_state_table)
715                 fd_state_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
716
717         muse_core_get_cur_time(&tv, NULL);
718         g_hash_table_insert(fd_state_table, GINT_TO_POINTER(fd), GINT_TO_POINTER((int)tv.tv_sec));
719 }
720
721 gboolean muse_core_set_close_on_exec(int fd)
722 {
723         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
724
725         if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
726                 strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
727                 LOGE("unable to set FD_CLOEXEC on fd %d: %s", fd, err_msg);
728                 return FALSE;
729         }
730
731         return TRUE;
732 }
733
734 void muse_core_create_fd_table(void)
735 {
736         g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&fd_state_lock);
737
738         if (fd_state_table) {
739                 LOGW("fd state table [%p] is already created", fd_state_table);
740                 return;
741         }
742
743         fd_state_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
744         if (!fd_state_table)
745                 LOGE("fail to create new fd state table");
746 }
747
748 void muse_core_remove_all_fd_table(void)
749 {
750         g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&fd_state_lock);
751         g_hash_table_remove_all(fd_state_table);
752 }
753
754 void muse_core_destroy_fd_table(void)
755 {
756         g_autoptr(GMutexLocker) locker = g_mutex_locker_new(&fd_state_lock);
757         g_hash_table_destroy(fd_state_table);
758         fd_state_table = NULL;
759 }
760
761 void muse_core_get_cur_time(struct timespec *time, char *time_buf)
762 {
763         char cur_time[MUSE_MSG_LEN];
764         struct tm newtime;
765         struct timespec tv;
766
767         muse_return_if_fail(clock_gettime(CLOCK_MONOTONIC, &tv) == 0);
768
769         if (time)
770                 *time = tv;
771
772         if (time_buf) {
773                 strftime(cur_time, MUSE_MSG_LEN, STR_TIME_FORMAT, localtime_r(&(tv.tv_sec), &newtime));
774                 snprintf(time_buf, MUSE_MSG_TIME_LEN, "%s.%03ld", cur_time, tv.tv_nsec);
775         }
776 }
777
778 void muse_core_log_process_thread_info(int pid)
779 {
780         char cmd[MUSE_MSG_LEN_MAX];
781
782         snprintf(cmd, sizeof(cmd), "/bin/cat /proc/%d/status | /bin/grep Threads", pid);
783         muse_core_log_cmd_info(cmd);
784 }
785
786 void muse_core_log_process_opened_fds(int pid)
787 {
788         char dir_path[MUSE_MSG_LEN_MAX];
789         struct dirent *de = NULL;
790         DIR *dr = NULL;
791
792         snprintf(dir_path, sizeof(dir_path), "/proc/%d/fd", pid); /* /proc/%d/fd is directory */
793         dr = opendir(dir_path);
794         muse_return_if_fail(dr);
795
796         LOGI("directory path : %s", dir_path);
797
798         while ((de = readdir(dr)) != NULL)
799                 LOGW("%s\n", de->d_name);
800
801         closedir(dr);
802 }
803
804 void muse_core_log_process_cpu_memory(int pid)
805 {
806         char cmd[MUSE_MSG_LEN_MAX];
807
808         snprintf(cmd, sizeof(cmd), "/bin/ps -Lo pcpu,pmem,tid,comm -p %d", pid);
809         muse_core_log_cmd_info(cmd);
810 }
811
812 int muse_core_get_process_cpu_usage(int pid)
813 {
814         FILE *fp = NULL;
815         int cpu = 0;
816         char cmd[MUSE_MSG_LEN_MAX];
817         char buf[MUSE_MSG_LEN_MAX];
818
819         snprintf(cmd, sizeof(cmd), "/bin/ps -Lo pcpu,pmem,tid,comm -p %d", pid);
820
821         fp = popen(cmd, "r");
822
823         if (fp) {
824                 while (fgets(buf, MUSE_MSG_LEN_MAX, fp)) {
825                         LOGI("%s", buf);
826                         cpu += atoi(g_strstrip(buf));
827                 }
828
829                 if (pclose(fp) == -1)
830                         LOGE("Fail to pclose");
831         }
832
833         return cpu;
834 }
835
836 void muse_core_log_file_list(const char *path)
837 {
838         char cmd[MUSE_MSG_LEN_MAX];
839
840         snprintf(cmd, sizeof(cmd), "/bin/ls -alt %s", path);
841         muse_core_log_cmd_info(cmd);
842 }
843
844 void muse_core_remove_symlink(const char *path)
845 {
846         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
847         char *r = NULL;
848
849         muse_return_if_fail(path);
850
851         r = realpath(path, NULL);
852         if (r) {
853                 if (strncmp(r, path, strlen(path)) != 0) {
854                         LOGW("symbolic link exists [%s] -> [%s]", path, r);
855                         unlink(path);
856                 }
857                 free(r);
858         } else {
859                 if (errno != ENOENT) {
860                         strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
861                         LOGE("realpath failed [error %s %d]", err_msg, errno);
862                 }
863         }
864 }
865