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.
22 #include "thumb-server-internal.h"
23 #include "media-thumb-util.h"
24 #include "media-thumb-debug.h"
31 #include <Ecore_Evas.h>
32 #include <tzplatform_config.h>
38 #define LOG_TAG "MEDIA_THUMBNAIL_SERVER"
39 #define THUMB_DEFAULT_WIDTH 320
40 #define THUMB_DEFAULT_HEIGHT 240
41 #define THUMB_BLOCK_SIZE 512
42 #define THUMB_COMM_SOCK_PATH tzplatform_mkpath(TZ_SYS_RUN, "media-server/media_ipc_thumbcomm.socket")
43 #define THUMB_EMPTY_STR ""
45 GMainLoop *g_thumb_server_mainloop; // defined in thumb-server.c as extern
47 static gboolean __thumb_server_send_msg_to_agent(int msg_type);
48 static gboolean _thumb_server_send_deny_message(int sockfd);
50 gboolean _thumb_daemon_start_jobs(gpointer data)
53 /* Initialize ecore-evas to use evas library */
56 __thumb_server_send_msg_to_agent(MS_MSG_THUMB_SERVER_READY);
61 void _thumb_daemon_finish_jobs(void)
63 sqlite3 *sqlite_db_handle = _media_thumb_db_get_handle();
65 if (sqlite_db_handle != NULL) {
66 _media_thumb_db_disconnect();
67 thumb_dbg("sqlite3 handle is alive. So disconnect to sqlite3");
70 /* Shutdown ecore-evas */
71 ecore_evas_shutdown();
72 g_main_loop_quit(g_thumb_server_mainloop);
77 int _thumb_daemon_process_job(thumbMsg *req_msg, thumbMsg *res_msg)
79 int err = MS_MEDIA_ERR_NONE;
81 if (req_msg->msg_type == THUMB_REQUEST_RAW_DATA) {
82 err = _media_thumb_process_raw(req_msg, res_msg);
83 if (err != MS_MEDIA_ERR_NONE)
84 thumb_warn("_media_thumb_process_raw is failed: %d", err);
86 err = _media_thumb_process(req_msg, res_msg);
87 if (err != MS_MEDIA_ERR_NONE)
88 thumb_warn("_media_thumb_process is failed: %d", err);
94 gboolean _thumb_server_read_socket(GIOChannel *src,
95 GIOCondition condition,
98 struct sockaddr_un client_addr;
99 unsigned int client_addr_len;
102 ms_peer_credentials credentials;
105 int client_sock = -1;
107 memset((void *)&recv_msg, 0, sizeof(recv_msg));
108 memset((void *)&res_msg, 0, sizeof(res_msg));
109 memset((void *)&credentials, 0, sizeof(credentials));
111 sock = g_io_channel_unix_get_fd(src);
113 thumb_err("sock fd is invalid!");
117 client_addr_len = sizeof(client_addr);
119 if ((client_sock = accept(sock, (struct sockaddr*)&client_addr, &client_addr_len)) < 0) {
120 thumb_stderror("accept failed");
124 if (ms_cynara_receive_untrusted_message_thumb(client_sock, &recv_msg, &credentials) != MS_MEDIA_ERR_NONE) {
125 thumb_err("ms_cynara_receive_untrusted_message_thumb failed");
130 if (recv_msg.msg_type != THUMB_REQUEST_KILL_SERVER) {
131 if (ms_cynara_check(&credentials, MEDIA_STORAGE_PRIVILEGE) != MS_MEDIA_ERR_NONE) {
132 thumb_err("Cynara denied access to process request");
133 _thumb_server_send_deny_message(client_sock);
139 SAFE_FREE(credentials.smack);
140 SAFE_FREE(credentials.uid);
142 thumb_warn_slog("Received [%d] %s(%d) from PID(%d)", recv_msg.msg_type, recv_msg.org_path, strlen(recv_msg.org_path), recv_msg.pid);
144 if (recv_msg.msg_type != THUMB_REQUEST_KILL_SERVER)
145 _thumb_daemon_process_job(&recv_msg, &res_msg);
147 if (res_msg.msg_type == 0)
148 res_msg.msg_type = recv_msg.msg_type;
149 res_msg.request_id = recv_msg.request_id;
150 SAFE_STRLCPY(res_msg.org_path, recv_msg.org_path, sizeof(res_msg.org_path));
151 res_msg.origin_path_size = recv_msg.origin_path_size;
152 if (res_msg.msg_type != THUMB_RESPONSE_RAW_DATA) {
153 res_msg.dest_path_size = strlen(res_msg.dst_path)+1;
154 res_msg.thumb_size = 0;
156 res_msg.dest_path_size = 1;
157 res_msg.dst_path[0] = '\0';
161 int sending_block = 0;
162 int block_size = sizeof(res_msg) - MAX_FILEPATH_LEN*2 - sizeof(unsigned char *);
163 unsigned char *buf = NULL;
164 _media_thumb_set_buffer(&res_msg, &buf, &buf_size);
166 while (buf_size > 0) {
167 if (buf_size < THUMB_BLOCK_SIZE) {
168 block_size = buf_size;
170 if (send(client_sock, buf+sending_block, block_size, 0) != block_size) {
171 thumb_stderror("sendto failed");
173 sending_block += block_size;
174 buf_size -= block_size;
175 if (block_size < THUMB_BLOCK_SIZE) {
176 block_size = THUMB_BLOCK_SIZE;
180 thumb_dbg_slog("Sent data(%d) from %s", res_msg.thumb_size, res_msg.org_path);
183 SAFE_FREE(res_msg.thumb_data);
185 if (recv_msg.msg_type == THUMB_REQUEST_KILL_SERVER) {
186 thumb_warn("Shutting down...");
187 g_main_loop_quit(g_thumb_server_mainloop);
195 static gboolean __thumb_server_send_msg_to_agent(int msg_type)
198 struct sockaddr_un serv_addr;
199 ms_thumb_server_msg send_msg;
201 if (ms_ipc_create_client_socket(MS_TIMEOUT_SEC_10, &sock) < 0) {
202 thumb_err("ms_ipc_create_server_socket failed");
206 memset(&serv_addr, 0, sizeof(serv_addr));
208 serv_addr.sun_family = AF_UNIX;
209 SAFE_STRLCPY(serv_addr.sun_path, THUMB_COMM_SOCK_PATH, sizeof(serv_addr.sun_path));
212 /* Connecting to the thumbnail server */
213 if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
214 thumb_stderror("connect");
216 return MS_MEDIA_ERR_SOCKET_CONN;
219 send_msg.msg_type = msg_type;
221 if (send(sock, &send_msg, sizeof(ms_thumb_server_msg), 0) != sizeof(ms_thumb_server_msg)) {
222 thumb_stderror("sendto failed");
227 thumb_dbg("Sending msg to thumbnail agent[%d] is successful", send_msg.msg_type);
233 static gboolean _thumb_server_send_deny_message(int sockfd)
236 int bytes_to_send = sizeof(msg) - sizeof(msg.org_path) - sizeof(msg.dst_path);
238 msg.msg_type = THUMB_RESPONSE;
239 msg.status = MS_MEDIA_ERR_PERMISSION_DENIED;
241 if (send(sockfd, &msg, bytes_to_send, 0) != bytes_to_send) {
242 thumb_stderror("send failed");
249 gboolean _thumb_server_prepare_socket(int *sock_fd)
253 if (ms_ipc_create_server_socket(MS_THUMB_DAEMON_PORT, &sock) < 0) {
254 thumb_err("ms_ipc_create_server_socket failed");
258 if (ms_cynara_enable_credentials_passing(sock) != MS_MEDIA_ERR_NONE) {
259 thumb_err("ms_cynara_enable_credentials_passing failed");
269 int _thumbnail_get_data(const char *origin_path,
271 unsigned char **data,
280 int err = MS_MEDIA_ERR_NONE;
281 int thumb_width = -1;
282 int thumb_height = -1;
284 if (origin_path == NULL || size == NULL || width == NULL || height == NULL) {
285 thumb_err("Invalid parameter");
286 return MS_MEDIA_ERR_INVALID_PARAMETER;
289 if (!g_file_test(origin_path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
290 thumb_err("Original path (%s) does not exist", origin_path);
291 return MS_MEDIA_ERR_INVALID_PARAMETER;
294 thumb_dbg("Origin path : %s", origin_path);
296 int file_type = THUMB_NONE_TYPE;
297 media_thumb_info thumb_info = {0,};
298 file_type = _media_thumb_get_file_type(origin_path);
299 thumb_width = *width;
300 thumb_height = *height;
301 if (thumb_width == 0 || thumb_height == 0) {
302 thumb_width = THUMB_DEFAULT_WIDTH;
303 thumb_height = THUMB_DEFAULT_HEIGHT;
306 thumb_info.is_raw = FALSE;
308 if (file_type == THUMB_IMAGE_TYPE) {
309 err = _media_thumb_image(origin_path, thumb_path, thumb_width, thumb_height, &thumb_info);
310 if (err != MS_MEDIA_ERR_NONE) {
311 thumb_err("_media_thumb_image failed");
314 } else if (file_type == THUMB_VIDEO_TYPE) {
315 err = _media_thumb_video(origin_path, thumb_width, thumb_height, &thumb_info);
316 if (err != MS_MEDIA_ERR_NONE) {
317 thumb_err("_media_thumb_image failed");
321 thumb_err("invalid file type");
322 return MS_MEDIA_ERR_THUMB_UNSUPPORTED;
325 if (size) *size = thumb_info.size;
326 if (width) *width = thumb_info.width;
327 if (height) *height = thumb_info.height;
328 *data = thumb_info.data;
329 if (origin_width) *origin_width = thumb_info.origin_width;
330 if (origin_height) *origin_height = thumb_info.origin_height;
331 if (alpha) *alpha = thumb_info.alpha;
332 if (is_saved) *is_saved = thumb_info.is_saved;
334 thumb_dbg("Thumb data is generated successfully (Size:%d, W:%d, H:%d) %p", *size, *width, *height, *data);
336 return MS_MEDIA_ERR_NONE;
339 int _thumbnail_get_raw_data(const char *origin_path,
342 unsigned char **data,
345 int err = MS_MEDIA_ERR_NONE;
346 int thumb_width = -1;
347 int thumb_height = -1;
348 const char * thumb_path = NULL;
350 if (origin_path == NULL || *width <= 0 || *height <= 0) {
351 thumb_err("Invalid parameter");
352 return MS_MEDIA_ERR_INVALID_PARAMETER;
355 if (!g_file_test(origin_path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
356 thumb_err("Original path (%s) does not exist", origin_path);
357 return MS_MEDIA_ERR_INVALID_PARAMETER;
360 int file_type = THUMB_NONE_TYPE;
361 media_thumb_info thumb_info = {0,};
362 file_type = _media_thumb_get_file_type(origin_path);
363 thumb_width = *width;
364 thumb_height = *height;
365 thumb_info.is_raw = TRUE;
367 if (file_type == THUMB_IMAGE_TYPE) {
368 err = _media_thumb_image(origin_path, thumb_path, thumb_width, thumb_height, &thumb_info);
369 if (err != MS_MEDIA_ERR_NONE) {
370 thumb_err("_media_thumb_image failed");
373 } else if (file_type == THUMB_VIDEO_TYPE) {
374 err = _media_thumb_video(origin_path, thumb_width, thumb_height, &thumb_info);
375 if (err != MS_MEDIA_ERR_NONE) {
376 thumb_err("_media_thumb_image failed");
380 thumb_err("invalid file type");
381 return MS_MEDIA_ERR_THUMB_UNSUPPORTED;
384 if (size) *size = thumb_info.size;
385 *data = thumb_info.data;
386 *width = thumb_info.width;
387 *height = thumb_info.height;
389 return MS_MEDIA_ERR_NONE;
392 int _media_thumb_process(thumbMsg *req_msg, thumbMsg *res_msg)
394 int err = MS_MEDIA_ERR_NONE;
395 unsigned char *data = NULL;
402 char *thumb_path = NULL;
403 int need_update_db = 0;
405 bool is_saved = FALSE;
407 if (req_msg == NULL || res_msg == NULL) {
408 thumb_err("Invalid msg!");
409 return MS_MEDIA_ERR_INVALID_PARAMETER;
412 int msg_type = req_msg->msg_type;
413 const char *origin_path = req_msg->org_path;
414 thumb_w = req_msg->thumb_width;
415 thumb_h = req_msg->thumb_height;
416 thumb_path = res_msg->dst_path;
417 thumb_path[0] = '\0';
418 max_length = sizeof(res_msg->dst_path) -1;
419 res_msg->status = MS_MEDIA_ERR_NONE;
421 if (!g_file_test(origin_path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
422 thumb_err("origin_path does not exist in file system.");
423 res_msg->status = MS_MEDIA_ERR_FILE_NOT_EXIST;
424 return MS_MEDIA_ERR_FILE_NOT_EXIST;
427 err = _media_thumb_db_connect(req_msg->uid);
428 if (err != MS_MEDIA_ERR_NONE) {
429 thumb_err("_media_thumb_mb_svc_connect failed: %d", err);
430 res_msg->status = MS_MEDIA_ERR_DB_CONNECT_FAIL;
434 if (msg_type == THUMB_REQUEST_DB_INSERT) {
435 err = _media_thumb_get_thumb_from_db_with_size(origin_path, thumb_path, max_length, &need_update_db, &origin_w, &origin_h);
436 if (err == MS_MEDIA_ERR_NONE) {
437 res_msg->origin_width = origin_w;
438 res_msg->origin_height = origin_h;
439 _media_thumb_db_disconnect();
440 return MS_MEDIA_ERR_NONE;
442 if (strlen(thumb_path) == 0) {
443 err = _media_thumb_get_hash_name(origin_path, thumb_path, max_length, req_msg->uid);
444 if (err != MS_MEDIA_ERR_NONE) {
445 thumb_err("_media_thumb_get_hash_name failed - %d", err);
446 strncpy(thumb_path, THUMB_EMPTY_STR, max_length);
447 _media_thumb_db_disconnect();
448 res_msg->status = err;
452 thumb_path[strlen(thumb_path)] = '\0';
458 thumb_dbg_slog("Thumb path : %s", thumb_path);
460 if (g_file_test(thumb_path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
461 thumb_warn("thumb path already exists in file system.. remove the existed file");
462 _media_thumb_remove_file(thumb_path);
465 err = _thumbnail_get_data(origin_path, thumb_path, &data, &thumb_size, &thumb_w, &thumb_h, &origin_w, &origin_h, &alpha, &is_saved);
466 if (err != MS_MEDIA_ERR_NONE) {
467 thumb_err("_thumbnail_get_data failed - %d", err);
469 strncpy(thumb_path, THUMB_EMPTY_STR, max_length);
470 res_msg->status = err;
475 res_msg->msg_type = THUMB_RESPONSE;
476 res_msg->thumb_size = thumb_size;
477 res_msg->thumb_width = thumb_w;
478 res_msg->thumb_height = thumb_h;
479 res_msg->origin_width = origin_w;
480 res_msg->origin_height = origin_h;
482 /* If the image is transparent PNG format, make png file as thumbnail of this image */
485 err = _media_thumb_get_file_ext(origin_path, file_ext, sizeof(file_ext));
486 if (strncasecmp(file_ext, "png", 3) == 0) {
487 int len = strlen(thumb_path);
488 thumb_path[len - 3] = 'p';
489 thumb_path[len - 2] = 'n';
490 thumb_path[len - 1] = 'g';
492 thumb_dbg_slog("Thumb path is changed : %s", thumb_path);
495 if (is_saved == FALSE && data != NULL) {
496 err = _media_thumb_save_to_file_with_evas(data, thumb_w, thumb_h, alpha, thumb_path);
497 if (err != MS_MEDIA_ERR_NONE) {
498 thumb_err("save_to_file_with_evas failed - %d", err);
501 if (msg_type == THUMB_REQUEST_DB_INSERT) {
502 strncpy(thumb_path, THUMB_EMPTY_STR, max_length);
504 _media_thumb_db_disconnect();
505 res_msg->status = err;
508 thumb_dbg("file save success");
511 thumb_dbg("file is already saved");
516 fd = open(thumb_path, O_WRONLY);
518 thumb_warn("open failed");
522 thumb_warn("fsync failed");
523 res_msg->status = MS_MEDIA_ERR_INTERNAL;
532 /* DB update if needed */
533 if (need_update_db == 1) {
534 err = _media_thumb_update_db(origin_path, thumb_path, res_msg->origin_width, res_msg->origin_height, req_msg->uid);
535 if (err != MS_MEDIA_ERR_NONE) {
536 thumb_err("_media_thumb_update_db failed : %d", err);
537 res_msg->status = err;
541 _media_thumb_db_disconnect();
547 _media_thumb_process_raw(thumbMsg *req_msg, thumbMsg *res_msg)
549 int err = MS_MEDIA_ERR_NONE;
550 unsigned char *data = NULL;
555 if (req_msg == NULL || res_msg == NULL) {
556 thumb_err("Invalid msg!");
557 return MS_MEDIA_ERR_INVALID_PARAMETER;
560 const char *origin_path = req_msg->org_path;
561 thumb_w = req_msg->thumb_width;
562 thumb_h = req_msg->thumb_height;
563 res_msg->status = MS_MEDIA_ERR_NONE;
565 err = _thumbnail_get_raw_data(origin_path, &thumb_w, &thumb_h, &data, &thumb_size);
566 if (err != MS_MEDIA_ERR_NONE) {
567 thumb_err("_thumbnail_get_data failed - %d", err);
568 res_msg->status = err;
572 res_msg->msg_type = THUMB_RESPONSE_RAW_DATA;
573 res_msg->thumb_width = thumb_w;
574 res_msg->thumb_height = thumb_h;
575 res_msg->thumb_size = thumb_size;
576 res_msg->thumb_data = malloc(thumb_size * sizeof(unsigned char));
577 memcpy(res_msg->thumb_data, data, thumb_size);