4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jiyong Min <jiyong.min@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include "media-util.h"
27 #include "media-common-utils.h"
28 #include "media-common-system.h"
29 #include "media-server-dbg.h"
30 #include "media-server-dcm.h"
31 #include <tzplatform_config.h>
37 #define LOG_TAG "MEDIA_SERVER_DCM"
39 #define DCM_SERVER_PATH tzplatform_mkpath(TZ_SYS_BIN, "dcm-svc")
41 static GMainLoop *g_dcm_agent_loop = NULL;
42 static GIOChannel *g_dcm_tcp_channel = NULL;
43 static gboolean g_folk_dcm_server = FALSE;
44 static gboolean g_dcm_server_extracting = FALSE;
45 static gboolean g_shutdowning_dcm_server = FALSE;
46 static gboolean g_dcm_server_queued_all_extracting_request = FALSE;
47 static int g_dcm_comm_sock = 0;
48 static int g_dcm_timer_id = 0;
49 static int g_dcm_service_pid = 0;
51 static GQueue *g_dcm_request_queue = NULL;
52 static int g_dcm_queue_work = 0;
59 extern char MEDIA_IPC_PATH[][70];
61 gboolean _ms_dcm_agent_timer();
62 gboolean _ms_dcm_check_queued_request(gpointer data);
63 gboolean _ms_dcm_agent_prepare_tcp_socket(int *sock_fd, unsigned short serv_port);
66 int ms_dcm_get_server_pid()
68 return g_dcm_service_pid;
71 void ms_dcm_reset_server_status()
73 g_folk_dcm_server = FALSE;
74 g_shutdowning_dcm_server = FALSE;
76 if (g_dcm_timer_id > 0) {
77 g_source_destroy(g_main_context_find_source_by_id(g_main_context_get_thread_default(), g_dcm_timer_id));
81 if (g_dcm_server_extracting) {
82 /* Need to inplement when crash happens */
83 MS_DBG_ERR("DCM server is dead when processing all-dcm extraction");
84 g_dcm_server_extracting = FALSE;
85 MS_DBG("g_dcm_server_extracting is false");
86 g_dcm_service_pid = 0;
88 g_dcm_server_extracting = FALSE;
89 MS_DBG("g_dcm_server_extracting is false");
90 g_dcm_service_pid = 0;
96 void _ms_dcm_create_timer(int id)
99 g_source_destroy(g_main_context_find_source_by_id(g_main_context_get_thread_default(), id));
101 GSource *timer_src = g_timeout_source_new_seconds(MS_TIMEOUT_SEC_60);
102 g_source_set_callback(timer_src, _ms_dcm_agent_timer, NULL, NULL);
103 g_dcm_timer_id = g_source_attach(timer_src, g_main_context_get_thread_default());
107 int _media_dcm_get_error()
109 if (errno == EWOULDBLOCK) {
110 MS_DBG_ERR("Timeout. Can't try any more");
111 return MS_MEDIA_ERR_SOCKET_RECEIVE_TIMEOUT;
113 MS_DBG_STRERROR("recvfrom failed");
114 return MS_MEDIA_ERR_SOCKET_RECEIVE;
118 int _ms_dcm_recv_msg(int sock, dcmMsg *msg)
120 int recv_msg_len = 0;
121 unsigned char *buf = NULL;
123 MS_DBG("_ms_dcm_recv_msg in");
125 MS_MALLOC(buf, sizeof(dcmMsg));
127 MS_DBG_STRERROR("malloc failed");
128 return MS_MEDIA_ERR_OUT_OF_MEMORY;
131 if ((recv_msg_len = recv(sock, buf, sizeof(dcmMsg), 0)) < 0) {
132 MS_DBG_STRERROR("recv failed");
134 return _media_dcm_get_error();
136 memcpy(msg, buf, sizeof(dcmMsg));
140 MS_DBG("_ms_dcm_recv_msg out %d", msg->msg_type);
142 return MS_MEDIA_ERR_NONE;
145 gboolean _ms_dcm_agent_recv_msg_from_server()
147 struct sockaddr_un serv_addr;
148 unsigned int serv_addr_len;
152 MS_DBG("_ms_dcm_agent_recv_msg_from_server in");
154 if (g_dcm_comm_sock <= 0)
155 _ms_dcm_agent_prepare_tcp_socket(&g_dcm_comm_sock, MS_DCM_COMM_PORT);
157 serv_addr_len = sizeof(serv_addr);
159 if ((sockfd = accept(g_dcm_comm_sock, (struct sockaddr*)&serv_addr, &serv_addr_len)) < 0) {
160 MS_DBG_STRERROR("accept failed");
168 recv_result = _ms_dcm_recv_msg(sockfd, & recv_msg);
169 if (recv_result != MS_MEDIA_ERR_NONE) {
170 MS_DBG_STRERROR("_ms_dcm_recv_msg failed");
175 if (recv_msg.msg_type == MS_MSG_DCM_SERVER_READY) {
176 MS_DBG("DCM service is ready");
178 MS_DBG("DCM service is not ready retry=%d", retry);
186 MS_DBG("_ms_dcm_agent_recv_msg_from_server out %d", recv_msg.msg_type);
192 gboolean _ms_dcm_agent_recv_dcm_done_from_server(GIOChannel *src, GIOCondition condition, gpointer data)
194 int ret = MS_MEDIA_ERR_NONE;
195 struct sockaddr_un dcm_serv_addr;
196 unsigned int dcm_serv_addr_len;
199 int dcm_serv_sockfd = -1;
201 /* Once all-dcm extraction is done, check if there is queued all-dcm request */
202 GSource *check_queued_all_dcm_request = NULL;
203 check_queued_all_dcm_request = g_idle_source_new();
204 g_source_set_callback(check_queued_all_dcm_request, _ms_dcm_check_queued_request, NULL, NULL);
205 g_source_attach(check_queued_all_dcm_request, g_main_context_get_thread_default());
207 if (g_dcm_server_extracting == FALSE) {
208 MS_DBG_WARN("Recv DCM service extracting done already");
212 sockfd = g_io_channel_unix_get_fd(src);
214 MS_DBG_ERR("sock fd is invalid!");
218 dcm_serv_addr_len = sizeof(dcm_serv_addr);
220 if ((dcm_serv_sockfd = accept(sockfd, (struct sockaddr*)&dcm_serv_addr, &dcm_serv_addr_len)) < 0) {
221 MS_DBG_STRERROR("accept failed");
227 MS_DBG_WARN("DCM service SOCKET %d", dcm_serv_sockfd);
229 ret = ms_ipc_receive_message(dcm_serv_sockfd, &recv_msg, sizeof(dcmMsg));
230 if (ret != MS_MEDIA_ERR_NONE) {
231 MS_DBG_STRERROR("ms_ipc_receive_message failed");
232 close(dcm_serv_sockfd);
236 close(dcm_serv_sockfd);
238 MS_DBG("Receive : %d", recv_msg.msg_type);
239 if (recv_msg.msg_type == MS_MSG_DCM_EXTRACT_ALL_DONE) {
240 MS_DBG("DCM extracting done");
241 g_dcm_server_extracting = FALSE;
242 MS_DBG("g_dcm_server_extracting is false");
250 gboolean _ms_dcm_agent_execute_server()
257 } else if (pid == 0) {
258 execl(DCM_SERVER_PATH, "dcm-svc", NULL);
260 MS_DBG("Child process for dcm is %d", pid);
261 g_folk_dcm_server = TRUE;
264 g_dcm_service_pid = pid;
266 if (!_ms_dcm_agent_recv_msg_from_server()) {
267 MS_DBG_ERR("_ms_dcm_agent_recv_msg_from_server is failed");
274 gboolean _ms_dcm_agent_send_msg_to_dcm_server(dcmMsg *recv_msg, dcmMsg *res_msg)
277 ms_sock_info_s sock_info;
278 struct sockaddr_un serv_addr;
279 int send_str_len = strlen(recv_msg->msg);
281 if (send_str_len > MAX_FILEPATH_LEN) {
282 MS_DBG_ERR("original path's length exceeds %d(max packet size)", MAX_FILEPATH_LEN);
286 if (ms_ipc_create_client_socket(MS_PROTOCOL_TCP, MS_TIMEOUT_SEC_60, &sock_info) < 0) {
287 MS_DBG_ERR("ms_ipc_create_client_socket failed");
291 if (recv_msg->uid == 0)
292 ms_sys_get_uid(&(recv_msg->uid));
293 memset(&serv_addr, 0, sizeof(serv_addr));
294 sock = sock_info.sock_fd;
295 serv_addr.sun_family = AF_UNIX;
296 strncpy(serv_addr.sun_path, tzplatform_mkpath(TZ_SYS_RUN, MEDIA_IPC_PATH[MS_DCM_DAEMON_PORT]), strlen(tzplatform_mkpath(TZ_SYS_RUN, MEDIA_IPC_PATH[MS_DCM_DAEMON_PORT])));
298 /* Connecting to the DCM service */
299 if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
300 MS_DBG_STRERROR("connect");
301 return MS_MEDIA_ERR_SOCKET_CONN;
304 if (send(sock, recv_msg, sizeof(dcmMsg), 0) != sizeof(dcmMsg)) {
305 MS_DBG_STRERROR("send failed");
306 ms_ipc_delete_client_socket(&sock_info);
310 MS_DBG_SLOG("Sending msg to DCM service is successful %d", recv_msg->msg_type);
312 if (_ms_dcm_recv_msg(sock, res_msg) < 0) {
313 MS_DBG_ERR("_ms_dcm_recv_msg failed");
314 ms_ipc_delete_client_socket(&sock_info);
318 MS_DBG_SLOG("recv %s(%d, %d) from DCM daemon is successful", res_msg->msg, res_msg->msg_type, res_msg->result);
319 ms_ipc_delete_client_socket(&sock_info);
321 if (res_msg->msg_type == DCM_REQUEST_MEDIA && g_dcm_comm_sock > 0) { /* DCM_REQUEST_ALL_MEDIA */
322 GSource *source = NULL;
323 if (g_dcm_tcp_channel == NULL)
324 g_dcm_tcp_channel = g_io_channel_unix_new(g_dcm_comm_sock);
325 source = g_io_create_watch(g_dcm_tcp_channel, G_IO_IN);
327 /* Set callback to be called when socket is readable */
328 g_source_set_callback(source, (GSourceFunc)_ms_dcm_agent_recv_dcm_done_from_server, NULL, NULL);
329 g_source_attach(source, g_main_context_get_thread_default());
331 g_dcm_server_extracting = TRUE;
332 MS_DBG("g_dcm_server_extracting is true");
338 gboolean _ms_dcm_check_queued_request(gpointer data)
340 if (g_dcm_server_queued_all_extracting_request) {
341 MS_DBG_WARN("There is queued request");
343 /* request all-DCM extraction to DCM service */
346 memset((void *)&msg, 0, sizeof(msg));
347 memset((void *)&recv_msg, 0, sizeof(recv_msg));
349 msg.msg_type = 1; /* DCM_REQUEST_ALL_MEDIA */
350 ms_sys_get_uid(&(msg.uid));
354 /* Command All-DCM extraction to DCM service */
355 if (!_ms_dcm_agent_send_msg_to_dcm_server(&msg, &recv_msg))
356 MS_DBG_ERR("_ms_dcm_agent_send_msg_to_dcm_server is failed");
358 g_dcm_server_queued_all_extracting_request = FALSE;
360 MS_DBG("There is no queued request");
367 gboolean _ms_dcm_agent_timer()
369 if (g_dcm_server_extracting) {
370 MS_DBG("Timer is called.. But dcm-service[%d] is busy.. so timer is recreated", g_dcm_service_pid);
372 _ms_dcm_create_timer(g_dcm_timer_id);
377 MS_DBG("Timer is called.. Now killing dcm-service[%d]", g_dcm_service_pid);
379 if (g_dcm_service_pid > 0) {
380 /* Kill DCM service */
383 memset((void *)&msg, 0, sizeof(msg));
384 memset((void *)&recv_msg, 0, sizeof(recv_msg));
386 msg.msg_type = 4; /* DCM_REQUEST_KILL_SERVER */
390 /* Command Kill to DCM service */
391 g_shutdowning_dcm_server = TRUE;
392 if (!_ms_dcm_agent_send_msg_to_dcm_server(&msg, &recv_msg)) {
393 MS_DBG_ERR("_ms_dcm_agent_send_msg_to_dcm_server is failed");
394 g_shutdowning_dcm_server = FALSE;
398 MS_DBG_ERR("g_dcm_service_pid is %d. Maybe there's problem in dcm-service", g_dcm_service_pid);
404 gboolean _ms_dcm_request_to_server(gpointer data)
408 req_len = g_queue_get_length(g_dcm_request_queue);
410 MS_DBG("Queue length : %d", req_len);
413 MS_DBG("There is no request job in the queue");
414 g_dcm_queue_work = 0;
418 if (g_shutdowning_dcm_server) {
419 MS_DBG_ERR("DCM service is shutting down... wait for complete");
424 if (g_folk_dcm_server == FALSE && g_dcm_server_extracting == FALSE) {
425 if (g_dcm_service_pid <= 0) { /* This logic is temporary */
426 MS_DBG_WARN("DCM service is not running.. so start it");
427 if (!_ms_dcm_agent_execute_server()) {
428 MS_DBG_ERR("_ms_dcm_agent_execute_server is failed");
429 g_dcm_queue_work = 0;
432 _ms_dcm_create_timer(g_dcm_timer_id);
436 /* Timer is re-created*/
437 _ms_dcm_create_timer(g_dcm_timer_id);
440 dcmRequest *req = NULL;
441 req = (dcmRequest *)g_queue_pop_head(g_dcm_request_queue);
443 // MS_DBG("Pop request %d %p", req->recv_msg->msg_type);
446 MS_DBG_ERR("Failed to get a request job from queue");
450 int client_sock = -1;
451 dcmMsg *recv_msg = NULL;
453 memset((void *)&res_msg, 0, sizeof(res_msg));
455 client_sock = req->client_sock;
456 recv_msg = req->recv_msg;
458 if (req->client_sock <= 0 || req->recv_msg == NULL) {
459 MS_DBG_ERR("client sock is below 0 or recv msg is NULL");
460 MS_SAFE_FREE(req->recv_msg);
466 if (recv_msg->msg_type == 1 && g_dcm_server_extracting) {
467 MS_DBG_WARN("DCM service is already extracting..This request is queued.");
468 g_dcm_server_queued_all_extracting_request = TRUE;
470 if (!_ms_dcm_agent_send_msg_to_dcm_server(recv_msg, &res_msg)) {
471 MS_DBG_ERR("_ms_dcm_agent_send_msg_to_dcm_server is failed");
474 memset((void *)&res_msg, 0, sizeof(res_msg));
476 res_msg.msg_type = recv_msg->msg_type;
477 res_msg.msg_size = strlen(recv_msg->msg);
478 if (res_msg.msg_size > 0)
479 strncpy(res_msg.msg, recv_msg->msg, res_msg.msg_size);
480 res_msg.result = recv_msg->result;
482 if (send(client_sock, &res_msg, sizeof(res_msg), 0) != sizeof(res_msg))
483 MS_DBG_STRERROR("sendto failed");
485 MS_DBG("Sent Refuse msg from %s", recv_msg->msg);
489 MS_SAFE_FREE(req->recv_msg);
496 MS_DBG_ERR("recv_msg is NULL from queue request");
499 strncpy(res_msg.msg, recv_msg->msg, recv_msg->msg_size);
500 res_msg.msg_size = recv_msg->msg_size;
502 if (send(client_sock, &res_msg, sizeof(res_msg), 0) != sizeof(res_msg))
503 MS_DBG_STRERROR("sendto failed");
506 MS_SAFE_FREE(req->recv_msg);
512 gboolean _ms_dcm_agent_read_socket(GIOChannel *src,
513 GIOCondition condition,
516 struct sockaddr_un client_addr;
517 unsigned int client_addr_len;
518 dcmMsg *recv_msg = NULL;
520 int client_sock = -1;
523 int cl = sizeof(struct ucred);
525 sock = g_io_channel_unix_get_fd(src);
527 MS_DBG_ERR("sock fd is invalid!");
531 client_addr_len = sizeof(client_addr);
533 if ((client_sock = accept(sock, (struct sockaddr*)&client_addr, &client_addr_len)) < 0) {
534 MS_DBG_STRERROR("accept failed");
538 MS_DBG("Client[%d] is accepted", client_sock);
540 recv_msg = calloc(1, sizeof(dcmMsg));
541 if (recv_msg == NULL) {
542 MS_DBG_ERR("Failed to allocate memory");
547 if (_ms_dcm_recv_msg(client_sock, recv_msg) < 0) {
548 MS_DBG_ERR("_ms_dcm_recv_msg failed ");
550 MS_SAFE_FREE(recv_msg);
554 if (getsockopt(client_sock, SOL_SOCKET, SO_PEERCRED, &cr, (socklen_t *) &cl) < 0) {
555 MS_DBG_ERR("credential information error");
558 if (getuid() != cr.uid)
559 recv_msg->uid = cr.uid;
561 dcmRequest *dcm_req = NULL;
563 MS_MALLOC(dcm_req, sizeof(dcmRequest));
564 if (dcm_req == NULL) {
565 MS_DBG_ERR("Failed to create request element");
567 MS_SAFE_FREE(recv_msg);
571 dcm_req->client_sock = client_sock;
572 dcm_req->recv_msg = recv_msg;
574 if (g_dcm_request_queue == NULL) {
575 MS_DBG_WARN("queue is init");
576 g_dcm_request_queue = g_queue_new();
579 if (g_queue_get_length(g_dcm_request_queue) >= MAX_DCM_REQUEST) {
580 MS_DBG_WARN("Request Queue is full");
582 memset((void *)&res_msg, 0, sizeof(res_msg));
584 res_msg.msg_type = recv_msg->msg_type;
585 if (res_msg.msg_size != 0) {
586 res_msg.msg_size = recv_msg->msg_size;
587 strncpy(res_msg.msg, recv_msg->msg, res_msg.msg_size);
590 if (send(client_sock, &res_msg, sizeof(dcmMsg), 0) != sizeof(dcmMsg))
591 MS_DBG_STRERROR("sendto failed");
593 MS_DBG("Sent Refuse msg from %s", recv_msg->msg);
596 MS_SAFE_FREE(dcm_req->recv_msg);
597 MS_SAFE_FREE(dcm_req);
602 MS_DBG_SLOG("%s is queued", recv_msg->msg);
603 g_queue_push_tail(g_dcm_request_queue, (gpointer)dcm_req);
605 if (!g_dcm_queue_work) {
606 GSource *src_request = NULL;
607 src_request = g_idle_source_new();
608 g_source_set_callback(src_request, _ms_dcm_request_to_server, NULL, NULL);
609 g_source_attach(src_request, g_main_context_get_thread_default());
610 g_dcm_queue_work = 1;
616 gboolean _ms_dcm_agent_prepare_tcp_socket(int *sock_fd, unsigned short serv_port)
620 if (ms_ipc_create_server_socket(MS_PROTOCOL_TCP, serv_port, &sock) < 0) {
621 MS_DBG_ERR("_ms_dcm_create_socket failed");
630 gpointer ms_dcm_agent_start_thread(gpointer data)
633 GSource *source = NULL;
634 GIOChannel *channel = NULL;
635 GMainContext *context = NULL;
639 /* Create and bind new TCP socket */
640 if (!_ms_dcm_agent_prepare_tcp_socket(&sockfd, MS_DCM_CREATOR_PORT)) {
641 MS_DBG_ERR("Failed to create socket");
645 context = g_main_context_new();
648 MS_DBG_ERR("g_main_context_new failed");
650 MS_DBG("g_main_context_new success");
652 g_dcm_agent_loop = g_main_loop_new(context, FALSE);
653 g_main_context_push_thread_default(context);
655 /* Create new channel to watch udp socket */
656 channel = g_io_channel_unix_new(sockfd);
657 source = g_io_create_watch(channel, G_IO_IN);
659 /* Set callback to be called when socket is readable */
660 g_source_set_callback(source, (GSourceFunc)_ms_dcm_agent_read_socket, NULL, NULL);
661 g_source_attach(source, context);
663 MS_DBG("************************************");
664 MS_DBG("*** DCM Agent thread is running ***");
665 MS_DBG("************************************");
667 g_main_loop_run(g_dcm_agent_loop);
669 MS_DBG("DCM Agent thread is shutting down...");
671 /*close an IO channel & remove resources */
672 g_io_channel_shutdown(channel, FALSE, NULL);
673 g_io_channel_shutdown(g_dcm_tcp_channel, FALSE, NULL);
674 g_io_channel_unref(channel);
675 close(g_dcm_comm_sock);
677 g_main_loop_unref(g_dcm_agent_loop);