2 * media-thumbnail-server
4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hyunjun Ko <zzoon.ko@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.
25 #include "media-util.h"
26 #include "media-common-utils.h"
27 #include "media-server-dbg.h"
28 #include "media-server-thumb.h"
34 #define LOG_TAG "MEDIA_SERVER_THUMB"
36 #define THUMB_SERVER_NAME "media-thumbnail"
38 gboolean _ms_thumb_agent_timer();
40 static GMainLoop *g_thumb_agent_loop = NULL;
41 static GIOChannel *g_udp_channel = NULL;
42 static gboolean g_folk_thumb_server = FALSE;
43 static gboolean g_thumb_server_extracting = FALSE;
44 static int g_communicate_sock = 0;
45 static int g_timer_id = 0;
46 static int g_server_pid = 0;
48 static GQueue *g_request_queue = NULL;
49 static int g_queue_work = 0;
56 #ifdef _USE_UDS_SOCKET_
57 extern char MEDIA_IPC_PATH[][50];
60 gboolean _ms_thumb_agent_start_jobs(gpointer data)
67 void _ms_thumb_agent_finish_jobs()
75 ms_get_thumb_thread_mainloop(void)
77 return g_thumb_agent_loop;
80 int ms_thumb_get_server_pid()
85 void ms_thumb_reset_server_status()
87 g_folk_thumb_server = FALSE;
90 g_source_destroy(g_main_context_find_source_by_id(g_main_context_get_thread_default(), g_timer_id));
94 if (g_thumb_server_extracting) {
95 /* Need to inplement when crash happens */
97 /* Restart thumbnail server */
98 if (_ms_thumb_agent_execute_server() < 0) {
99 MS_DBG_ERR("starting thumbnail-server failed");
101 MS_DBG("Thumbnail-server is started");
106 memset((void *)&msg, 0, sizeof(msg));
107 memset((void *)&recv_msg, 0, sizeof(recv_msg));
109 msg.msg_type = 2; // THUMB_REQUEST_ALL_MEDIA
110 msg.org_path[0] = '\0';
111 msg.origin_path_size = 1;
112 msg.dst_path[0] = '\0';
113 msg.dest_path_size = 1;
115 /* Command all thumbnail extraction to thumbnail server */
116 if (!_ms_thumb_agent_send_msg_to_thumb_server(&msg, &recv_msg)) {
117 MS_DBG_ERR("_ms_thumb_agent_send_msg_to_thumb_server is failed");
120 _ms_thumb_create_timer(g_timer_id);
122 MS_DBG_ERR("Thumbnail server is dead when processing all-thumbs extraction");
123 g_thumb_server_extracting = FALSE;
127 g_thumb_server_extracting = FALSE;
134 void _ms_thumb_create_timer(int id)
137 g_source_destroy(g_main_context_find_source_by_id(g_main_context_get_thread_default(), id));
139 GSource *timer_src = g_timeout_source_new_seconds(MS_TIMEOUT_SEC_20);
140 g_source_set_callback (timer_src, _ms_thumb_agent_timer, NULL, NULL);
141 g_timer_id = g_source_attach (timer_src, g_main_context_get_thread_default());
145 /* This checks if thumbnail server is running */
146 bool _ms_thumb_check_process()
150 struct dirent *result = NULL;
153 pdir = opendir("/proc");
155 MS_DBG_ERR("err: NO_DIR\n");
159 while (!readdir_r(pdir, &pinfo, &result)) {
163 if (pinfo.d_type != 4 || pinfo.d_name[0] == '.'
164 || pinfo.d_name[0] > 57)
171 ms_strcopy(path, sizeof(path), "/proc/%s/status", pinfo.d_name);
172 fp = fopen(path, "rt");
174 if (fgets(buff, 128, fp) == NULL)
175 MS_DBG_ERR("fgets failed");
178 if (strstr(buff, THUMB_SERVER_NAME)) {
183 MS_DBG_ERR("Can't read file [%s]", path);
192 _ms_thumb_create_socket(int sock_type, int *sock)
196 #ifdef _USE_UDS_SOCKET_
197 if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
198 #elif defined(_USE_UDS_SOCKET_TCP_)
199 if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
201 if ((sock_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
203 MS_DBG_ERR("socket failed: %s", strerror(errno));
204 return MS_MEDIA_ERR_SOCKET_CONN;
207 if (sock_type == CLIENT_SOCKET) {
209 struct timeval tv_timeout = { MS_TIMEOUT_SEC_10, 0 };
211 if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &tv_timeout, sizeof(tv_timeout)) == -1) {
212 MS_DBG_ERR("setsockopt failed: %s", strerror(errno));
214 return MS_MEDIA_ERR_SOCKET_INTERNAL;
216 } else if (sock_type == SERVER_SOCKET) {
220 if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &n_reuse, sizeof(n_reuse)) == -1) {
221 MS_DBG_ERR("setsockopt failed: %s", strerror(errno));
223 return MS_MEDIA_ERR_SOCKET_INTERNAL;
229 return MS_MEDIA_ERR_NONE;
234 _ms_thumb_create_udp_socket(int *sock)
238 #ifdef _USE_UDS_SOCKET_
239 if ((sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
241 if ((sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
243 MS_DBG_ERR("socket failed: %s", strerror(errno));
244 return MS_MEDIA_ERR_SOCKET_CONN;
247 struct timeval tv_timeout = { MS_TIMEOUT_SEC_10, 0 };
249 if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &tv_timeout, sizeof(tv_timeout)) == -1) {
250 MS_DBG_ERR("setsockopt failed: %s", strerror(errno));
252 return MS_MEDIA_ERR_SOCKET_INTERNAL;
257 return MS_MEDIA_ERR_NONE;
260 int _media_thumb_get_error()
262 if (errno == EWOULDBLOCK) {
263 MS_DBG_ERR("Timeout. Can't try any more");
264 if (!_ms_thumb_check_process()) {
265 MS_DBG_ERR("Thumbnail server is not running!. Reset info for thumb server to execute");
266 ms_thumb_reset_server_status();
269 return MS_MEDIA_ERR_SOCKET_RECEIVE_TIMEOUT;
271 MS_DBG_ERR("recvfrom failed : %s", strerror(errno));
272 return MS_MEDIA_ERR_SOCKET_RECEIVE;
277 _ms_thumb_recv_msg(int sock, int header_size, thumbMsg *msg)
279 int recv_msg_len = 0;
280 unsigned char *buf = NULL;
282 buf = (unsigned char*)malloc(header_size);
284 if ((recv_msg_len = recv(sock, buf, header_size, 0)) < 0) {
285 MS_DBG_ERR("recv failed : %s", strerror(errno));
287 return _media_thumb_get_error();
290 memcpy(msg, buf, header_size);
291 //MS_DBG("origin_path_size : %d, dest_path_size : %d", msg->origin_path_size, msg->dest_path_size);
295 if (msg->origin_path_size <= 0 || msg->origin_path_size > MS_FILE_PATH_LEN_MAX) {
297 MS_DBG_ERR("msg->origin_path_size is invalid %d", msg->origin_path_size );
298 return MS_MEDIA_ERR_DATA_TAINTED;
301 buf = (unsigned char*)malloc(msg->origin_path_size);
303 if ((recv_msg_len = recv(sock, buf, msg->origin_path_size, 0)) < 0) {
304 MS_DBG_ERR("recv failed : %s", strerror(errno));
306 return _media_thumb_get_error();
309 strncpy(msg->org_path, (char*)buf, msg->origin_path_size);
310 //MS_DBG("original path : %s", msg->org_path);
314 if (msg->dest_path_size <= 0 || msg->dest_path_size > MS_FILE_PATH_LEN_MAX) {
316 MS_DBG_ERR("msg->dest_path_size is invalid %d", msg->dest_path_size );
317 return MS_MEDIA_ERR_DATA_TAINTED;
320 buf = (unsigned char*)malloc(msg->dest_path_size);
322 if ((recv_msg_len = recv(sock, buf, msg->dest_path_size, 0)) < 0) {
323 MS_DBG_ERR("recv failed : %s", strerror(errno));
325 return _media_thumb_get_error();
328 strncpy(msg->dst_path, (char*)buf, msg->dest_path_size);
329 //MS_DBG("destination path : %s", msg->dst_path);
332 return MS_MEDIA_ERR_NONE;
337 #ifdef _USE_UDS_SOCKET_
338 _ms_thumb_recv_udp_msg(int sock, int header_size, thumbMsg *msg, struct sockaddr_un *from_addr, unsigned int *from_size)
340 _ms_thumb_recv_udp_msg(int sock, int header_size, thumbMsg *msg, struct sockaddr_in *from_addr, unsigned int *from_size)
343 int recv_msg_len = 0;
344 #ifdef _USE_UDS_SOCKET_
345 unsigned int from_addr_size = sizeof(struct sockaddr_un);
347 unsigned int from_addr_size = sizeof(struct sockaddr_in);
349 unsigned char *buf = NULL;
351 buf = (unsigned char*)malloc(sizeof(thumbMsg));
353 recv_msg_len = ms_ipc_wait_message(sock, buf, sizeof(thumbMsg), from_addr, &from_addr_size);
354 if (recv_msg_len != MS_MEDIA_ERR_NONE) {
355 MS_DBG_ERR("ms_ipc_wait_message failed : %s", strerror(errno));
357 return _media_thumb_get_error();
360 memcpy(msg, buf, header_size);
361 //MS_DBG("origin_path_size : %d, dest_path_size : %d", msg->origin_path_size, msg->dest_path_size);
363 if (msg->origin_path_size <= 0 || msg->origin_path_size > MS_FILE_PATH_LEN_MAX) {
365 MS_DBG_ERR("msg->origin_path_size is invalid %d", msg->origin_path_size );
366 return MS_MEDIA_ERR_DATA_TAINTED;
369 strncpy(msg->org_path, (char*)buf + header_size, msg->origin_path_size);
370 //MS_DBG("original path : %s", msg->org_path);
372 if (msg->dest_path_size <= 0 || msg->dest_path_size > MS_FILE_PATH_LEN_MAX) {
374 MS_DBG_ERR("msg->origin_path_size is invalid %d", msg->dest_path_size );
375 return MS_MEDIA_ERR_DATA_TAINTED;
378 strncpy(msg->dst_path, (char*)buf + header_size + msg->origin_path_size, msg->dest_path_size);
379 //MS_DBG("destination path : %s", msg->dst_path);
382 *from_size = from_addr_size;
384 return MS_MEDIA_ERR_NONE;
388 _ms_thumb_set_buffer(thumbMsg *req_msg, unsigned char **buf, int *buf_size)
390 if (req_msg == NULL || buf == NULL) {
394 int org_path_len = 0;
395 int dst_path_len = 0;
399 header_size = sizeof(thumbMsg) - MAX_MSG_SIZE*2;
400 org_path_len = strlen(req_msg->org_path) + 1;
401 dst_path_len = strlen(req_msg->dst_path) + 1;
403 //MS_DBG("Basic Size : %d, org_path : %s[%d], dst_path : %s[%d]", header_size, req_msg->org_path, org_path_len, req_msg->dst_path, dst_path_len);
405 size = header_size + org_path_len + dst_path_len;
407 memcpy(*buf, req_msg, header_size);
408 memcpy((*buf)+header_size, req_msg->org_path, org_path_len);
409 memcpy((*buf)+header_size + org_path_len, req_msg->dst_path, dst_path_len);
417 void _ms_thumb_agent_child_handler(GPid pid, gint status, gpointer user_data)
419 MS_DBG_WARN("media-thumbnail-server[%d] is shutdown : %d", pid, status);
420 g_folk_thumb_server = FALSE;
423 gboolean _ms_thumb_agent_child_handler(gpointer data)
425 int pid = GPOINTER_TO_INT(data);
426 MS_DBG("media-thumbnail-server[%d] is killed", pid);
430 gboolean _ms_thumb_agent_recv_msg_from_server()
432 if (g_communicate_sock <= 0) {
433 _ms_thumb_agent_prepare_udp_socket();
436 ms_thumb_server_msg recv_msg;
437 int recv_msg_size = 0;
439 recv_msg_size = ms_ipc_receive_message(g_communicate_sock, & recv_msg, sizeof(ms_thumb_server_msg), NULL, NULL);
440 if (recv_msg_size != MS_MEDIA_ERR_NONE) {
441 MS_DBG_ERR("ms_ipc_receive_message failed : %s\n", strerror(errno));
445 //MS_DBG("Receive : %d(%d)", recv_msg.msg_type, recv_msg_size);
446 if (recv_msg.msg_type == MS_MSG_THUMB_SERVER_READY) {
447 MS_DBG("Thumbnail server is ready");
453 gboolean _ms_thumb_agent_recv_thumb_done_from_server(GIOChannel *src, GIOCondition condition, gpointer data)
457 sockfd = g_io_channel_unix_get_fd(src);
459 MS_DBG_ERR("sock fd is invalid!");
463 ms_thumb_server_msg recv_msg;
464 int recv_msg_size = 0;
466 recv_msg_size = ms_ipc_receive_message(sockfd, &recv_msg, sizeof(ms_thumb_server_msg), NULL, NULL);
467 if (recv_msg_size != MS_MEDIA_ERR_NONE) {
468 MS_DBG_ERR("ms_ipc_receive_message failed : %s\n", strerror(errno));
472 MS_DBG("Receive : %d(%d)", recv_msg.msg_type, recv_msg_size);
473 if (recv_msg.msg_type == MS_MSG_THUMB_EXTRACT_ALL_DONE) {
474 MS_DBG("Thumbnail extracting done");
475 g_thumb_server_extracting = FALSE;
483 gboolean _ms_thumb_agent_execute_server()
490 } else if (pid == 0) {
491 execl("/usr/bin/media-thumbnail-server", "media-thumbnail-server", NULL);
493 MS_DBG("Child process is %d", pid);
494 g_folk_thumb_server = TRUE;
497 GSource *child_watch_src = g_child_watch_source_new(pid);
498 g_source_set_callback(child_watch_src, _ms_thumb_agent_child_handler, GINT_TO_POINTER(pid), NULL);
499 g_source_attach(child_watch_src, g_main_context_get_thread_default());
501 //g_child_watch_add(pid, _ms_thumb_agent_child_handler, NULL);
504 if (!_ms_thumb_agent_recv_msg_from_server()) {
505 MS_DBG_ERR("_ms_thumb_agent_recv_msg_from_server is failed");
512 gboolean _ms_thumb_agent_send_msg_to_thumb_server(thumbMsg *recv_msg, thumbMsg *res_msg)
515 const char *serv_ip = "127.0.0.1";
516 #ifdef _USE_UDS_SOCKET_
517 struct sockaddr_un serv_addr;
519 struct sockaddr_in serv_addr;
522 int send_str_len = strlen(recv_msg->org_path);
524 if (send_str_len > MAX_MSG_SIZE) {
525 MS_DBG_ERR("original path's length exceeds %d(max packet size)", MAX_MSG_SIZE);
530 /* Creaete a datagram/UDP socket */
531 if (_ms_thumb_create_udp_socket(&sock) < 0) {
532 MS_DBG_ERR("_ms_thumb_create_udp_socket failed");
536 #ifdef _USE_UDS_SOCKET_
537 if (ms_ipc_create_client_socket(MS_PROTOCOL_UDP, MS_TIMEOUT_SEC_10, &sock, MS_THUMB_DAEMON_PORT) < 0) {
539 if (ms_ipc_create_client_socket(MS_PROTOCOL_UDP, MS_TIMEOUT_SEC_10, &sock) < 0) {
541 MS_DBG_ERR("ms_ipc_create_client_socket failed");
545 memset(&serv_addr, 0, sizeof(serv_addr));
546 #ifdef _USE_UDS_SOCKET_
547 serv_addr.sun_family = AF_UNIX;
548 MS_DBG("%s", MEDIA_IPC_PATH[MS_THUMB_DAEMON_PORT]);
549 strcpy(serv_addr.sun_path, MEDIA_IPC_PATH[MS_THUMB_DAEMON_PORT]);
551 serv_addr.sin_family = AF_INET;
552 serv_addr.sin_addr.s_addr = inet_addr(serv_ip);
553 serv_addr.sin_port = htons(MS_THUMB_DAEMON_PORT);
558 unsigned char *buf = NULL;
559 _ms_thumb_set_buffer(recv_msg, &buf, &buf_size);
561 //MS_DBG("buffer size : %d", buf_size);
562 if (sendto(sock, buf, buf_size, 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != buf_size) {
563 MS_DBG_ERR("sendto failed: %s\n", strerror(errno));
570 MS_DBG("Sending msg to thumbnail server is successful");
572 #ifdef _USE_UDS_SOCKET_
573 struct sockaddr_un client_addr;
575 struct sockaddr_in client_addr;
577 unsigned int client_addr_len;
578 header_size = sizeof(thumbMsg) - MAX_MSG_SIZE*2;
580 if (_ms_thumb_recv_udp_msg(sock, header_size, res_msg, &client_addr, &client_addr_len) < 0) {
581 MS_DBG_ERR("_ms_thumb_recv_udp_msg failed");
586 MS_DBG("recv %s from thumb daemon is successful", res_msg->dst_path);
589 if (res_msg->msg_type == 2 && g_communicate_sock > 0) { // THUMB_REQUEST_ALL_MEDIA
590 /* Create new channel to watch udp socket */
591 GSource *source = NULL;
592 if (g_udp_channel == NULL)
593 g_udp_channel = g_io_channel_unix_new(g_communicate_sock);
594 source = g_io_create_watch(g_udp_channel, G_IO_IN);
596 /* Set callback to be called when socket is readable */
597 g_source_set_callback(source, (GSourceFunc)_ms_thumb_agent_recv_thumb_done_from_server, NULL, NULL);
598 g_source_attach(source, g_main_context_get_thread_default());
600 g_thumb_server_extracting = TRUE;
606 gboolean _ms_thumb_agent_timer()
608 if (g_thumb_server_extracting) {
609 MS_DBG("Timer is called.. But media-thumbnail-server[%d] is busy.. so timer is recreated", g_server_pid);
611 _ms_thumb_create_timer(g_timer_id);
616 MS_DBG("Timer is called.. Now killing media-thumbnail-server[%d]", g_server_pid);
618 if (g_server_pid > 0) {
620 if (kill(g_server_pid, SIGKILL) < 0) {
621 MS_DBG_ERR("kill failed : %s", strerror(errno));
624 /* Kill thumbnail server */
627 memset((void *)&msg, 0, sizeof(msg));
628 memset((void *)&recv_msg, 0, sizeof(recv_msg));
630 msg.msg_type = 5; // THUMB_REQUEST_KILL_SERVER
631 msg.org_path[0] = '\0';
632 msg.origin_path_size = 1;
633 msg.dst_path[0] = '\0';
634 msg.dest_path_size = 1;
636 /* Command Kill to thumbnail server */
637 if (!_ms_thumb_agent_send_msg_to_thumb_server(&msg, &recv_msg)) {
638 MS_DBG_ERR("_ms_thumb_agent_send_msg_to_thumb_server is failed");
643 MS_DBG_ERR("g_server_pid is %d. Maybe there's problem in thumbnail-server", g_server_pid);
650 gboolean _ms_thumb_agent_read_socket(GIOChannel *src,
651 GIOCondition condition,
654 #ifdef _USE_UDS_SOCKET_
655 struct sockaddr_un client_addr;
657 struct sockaddr_in client_addr;
659 unsigned int client_addr_len;
665 int client_sock = -1;
667 sock = g_io_channel_unix_get_fd(src);
669 MS_DBG_ERR("sock fd is invalid!");
673 memset((void *)&recv_msg, 0, sizeof(thumbMsg));
674 memset((void *)&res_msg, 0, sizeof(res_msg));
675 header_size = sizeof(thumbMsg) - MAX_MSG_SIZE*2;
677 if ((client_sock = accept(sock, (struct sockaddr*)&client_addr, &client_addr_len)) < 0) {
678 MS_DBG_ERR("accept failed : %s", strerror(errno));
682 MS_DBG("Client[%d] is accepted", client_sock);
684 if (_ms_thumb_recv_msg(client_sock, header_size, &recv_msg) < 0) {
685 MS_DBG_ERR("_ms_thumb_recv_msg failed ");
690 MS_DBG("Received [%d] %s(%d) from PID(%d) \n", recv_msg.msg_type, recv_msg.org_path, strlen(recv_msg.org_path), recv_msg.pid);
692 if (g_folk_thumb_server == FALSE && g_thumb_server_extracting == FALSE) {
693 if(_ms_thumb_check_process() == FALSE) { // This logic is temporary
694 MS_DBG_WARN("Thumb server is not running.. so start it");
695 if (!_ms_thumb_agent_execute_server()) {
696 MS_DBG_ERR("_ms_thumb_agent_execute_server is failed");
700 GSource *timer_src = g_timeout_source_new_seconds(MS_TIMEOUT_SEC_20);
701 g_source_set_callback (timer_src, _ms_thumb_agent_timer, NULL, NULL);
702 g_timer_id = g_source_attach (timer_src, g_main_context_get_thread_default());
706 if (g_timer_id > 0) {
707 g_source_destroy(g_main_context_find_source_by_id(g_main_context_get_thread_default(), g_timer_id));
708 //MS_DBG("Timer is recreated");
709 GSource *timer_src = g_timeout_source_new_seconds(MS_TIMEOUT_SEC_20);
710 g_source_set_callback (timer_src, _ms_thumb_agent_timer, NULL, NULL);
711 g_timer_id = g_source_attach (timer_src, g_main_context_get_thread_default());
715 if (!_ms_thumb_agent_send_msg_to_thumb_server(&recv_msg, &res_msg)) {
716 MS_DBG_ERR("_ms_thumb_agent_send_msg_to_thumb_server is failed");
721 strncpy(res_msg.org_path, recv_msg.org_path, recv_msg.origin_path_size);
722 res_msg.origin_path_size = recv_msg.origin_path_size;
723 res_msg.dest_path_size = strlen(res_msg.dst_path) + 1;
726 unsigned char *buf = NULL;
727 _ms_thumb_set_buffer(&res_msg, &buf, &buf_size);
729 //MS_DBG("buffer size : %d", buf_size);
731 if (send(client_sock, buf, buf_size, 0) != buf_size) {
732 MS_DBG_ERR("sendto failed : %s", strerror(errno));
734 MS_DBG("Sent %s(%d) \n", res_msg.dst_path, strlen(res_msg.dst_path));
742 int _ms_thumb_cancel_media(const char *path, int pid)
748 req_len = g_queue_get_length(g_request_queue);
750 MS_DBG("Queue length : %d", req_len);
752 for (i = 0; i < req_len; i++) {
753 thumbRequest *req = NULL;
754 req = (thumbRequest *)g_queue_peek_nth(g_request_queue, i);
755 if (req == NULL) continue;
757 if ((req->recv_msg->pid) == pid && (strncmp(path, req->recv_msg->org_path, strlen(path))) == 0) {
758 MS_DBG("Remove %s from queue", req->recv_msg->org_path);
759 g_queue_pop_nth(g_request_queue, i);
761 close(req->client_sock);
762 MS_SAFE_FREE(req->recv_msg);
773 int _ms_thumb_cancel_all(int pid)
779 req_len = g_queue_get_length(g_request_queue);
781 MS_DBG("Queue length : %d", req_len);
783 for (i = 0; i < req_len; i++) {
784 thumbRequest *req = NULL;
785 req = (thumbRequest *)g_queue_peek_nth(g_request_queue, i);
786 if (req == NULL) continue;
788 if (req->recv_msg->pid == pid) {
789 MS_DBG("Remove [%d] %s from queue", req->recv_msg->pid, req->recv_msg->org_path);
790 g_queue_pop_nth(g_request_queue, i);
794 close(req->client_sock);
795 MS_SAFE_FREE(req->recv_msg);
804 void _ms_thumb_cancle_request(thumbRequest *thumb_req)
809 if (thumb_req == NULL) return;
811 thumbMsg *recv_msg = thumb_req->recv_msg;
812 if (recv_msg == NULL) {
813 MS_SAFE_FREE(thumb_req);
817 if (recv_msg->msg_type == 3)
818 ret = _ms_thumb_cancel_media(recv_msg->org_path, recv_msg->pid);
819 else if (recv_msg->msg_type == 4)
820 ret = _ms_thumb_cancel_all(recv_msg->pid);
823 recv_msg->status = 0; // THUMB_SUCCESS
825 recv_msg->status = 0; // THUMB_SUCCESS
828 if (recv_msg->origin_path_size <= 0 || recv_msg->origin_path_size > MS_FILE_PATH_LEN_MAX) {
829 MS_DBG_ERR("recv_msg->origin_path_size is invalid %d", recv_msg->origin_path_size );
833 recv_msg->dest_path_size = recv_msg->origin_path_size;
834 strncpy(recv_msg->dst_path, recv_msg->org_path, recv_msg->dest_path_size);
837 unsigned char *buf = NULL;
838 _ms_thumb_set_buffer(recv_msg, &buf, &buf_size);
840 if (send(thumb_req->client_sock, buf, buf_size, 0) != buf_size) {
841 MS_DBG_ERR("sendto failed : %s", strerror(errno));
843 MS_DBG("Sent response");
846 close(thumb_req->client_sock);
848 MS_SAFE_FREE(thumb_req->recv_msg);
849 MS_SAFE_FREE(thumb_req);
854 gboolean _ms_thumb_request_to_server(gpointer data)
858 req_len = g_queue_get_length(g_request_queue);
860 MS_DBG("Queue length : %d", req_len);
863 MS_DBG("There is no request job in the queue");
868 if (g_folk_thumb_server == FALSE && g_thumb_server_extracting == FALSE) {
869 if(_ms_thumb_check_process() == FALSE) { // This logic is temporary
870 MS_DBG_WARN("Thumb server is not running.. so start it");
871 if (!_ms_thumb_agent_execute_server()) {
872 MS_DBG_ERR("_ms_thumb_agent_execute_server is failed");
876 _ms_thumb_create_timer(g_timer_id);
880 /* Timer is re-created*/
881 _ms_thumb_create_timer(g_timer_id);
884 thumbRequest *req = NULL;
885 req = (thumbRequest *)g_queue_pop_head(g_request_queue);
888 MS_DBG_ERR("Failed to get a request job from queue");
892 int client_sock = -1;
893 thumbMsg *recv_msg = NULL;
895 memset((void *)&res_msg, 0, sizeof(res_msg));
897 client_sock = req->client_sock;
898 recv_msg = req->recv_msg;
900 if (req->client_sock <=0 || req->recv_msg == NULL) {
901 MS_DBG_ERR("client sock is below 0 or recv msg is NULL");
902 MS_SAFE_FREE(req->recv_msg);
908 if (!_ms_thumb_agent_send_msg_to_thumb_server(recv_msg, &res_msg)) {
909 MS_DBG_ERR("_ms_thumb_agent_send_msg_to_thumb_server is failed");
912 MS_SAFE_FREE(req->recv_msg);
917 MS_DBG_ERR("recv_msg is NULL from queue request");
920 strncpy(res_msg.org_path, recv_msg->org_path, recv_msg->origin_path_size);
921 res_msg.origin_path_size = recv_msg->origin_path_size;
922 res_msg.dest_path_size = strlen(res_msg.dst_path) + 1;
925 unsigned char *buf = NULL;
926 _ms_thumb_set_buffer(&res_msg, &buf, &buf_size);
928 if (send(client_sock, buf, buf_size, 0) != buf_size) {
929 MS_DBG_ERR("sendto failed : %s", strerror(errno));
931 MS_DBG("Sent %s(%d) from %s \n", res_msg.dst_path, strlen(res_msg.dst_path), res_msg.org_path);
936 MS_SAFE_FREE(req->recv_msg);
942 gboolean _ms_thumb_agent_read_socket(GIOChannel *src,
943 GIOCondition condition,
946 #ifdef _USE_UDS_SOCKET_
947 struct sockaddr_un client_addr;
948 #elif defined(_USE_UDS_SOCKET_TCP_)
949 struct sockaddr_un client_addr;
951 struct sockaddr_in client_addr;
953 unsigned int client_addr_len;
955 thumbMsg *recv_msg = NULL;
958 int client_sock = -1;
960 sock = g_io_channel_unix_get_fd(src);
962 MS_DBG_ERR("sock fd is invalid!");
966 header_size = sizeof(thumbMsg) - MAX_MSG_SIZE*2;
967 client_addr_len = sizeof(client_addr);
969 if ((client_sock = accept(sock, (struct sockaddr*)&client_addr, &client_addr_len)) < 0) {
970 MS_DBG_ERR("accept failed : %s", strerror(errno));
974 MS_DBG("Client[%d] is accepted", client_sock);
976 recv_msg = calloc(1, sizeof(thumbMsg));
977 if (recv_msg == NULL) {
978 MS_DBG_ERR("Failed to allocate memory");
983 if (_ms_thumb_recv_msg(client_sock, header_size, recv_msg) < 0) {
984 MS_DBG_ERR("_ms_thumb_recv_msg failed ");
986 MS_SAFE_FREE(recv_msg);
990 MS_DBG("Received [%d] %s(%d) from PID(%d) \n", recv_msg->msg_type, recv_msg->org_path, strlen(recv_msg->org_path), recv_msg->pid);
992 thumbRequest *thumb_req = NULL;
993 thumb_req = calloc(1, sizeof(thumbRequest));
994 if (thumb_req == NULL) {
995 MS_DBG_ERR("Failed to create request element");
997 MS_SAFE_FREE(recv_msg);
1001 thumb_req->client_sock = client_sock;
1002 thumb_req->recv_msg = recv_msg;
1004 if (recv_msg->msg_type == 3 || recv_msg->msg_type == 4) { // THUMB_REQUEST_CANCEL_MEDIA || THUMB_REQUEST_CANCEL_ALL
1005 _ms_thumb_cancle_request(thumb_req);
1009 if (g_request_queue == NULL) {
1010 MS_DBG_WARN("queue is init");
1011 g_request_queue = g_queue_new();
1014 if (g_queue_get_length(g_request_queue) >= MAX_THUMB_REQUEST) {
1015 MS_DBG_WARN("Request Queue is full");
1017 memset((void *)&res_msg, 0, sizeof(res_msg));
1019 res_msg.msg_type = 6; // THUMB_RESPONSE
1020 res_msg.status = 1; //THUMB_FAIL
1021 res_msg.org_path[0] = '\0';
1022 res_msg.origin_path_size = 0;
1023 res_msg.dst_path[0] = '\0';
1024 res_msg.dest_path_size = 0;
1027 unsigned char *buf = NULL;
1028 _ms_thumb_set_buffer(&res_msg, &buf, &buf_size);
1030 if (send(client_sock, buf, buf_size, 0) != buf_size) {
1031 MS_DBG_ERR("sendto failed : %s", strerror(errno));
1033 MS_DBG("Sent Refuse msg from %s \n", recv_msg->org_path);
1038 MS_SAFE_FREE(thumb_req->recv_msg);
1039 MS_SAFE_FREE(thumb_req);
1044 MS_DBG("%s is queued", recv_msg->org_path);
1045 g_queue_push_tail(g_request_queue, (gpointer)thumb_req);
1047 if (!g_queue_work) {
1048 GSource *src_request = NULL;
1049 src_request = g_idle_source_new ();
1050 g_source_set_callback (src_request, _ms_thumb_request_to_server, NULL, NULL);
1051 //g_source_set_priority(src_request, G_PRIORITY_LOW);
1052 g_source_attach (src_request, g_main_context_get_thread_default());
1061 gboolean _ms_thumb_agent_prepare_tcp_socket(int *sock_fd)
1064 unsigned short serv_port;
1066 #ifdef _USE_UDS_SOCKET_TCP_
1067 serv_port = MS_THUMB_CREATOR_TCP_PORT;
1069 serv_port = MS_THUMB_CREATOR_PORT;
1073 #ifdef _USE_UDS_SOCKET_
1074 struct sockaddr_un serv_addr;
1076 struct sockaddr_in serv_addr;
1079 /* Create a TCP socket */
1080 if (_ms_thumb_create_socket(SERVER_SOCKET, &sock) < 0) {
1081 MS_DBG_ERR("_ms_thumb_create_socket failed");
1085 memset(&serv_addr, 0, sizeof(serv_addr));
1086 #ifdef _USE_UDS_SOCKET_
1087 serv_addr.sun_family = AF_UNIX;
1088 strcpy(serv_addr.sun_path, MEDIA_IPC_PATH[serv_port]);
1090 serv_addr.sin_family = AF_INET;
1091 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1092 serv_addr.sin_port = htons(serv_port);
1095 /* Bind to the local address */
1096 if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
1097 MS_DBG_ERR("bind failed");
1101 MS_DBG("bind success");
1104 if (listen(sock, SOMAXCONN) < 0) {
1105 MS_DBG_ERR("listen failed : %s", strerror(errno));
1109 MS_DBG("Listening...");
1112 #ifdef _USE_UDS_SOCKET_TCP_
1113 if (ms_ipc_create_server_tcp_socket(MS_PROTOCOL_TCP, serv_port, &sock) < 0) {
1115 if (ms_ipc_create_server_socket(MS_PROTOCOL_TCP, serv_port, &sock) < 0) {
1117 MS_DBG_ERR("_ms_thumb_create_socket failed");
1126 gboolean _ms_thumb_agent_prepare_udp_socket()
1129 unsigned short serv_port;
1131 serv_port = MS_THUMB_COMM_PORT;
1133 if (ms_ipc_create_server_socket(MS_PROTOCOL_UDP, serv_port, &sock) < 0) {
1134 MS_DBG_ERR("ms_ipc_create_server_socket failed");
1138 #ifdef _USE_UDS_SOCKET_
1139 struct sockaddr_un serv_addr;
1141 struct sockaddr_in serv_addr;
1144 /* Creaete a UDP socket */
1145 if (_ms_thumb_create_udp_socket(&sock) < 0) {
1146 MS_DBG_ERR("_ms_thumb_create_udp_socket failed");
1150 memset(&serv_addr, 0, sizeof(serv_addr));
1151 #ifdef _USE_UDS_SOCKET_
1152 serv_addr.sun_family = AF_UNIX;
1153 strcpy(serv_addr.sun_path, MEDIA_IPC_PATH[serv_port]);
1155 serv_addr.sin_family = AF_INET;
1156 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1157 serv_addr.sin_port = htons(serv_port);
1160 /* Bind to the local address */
1161 if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
1162 MS_DBG_ERR("bind failed");
1166 MS_DBG("bind success");
1168 g_communicate_sock = sock;
1173 gpointer ms_thumb_agent_start_thread(gpointer data)
1178 GSource *source = NULL;
1179 GIOChannel *channel = NULL;
1180 GMainContext *context = NULL;
1182 /* Create and bind new TCP socket */
1183 if (!_ms_thumb_agent_prepare_tcp_socket(&sockfd)) {
1184 MS_DBG_ERR("Failed to create socket\n");
1188 context = g_main_context_new();
1190 if (context == NULL) {
1191 MS_DBG_ERR("g_main_context_new failed");
1193 MS_DBG("g_main_context_new success");
1196 g_thumb_agent_loop = g_main_loop_new(context, FALSE);
1197 g_main_context_push_thread_default(context);
1199 /* Create new channel to watch udp socket */
1200 channel = g_io_channel_unix_new(sockfd);
1201 source = g_io_create_watch(channel, G_IO_IN);
1203 /* Set callback to be called when socket is readable */
1204 g_source_set_callback(source, (GSourceFunc)_ms_thumb_agent_read_socket, NULL, NULL);
1205 g_source_attach(source, context);
1208 MS_DBG("************************************");
1209 MS_DBG("*** Thumbnail Agent thread is running ***");
1210 MS_DBG("************************************");
1212 g_main_loop_run(g_thumb_agent_loop);
1214 MS_DBG("Thumbnail Agent thread is shutting down...");
1215 _ms_thumb_agent_finish_jobs();
1217 /*close an IO channel*/
1218 g_io_channel_shutdown(channel, FALSE, NULL);
1219 g_io_channel_shutdown(g_udp_channel, FALSE, NULL);
1220 g_io_channel_unref(channel);
1221 close(g_communicate_sock);
1223 g_main_loop_unref(g_thumb_agent_loop);