Create the diag thread after daemonizing
[platform/core/multimedia/mmsvc-core.git] / server / src / muse_server_ipc.c
1 /*
2  * muse-server
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 "muse_server_private.h"
24
25 #define MSG_THREAD_NAME                                         "msg"
26 #define DATA_THREAD_NAME                                        "data"
27
28 #define DATA_WORKER_QDATA_MAX_SIZE                      (3840 * 2160 * 4) /* UHD BGRA8888 */
29 #define UNLIMITED_INSTANCE                                      -1
30
31 static void _ms_ipc_data_ch_init(muse_module_h m);
32 static void _ms_ipc_data_ch_deinit(muse_module_h m);
33 static void _ms_ipc_module_data_ch_cleanup(muse_module_h m);
34 static void _ms_ipc_module_msg_ch_cleanup(muse_module_h m);
35 static void _ms_ipc_module_cleanup(muse_module_h m);
36 static gboolean _ms_ipc_module_instance_creation_is_allowed(int module_idx);
37 static gboolean _ms_ipc_get_module_idx(muse_module_h m, void *jobj);
38 static gboolean _ms_ipc_dispatch_create(muse_module_h m, void *jobj);
39 static gboolean _ms_ipc_dispatch_destroy(muse_module_h m);
40 static gboolean _ms_ipc_dispatch_no_instance(muse_module_h m, void *jobj);
41 static gpointer _ms_ipc_dispatch_worker(gpointer data);
42 static gboolean _ms_ipc_data_processing(int fd, muse_recv_data_head_t *header, muse_channel_info_t *ch);
43 static gpointer _ms_ipc_data_worker(gpointer data);
44
45 static void _ms_ipc_data_ch_init(muse_module_h m)
46 {
47         muse_return_if_fail(m);
48
49         m->ch[MUSE_CHANNEL_DATA].data_queue = g_queue_new();
50         g_mutex_init(&m->ch[MUSE_CHANNEL_DATA].data_mutex);
51         g_cond_init(&m->ch[MUSE_CHANNEL_DATA].data_cond);
52 }
53
54 static void _ms_ipc_data_ch_deinit(muse_module_h m)
55 {
56         muse_return_if_fail(m);
57
58         g_mutex_lock(&m->ch[MUSE_CHANNEL_DATA].data_mutex);
59         g_queue_free(m->ch[MUSE_CHANNEL_DATA].data_queue);
60         m->ch[MUSE_CHANNEL_DATA].data_queue = NULL;
61         g_cond_broadcast(&m->ch[MUSE_CHANNEL_DATA].data_cond);
62         g_mutex_unlock(&m->ch[MUSE_CHANNEL_DATA].data_mutex);
63
64         g_mutex_clear(&m->ch[MUSE_CHANNEL_DATA].data_mutex);
65         g_cond_clear(&m->ch[MUSE_CHANNEL_DATA].data_cond);
66 }
67
68 static void _ms_ipc_module_data_ch_cleanup(muse_module_h m)
69 {
70         muse_return_if_fail(m);
71         muse_return_if_fail(m->ch[MUSE_CHANNEL_DATA].thread);
72
73         g_thread_join(m->ch[MUSE_CHANNEL_DATA].thread);
74         m->ch[MUSE_CHANNEL_DATA].thread = NULL;
75
76         _ms_ipc_data_ch_deinit(m);
77
78         LOGD("[close] [%d] MUSE_CHANNEL_DATA", m->ch[MUSE_CHANNEL_DATA].sock_fd);
79         muse_core_connection_close(m->ch[MUSE_CHANNEL_DATA].sock_fd);
80
81 }
82
83 static void _ms_ipc_module_msg_ch_cleanup(muse_module_h m)
84 {
85         muse_return_if_fail(m);
86         muse_return_if_fail(m->ch[MUSE_CHANNEL_MSG].thread);
87
88         SECURE_LOGD("[close] [%d] MUSE_CHANNEL_MSG %p", m->ch[MUSE_CHANNEL_MSG].sock_fd, m);
89         muse_core_connection_close(m->ch[MUSE_CHANNEL_MSG].sock_fd);
90
91         SECURE_LOGD("%p thread exit", m->ch[MUSE_CHANNEL_MSG].thread);
92         g_thread_unref(m->ch[MUSE_CHANNEL_MSG].thread);
93         m->ch[MUSE_CHANNEL_MSG].thread = NULL;
94 }
95
96 static void _ms_ipc_module_cleanup(muse_module_h m)
97 {
98         muse_return_if_fail(m);
99
100         _ms_ipc_module_data_ch_cleanup(m);
101
102         ms_connection_unregister(m);
103
104         _ms_ipc_module_msg_ch_cleanup(m);
105
106         g_mutex_clear(&m->dispatch_lock);
107
108         memset(m, 0, sizeof(muse_module_t));
109
110         free(m);
111 }
112
113 static gboolean _ms_ipc_module_instance_creation_is_allowed(int module_idx)
114 {
115         int max_instance, created_module_instance_count;
116
117         muse_return_val_if_fail(ms_check_module_idx(module_idx), FALSE);
118
119         max_instance = ms_config_get_max_instance(module_idx);
120         created_module_instance_count = muse_server_get_module_instance_count(module_idx);
121
122         if (max_instance == UNLIMITED_INSTANCE || created_module_instance_count < max_instance) {
123                 return TRUE;
124         } else {
125                 LOGW("The number (%d) of created module instance is over the value of max instance (%d)", created_module_instance_count, max_instance);
126                 return FALSE;
127         }
128 }
129
130 static gboolean _ms_ipc_get_module_idx(muse_module_h m, void *jobj)
131 {
132         muse_return_val_if_fail(m, FALSE);
133         muse_return_val_if_fail(jobj, FALSE);
134
135         if (!muse_core_msg_object_get_value(MSG_KEY_MODULE_INDEX, jobj, MUSE_TYPE_INT, &m->idx)) {
136                 LOGE("Failed to get the value of module index");
137                 return FALSE;
138         }
139
140         return TRUE;
141 }
142
143 static gboolean _ms_ipc_dispatch_create(muse_module_h m, void *jobj)
144 {
145         int pid, dispatch_ret = MM_ERROR_NONE;
146
147         muse_return_val_if_fail(m, FALSE);
148         muse_return_val_if_fail(jobj, FALSE);
149
150         ms_module_dispatch_lock(m);
151
152         if (!_ms_ipc_get_module_idx(m, jobj)) {
153                 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_DEBUG_INFO_DUMP);
154                 goto out;
155         }
156
157         m->ch[MUSE_CHANNEL_MSG].dll_handle = ms_module_open(m->idx);
158
159         if (!_ms_ipc_module_instance_creation_is_allowed(m->idx)) {
160                 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_RESOURCE_NOT_AVAILABLE);
161                 goto out;
162         }
163
164         if (muse_core_msg_object_get_value(MSG_KEY_PID, jobj, MUSE_TYPE_INT, &pid) && m->pid != pid)
165                 LOGW("connected pid [%d] msg [%d] is different", m->pid, pid);
166
167         ms_connection_register(m);
168
169         if (muse_server_is_ready())
170                 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_CREATE_SERVER_ACK);
171         else
172                 LOGW("Do not send server acknowledgement because muse server is actually not ready");
173
174         _ms_ipc_data_ch_init(m);
175
176         LOGD("module fd: %d dll_handle: %p", m->ch[MUSE_CHANNEL_MSG].sock_fd, m->ch[MUSE_CHANNEL_MSG].dll_handle);
177         dispatch_ret = ms_module_dispatch(m);
178         ms_module_dispatch_unlock(m);
179
180         if (dispatch_ret != MM_ERROR_NONE) {
181                 LOGE("create dispatch failed 0x%x, clean up module", dispatch_ret);
182                 goto out;
183         }
184
185         m->is_created = TRUE;
186
187         return TRUE;
188
189 out:
190
191         ms_module_dispatch_unlock(m);
192
193         return FALSE;
194 }
195
196 static gboolean _ms_ipc_dispatch_destroy(muse_module_h m)
197 {
198         int dispatch_ret = MM_ERROR_NONE;
199
200         muse_return_val_if_fail(m, FALSE);
201
202         ms_module_dispatch_lock(m);
203         dispatch_ret = ms_module_dispatch(m);
204         if (dispatch_ret != MM_ERROR_NONE)
205                 LOGE("destroy dispatch failed 0x%x", dispatch_ret);
206         ms_module_dispatch_unlock(m);
207
208         return FALSE;
209 }
210
211 static gboolean _ms_ipc_dispatch_no_instance(muse_module_h m, void *jobj)
212 {
213         muse_return_val_if_fail(m, FALSE);
214         muse_return_val_if_fail(jobj, FALSE);
215
216         ms_module_dispatch_lock(m);
217
218         if (!_ms_ipc_get_module_idx(m, jobj)) {
219                 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_DEBUG_INFO_DUMP);
220                 goto out;
221         }
222
223         m->ch[MUSE_CHANNEL_MSG].dll_handle = ms_module_open(m->idx);
224
225         if (!_ms_ipc_module_instance_creation_is_allowed(m->idx)) {
226                 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_RESOURCE_NOT_AVAILABLE);
227                 goto out;
228         }
229
230         ms_connection_register(m);
231
232         ms_module_dispatch(m);
233
234         SECURE_LOGW("_ms_ipc_module_cleanup [module %p] [loaded value %d]", m, ms_module_get_loaded_dllsym(m->idx));
235
236 out:
237         ms_module_dispatch_unlock(m);
238
239         return FALSE;
240 }
241
242 static gpointer _ms_ipc_dispatch_worker(gpointer data)
243 {
244         int len, fd, i;
245         int parse_len = 0;
246         muse_module_h m = NULL;
247         gboolean attempt_to_dispatch = TRUE;
248         void *jobj = NULL;
249         char err_msg[MUSE_MSG_LEN_MAX] = {'\0',};
250
251         muse_return_val_if_fail(data, NULL);
252
253         m = (muse_module_h)data;
254         muse_return_val_if_fail(m, NULL);
255
256         fd = m->ch[MUSE_CHANNEL_MSG].sock_fd;
257
258         LOGD("Enter %d", fd);
259
260         while (attempt_to_dispatch) {
261                 memset(m->recv_msg, 0x00, sizeof(m->recv_msg));
262
263                 for (i = 0; i < MUSE_NUM_FD; i++)
264                         m->ch[MUSE_CHANNEL_MSG].tbm_fd[i] = -1;
265
266                 len = muse_core_msg_recv_fd(fd, m->recv_msg, MUSE_MSG_MAX_LENGTH, m->ch[MUSE_CHANNEL_MSG].tbm_fd);
267                 if (len <= 0) {
268                         strerror_r(errno, err_msg, MUSE_MSG_LEN_MAX);
269                         LOGE("[%s] [%d] recv : %s (%d)", ms_config_get_host_name(m->idx), fd, err_msg, errno);
270                         ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_SHUTDOWN);
271                         attempt_to_dispatch = FALSE;
272                 }
273
274                 m->msg_offset = 0;
275
276                 while (attempt_to_dispatch && m->msg_offset < len && ms_is_server_ready()) {
277                         jobj = muse_core_msg_object_new(m->recv_msg + m->msg_offset, &parse_len, NULL);
278                         if (!jobj) {
279                                 LOGE("jobj is null");
280                                 attempt_to_dispatch = FALSE;
281                                 break;
282                         }
283
284                         if (muse_core_msg_object_get_value(MSG_KEY_API, jobj, MUSE_TYPE_INT, &m->api)) {
285                                 switch (m->api) {
286                                 case API_CREATE:
287                                         SECURE_LOGI("CREATE %p %d", m, fd);
288                                         attempt_to_dispatch = _ms_ipc_dispatch_create(m, jobj);
289                                         break;
290                                 case API_DESTROY:
291                                         SECURE_LOGI("DESTROY %p %d", m, fd);
292                                         attempt_to_dispatch = _ms_ipc_dispatch_destroy(m);
293                                         break;
294                                 default:
295                                         if (m->is_created) /* handle based */
296                                                 ms_module_dispatch(m);
297                                         else
298                                                 attempt_to_dispatch = _ms_ipc_dispatch_no_instance(m, jobj);
299                                         break;
300                                 }
301                         }
302                         muse_core_msg_object_free(jobj);
303                         jobj = NULL;
304                         m->msg_offset += parse_len;
305                         parse_len = len - parse_len;
306                 }
307         }
308
309         _ms_ipc_module_cleanup(m);
310
311         LOGD("worker exit");
312         g_thread_exit(NULL);
313
314         return NULL;
315 }
316
317 static gboolean _ms_ipc_data_processing(int fd, muse_recv_data_head_t *header, muse_channel_info_t *ch)
318 {
319         char *raw_data = NULL;
320
321         muse_return_val_if_fail(ms_get_instance(), FALSE);
322
323         if (!(fd > 0 && header && ch)) {
324                 LOGE("invalid param %d %p %p", fd, header, ch);
325                 goto _PROCESSING_FAILED;
326         }
327
328         /* check marker */
329         if (header->marker != MUSE_DATA_HEAD) {
330                 LOGE("invalid marker 0x%x", header->marker);
331                 goto _PROCESSING_FAILED;
332         }
333
334         /* check data size */
335         if (header->size > DATA_WORKER_QDATA_MAX_SIZE) {
336                 LOGE("invalid data size %d", header->size);
337                 goto _PROCESSING_FAILED;
338         }
339
340         /* allocation data */
341         raw_data = (char *)g_try_new0(char, header->size + sizeof(muse_recv_data_head_t));
342         if (!raw_data) {
343                 LOGE("failed to alloc data %d + %zu", header->size, sizeof(muse_recv_data_head_t));
344                 goto _PROCESSING_FAILED;
345         }
346
347         /* copy header */
348         memcpy(raw_data, header, sizeof(muse_recv_data_head_t));
349
350         /* receive data */
351         if (!muse_core_msg_recv_len(fd, raw_data + sizeof(muse_recv_data_head_t), header->size)) {
352                 LOGE("receive data failed - length %d", header->size);
353                 goto _PROCESSING_FAILED;
354         }
355
356         /* push data */
357         g_mutex_lock(&ch->data_mutex);
358         g_queue_push_tail(ch->data_queue, (gpointer)raw_data);
359         g_cond_signal(&ch->data_cond);
360         g_mutex_unlock(&ch->data_mutex);
361
362         return TRUE;
363
364 _PROCESSING_FAILED:
365
366         MUSE_G_FREE(raw_data);
367
368         ms_log_process_info(ms_get_instance()->pid);
369
370         return FALSE;
371 }
372
373 static gpointer _ms_ipc_data_worker(gpointer data)
374 {
375         char recv_buf[MUSE_MSG_LEN_MAX] = {'\0',};
376         int fd;
377         muse_module_h m = NULL;
378         muse_channel_info_t *ch = NULL;
379
380         muse_return_val_if_fail(data, NULL);
381
382         m = (muse_module_h)data;
383         SECURE_LOGW("module : %p", m);
384
385         fd = m->ch[MUSE_CHANNEL_DATA].sock_fd;
386         ch = &m->ch[MUSE_CHANNEL_DATA];
387
388         /* get data */
389         while (1) {
390                 if (!muse_core_msg_recv_len(fd, recv_buf, sizeof(muse_recv_data_head_t)))
391                         break;
392
393                 if (!_ms_ipc_data_processing(fd, (muse_recv_data_head_t *)recv_buf, ch)) {
394                         LOGE("ipc data processing failed");
395                         break;
396                 }
397         }
398
399         LOGW("Leave");
400
401         return NULL;
402 }
403
404 int ms_ipc_get_module_idx_from_job(ms_workqueue_job_t *job)
405 {
406         LOGD("Enter");
407         muse_module_h m = NULL;
408
409         muse_return_val_if_fail(job, MM_ERROR_INVALID_ARGUMENT);
410
411         m = (muse_module_h)job->user_data;
412         muse_return_val_if_fail(m, MM_ERROR_INVALID_ARGUMENT);
413
414         LOGD("Leave");
415         return m->idx;
416 }
417
418 gboolean ms_ipc_job_function(ms_workqueue_job_t *job)
419 {
420         muse_module_h m = NULL;
421         GError *error = NULL;
422
423         LOGD("Enter");
424
425         muse_return_val_if_fail(ms_get_instance(), FALSE);
426         muse_return_val_if_fail(job, FALSE);
427         muse_return_val_if_fail(ms_is_server_ready(), FALSE);
428
429         m = (muse_module_h)job->user_data;
430         muse_return_val_if_fail(m, FALSE);
431
432         SECURE_LOGD("[%p] module's msg channel fd : %d", m, m->ch[MUSE_CHANNEL_MSG].sock_fd);
433
434         m->ch[MUSE_CHANNEL_MSG].thread = g_thread_try_new(MSG_THREAD_NAME, _ms_ipc_dispatch_worker, (gpointer)m, &error);
435         if (!m->ch[MUSE_CHANNEL_MSG].thread && error) {
436                 LOGE("thread creation failed : %s", error->message);
437                 g_error_free(error);
438                 ms_log_process_info(ms_get_instance()->pid);
439         }
440
441         free(job);
442         muse_return_val_if_fail(m->ch[MUSE_CHANNEL_MSG].thread, FALSE);
443
444         LOGD("Leave");
445         return TRUE;
446 }
447
448 gboolean ms_ipc_data_job_function(ms_workqueue_job_t *job)
449 {
450         muse_module_h m = NULL;
451         GError *error = NULL;
452
453         LOGD("Enter");
454
455         muse_return_val_if_fail(ms_get_instance(), FALSE);
456         muse_return_val_if_fail(job, FALSE);
457         muse_return_val_if_fail(ms_is_server_ready(), FALSE);
458
459         m = (muse_module_h)job->user_data;
460         muse_return_val_if_fail(m, FALSE);
461
462         m->ch[MUSE_CHANNEL_DATA].thread = g_thread_try_new(DATA_THREAD_NAME, _ms_ipc_data_worker, (gpointer)m, &error);
463         if (!m->ch[MUSE_CHANNEL_DATA].thread && error) {
464                 LOGE("thread creation failed : %s", error->message);
465                 g_error_free(error);
466                 ms_log_process_info(ms_get_instance()->pid);
467                 ms_cmd_dispatch(m, MUSE_MODULE_COMMAND_RESOURCE_NOT_AVAILABLE);
468                 muse_core_connection_close(m->ch[MUSE_CHANNEL_MSG].sock_fd);
469         }
470
471         free(job);
472         muse_return_val_if_fail(m->ch[MUSE_CHANNEL_DATA].thread, FALSE);
473
474         LOGD("Leave");
475         return TRUE;
476 }
477