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 /* Shutdown ecore-evas */
64 ecore_evas_shutdown();
65 g_main_loop_quit(g_thumb_server_mainloop);
70 int _thumb_daemon_process_job(thumbMsg *req_msg, thumbMsg *res_msg)
72 int err = MS_MEDIA_ERR_NONE;
74 if (req_msg->msg_type == THUMB_REQUEST_RAW_DATA) {
75 err = _media_thumb_process_raw(req_msg, res_msg);
76 if (err != MS_MEDIA_ERR_NONE)
77 thumb_warn("_media_thumb_process_raw is failed: %d", err);
78 } else if (req_msg->msg_type == THUMB_REQUEST_DB_INSERT) {
79 err = _media_thumb_process(req_msg, res_msg);
80 if (err != MS_MEDIA_ERR_NONE)
81 thumb_warn("_media_thumb_process is failed: %d", err);
87 gboolean _thumb_server_read_socket(GIOChannel *src,
88 GIOCondition condition,
91 struct sockaddr_un client_addr;
92 unsigned int client_addr_len;
95 ms_peer_credentials credentials;
100 memset((void *)&recv_msg, 0, sizeof(recv_msg));
101 memset((void *)&res_msg, 0, sizeof(res_msg));
102 memset((void *)&credentials, 0, sizeof(credentials));
104 sock = g_io_channel_unix_get_fd(src);
106 thumb_err("sock fd is invalid!");
110 client_addr_len = sizeof(client_addr);
112 if ((client_sock = accept(sock, (struct sockaddr*)&client_addr, &client_addr_len)) < 0) {
113 thumb_stderror("accept failed");
117 if (ms_cynara_receive_untrusted_message_thumb(client_sock, &recv_msg, &credentials) != MS_MEDIA_ERR_NONE) {
118 thumb_err("ms_cynara_receive_untrusted_message_thumb failed");
123 if (recv_msg.msg_type != THUMB_REQUEST_KILL_SERVER) {
124 if (ms_cynara_check(&credentials, MEDIA_STORAGE_PRIVILEGE) != MS_MEDIA_ERR_NONE) {
125 thumb_err("Cynara denied access to process request");
126 _thumb_server_send_deny_message(client_sock);
132 SAFE_FREE(credentials.smack);
133 SAFE_FREE(credentials.uid);
135 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);
137 if (recv_msg.msg_type != THUMB_REQUEST_KILL_SERVER)
138 _thumb_daemon_process_job(&recv_msg, &res_msg);
140 if (res_msg.msg_type == 0)
141 res_msg.msg_type = recv_msg.msg_type;
142 res_msg.request_id = recv_msg.request_id;
143 SAFE_STRLCPY(res_msg.org_path, recv_msg.org_path, sizeof(res_msg.org_path));
144 res_msg.origin_path_size = recv_msg.origin_path_size;
145 if (res_msg.msg_type != THUMB_RESPONSE_RAW_DATA) {
146 res_msg.dest_path_size = strlen(res_msg.dst_path)+1;
147 res_msg.thumb_size = 0;
149 res_msg.dest_path_size = 1;
150 res_msg.dst_path[0] = '\0';
154 int sending_block = 0;
155 int block_size = sizeof(res_msg) - MAX_FILEPATH_LEN*2 - sizeof(unsigned char *);
156 unsigned char *buf = NULL;
157 _media_thumb_set_buffer(&res_msg, &buf, &buf_size);
159 while (buf_size > 0) {
160 if (buf_size < THUMB_BLOCK_SIZE) {
161 block_size = buf_size;
163 if (send(client_sock, buf+sending_block, block_size, 0) != block_size) {
164 thumb_stderror("sendto failed");
166 sending_block += block_size;
167 buf_size -= block_size;
168 if (block_size < THUMB_BLOCK_SIZE) {
169 block_size = THUMB_BLOCK_SIZE;
173 thumb_dbg_slog("Sent data(%d) from %s", res_msg.thumb_size, res_msg.org_path);
176 SAFE_FREE(res_msg.thumb_data);
178 if (recv_msg.msg_type == THUMB_REQUEST_KILL_SERVER) {
179 thumb_warn("Shutting down...");
180 g_main_loop_quit(g_thumb_server_mainloop);
188 static gboolean __thumb_server_send_msg_to_agent(int msg_type)
191 struct sockaddr_un serv_addr;
192 ms_thumb_server_msg send_msg;
194 if (ms_ipc_create_client_socket(MS_TIMEOUT_SEC_10, &sock) < 0) {
195 thumb_err("ms_ipc_create_server_socket failed");
199 memset(&serv_addr, 0, sizeof(serv_addr));
201 serv_addr.sun_family = AF_UNIX;
202 SAFE_STRLCPY(serv_addr.sun_path, THUMB_COMM_SOCK_PATH, sizeof(serv_addr.sun_path));
205 /* Connecting to the thumbnail server */
206 if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
207 thumb_stderror("connect");
209 return MS_MEDIA_ERR_SOCKET_CONN;
212 send_msg.msg_type = msg_type;
214 if (send(sock, &send_msg, sizeof(ms_thumb_server_msg), 0) != sizeof(ms_thumb_server_msg)) {
215 thumb_stderror("sendto failed");
220 thumb_dbg("Sending msg to thumbnail agent[%d] is successful", send_msg.msg_type);
226 static gboolean _thumb_server_send_deny_message(int sockfd)
229 int bytes_to_send = sizeof(msg) - sizeof(msg.org_path) - sizeof(msg.dst_path);
231 msg.msg_type = THUMB_RESPONSE;
232 msg.status = MS_MEDIA_ERR_PERMISSION_DENIED;
234 if (send(sockfd, &msg, bytes_to_send, 0) != bytes_to_send) {
235 thumb_stderror("send failed");
242 gboolean _thumb_server_prepare_socket(int *sock_fd)
246 if (ms_ipc_create_server_socket(MS_THUMB_DAEMON_PORT, &sock) < 0) {
247 thumb_err("ms_ipc_create_server_socket failed");
251 if (ms_cynara_enable_credentials_passing(sock) != MS_MEDIA_ERR_NONE) {
252 thumb_err("ms_cynara_enable_credentials_passing failed");
262 int _thumbnail_get_data(const char *origin_path,
264 unsigned char **data,
271 int err = MS_MEDIA_ERR_NONE;
272 int thumb_width = -1;
273 int thumb_height = -1;
275 if (origin_path == NULL || size == NULL || width == NULL || height == NULL) {
276 thumb_err("Invalid parameter");
277 return MS_MEDIA_ERR_INVALID_PARAMETER;
280 if (!g_file_test(origin_path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
281 thumb_err("Original path (%s) does not exist", origin_path);
282 return MS_MEDIA_ERR_INVALID_PARAMETER;
285 thumb_dbg("Origin path : %s", origin_path);
287 int file_type = THUMB_NONE_TYPE;
288 media_thumb_info thumb_info = {0,};
289 file_type = _media_thumb_get_file_type(origin_path);
290 thumb_width = *width;
291 thumb_height = *height;
292 if (thumb_width == 0 || thumb_height == 0) {
293 thumb_width = THUMB_DEFAULT_WIDTH;
294 thumb_height = THUMB_DEFAULT_HEIGHT;
297 thumb_info.is_raw = FALSE;
299 if (file_type == THUMB_IMAGE_TYPE) {
300 err = _media_thumb_image(origin_path, thumb_path, thumb_width, thumb_height, &thumb_info);
301 if (err != MS_MEDIA_ERR_NONE) {
302 thumb_err("_media_thumb_image failed");
305 } else if (file_type == THUMB_VIDEO_TYPE) {
306 err = _media_thumb_video(origin_path, thumb_width, thumb_height, &thumb_info);
307 if (err != MS_MEDIA_ERR_NONE) {
308 thumb_err("_media_thumb_image failed");
312 thumb_err("invalid file type");
313 return MS_MEDIA_ERR_THUMB_UNSUPPORTED;
316 if (size) *size = thumb_info.size;
317 if (width) *width = thumb_info.width;
318 if (height) *height = thumb_info.height;
319 *data = thumb_info.data;
320 if (alpha) *alpha = thumb_info.alpha;
321 if (is_saved) *is_saved = thumb_info.is_saved;
323 thumb_dbg("Thumb data is generated successfully (Size:%d, W:%d, H:%d) %p", *size, *width, *height, *data);
325 return MS_MEDIA_ERR_NONE;
328 int _thumbnail_get_raw_data(const char *origin_path,
331 unsigned char **data,
334 int err = MS_MEDIA_ERR_NONE;
335 int thumb_width = -1;
336 int thumb_height = -1;
337 const char * thumb_path = NULL;
339 if (origin_path == NULL || *width <= 0 || *height <= 0) {
340 thumb_err("Invalid parameter");
341 return MS_MEDIA_ERR_INVALID_PARAMETER;
344 if (!g_file_test(origin_path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
345 thumb_err("Original path (%s) does not exist", origin_path);
346 return MS_MEDIA_ERR_INVALID_PARAMETER;
349 int file_type = THUMB_NONE_TYPE;
350 media_thumb_info thumb_info = {0,};
351 file_type = _media_thumb_get_file_type(origin_path);
352 thumb_width = *width;
353 thumb_height = *height;
354 thumb_info.is_raw = TRUE;
356 if (file_type == THUMB_IMAGE_TYPE) {
357 err = _media_thumb_image(origin_path, thumb_path, thumb_width, thumb_height, &thumb_info);
358 if (err != MS_MEDIA_ERR_NONE) {
359 thumb_err("_media_thumb_image failed");
362 } else if (file_type == THUMB_VIDEO_TYPE) {
363 err = _media_thumb_video(origin_path, thumb_width, thumb_height, &thumb_info);
364 if (err != MS_MEDIA_ERR_NONE) {
365 thumb_err("_media_thumb_image failed");
369 thumb_err("invalid file type");
370 return MS_MEDIA_ERR_THUMB_UNSUPPORTED;
373 if (size) *size = thumb_info.size;
374 *data = thumb_info.data;
375 *width = thumb_info.width;
376 *height = thumb_info.height;
378 return MS_MEDIA_ERR_NONE;
381 int _media_thumb_process(thumbMsg *req_msg, thumbMsg *res_msg)
383 int err = MS_MEDIA_ERR_NONE;
384 unsigned char *data = NULL;
389 char *thumb_path = NULL;
391 bool is_saved = FALSE;
393 if (req_msg == NULL || res_msg == NULL) {
394 thumb_err("Invalid msg!");
395 return MS_MEDIA_ERR_INVALID_PARAMETER;
398 const char *origin_path = req_msg->org_path;
399 thumb_w = req_msg->thumb_width;
400 thumb_h = req_msg->thumb_height;
401 thumb_path = res_msg->dst_path;
402 thumb_path[0] = '\0';
403 max_length = sizeof(res_msg->dst_path) -1;
404 res_msg->status = MS_MEDIA_ERR_NONE;
406 if (!g_file_test(origin_path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
407 thumb_err("origin_path does not exist in file system.");
408 res_msg->status = MS_MEDIA_ERR_FILE_NOT_EXIST;
409 return MS_MEDIA_ERR_FILE_NOT_EXIST;
412 err = _media_thumb_get_thumb_from_db(origin_path, thumb_path, max_length, req_msg->uid);
413 if (err == MS_MEDIA_ERR_NONE) {
414 thumb_dbg_slog("Thumb path : %s", thumb_path);
415 return MS_MEDIA_ERR_NONE;
417 if (strlen(thumb_path) == 0) {
418 err = _media_thumb_get_hash_name(origin_path, thumb_path, max_length, req_msg->uid);
419 if (err != MS_MEDIA_ERR_NONE) {
420 thumb_err("_media_thumb_get_hash_name failed - %d", err);
421 strncpy(thumb_path, THUMB_EMPTY_STR, max_length);
422 res_msg->status = err;
426 thumb_path[strlen(thumb_path)] = '\0';
430 thumb_dbg_slog("Thumb path : %s", thumb_path);
432 if (g_file_test(thumb_path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
433 thumb_warn("thumb path already exists in file system.. remove the existed file");
434 _media_thumb_remove_file(thumb_path);
437 err = _thumbnail_get_data(origin_path, thumb_path, &data, &thumb_size, &thumb_w, &thumb_h, &alpha, &is_saved);
438 if (err != MS_MEDIA_ERR_NONE) {
439 thumb_err("_thumbnail_get_data failed - %d", err);
441 strncpy(thumb_path, THUMB_EMPTY_STR, max_length);
442 res_msg->status = err;
447 res_msg->msg_type = THUMB_RESPONSE;
448 res_msg->thumb_size = thumb_size;
449 res_msg->thumb_width = thumb_w;
450 res_msg->thumb_height = thumb_h;
452 /* If the image is transparent PNG format, make png file as thumbnail of this image */
455 err = _media_thumb_get_file_ext(origin_path, file_ext, sizeof(file_ext));
456 if (strncasecmp(file_ext, "png", 3) == 0) {
457 int len = strlen(thumb_path);
458 thumb_path[len - 3] = 'p';
459 thumb_path[len - 2] = 'n';
460 thumb_path[len - 1] = 'g';
462 thumb_dbg_slog("Thumb path is changed : %s", thumb_path);
465 if (is_saved == FALSE && data != NULL) {
466 err = _media_thumb_save_to_file_with_evas(data, thumb_w, thumb_h, alpha, thumb_path);
467 if (err != MS_MEDIA_ERR_NONE) {
468 thumb_err("save_to_file_with_evas failed - %d", err);
471 strncpy(thumb_path, THUMB_EMPTY_STR, max_length);
472 res_msg->status = err;
475 thumb_dbg("file save success");
478 thumb_dbg("file is already saved");
483 fd = open(thumb_path, O_WRONLY);
485 thumb_warn("open failed");
489 thumb_warn("fsync failed");
490 res_msg->status = MS_MEDIA_ERR_INTERNAL;
499 err = _media_thumb_update_db(origin_path, thumb_path, req_msg->uid);
500 if (err != MS_MEDIA_ERR_NONE) {
501 thumb_err("_media_thumb_update_db failed : %d", err);
502 res_msg->status = err;
509 _media_thumb_process_raw(thumbMsg *req_msg, thumbMsg *res_msg)
511 int err = MS_MEDIA_ERR_NONE;
512 unsigned char *data = NULL;
517 if (req_msg == NULL || res_msg == NULL) {
518 thumb_err("Invalid msg!");
519 return MS_MEDIA_ERR_INVALID_PARAMETER;
522 const char *origin_path = req_msg->org_path;
523 thumb_w = req_msg->thumb_width;
524 thumb_h = req_msg->thumb_height;
525 res_msg->status = MS_MEDIA_ERR_NONE;
526 res_msg->msg_type = THUMB_RESPONSE_RAW_DATA;
528 err = _thumbnail_get_raw_data(origin_path, &thumb_w, &thumb_h, &data, &thumb_size);
529 if (err != MS_MEDIA_ERR_NONE) {
530 thumb_err("_thumbnail_get_data failed - %d", err);
531 res_msg->status = err;
532 res_msg->thumb_size = 0;
538 res_msg->thumb_width = thumb_w;
539 res_msg->thumb_height = thumb_h;
540 res_msg->thumb_size = thumb_size;
541 res_msg->thumb_data = malloc(thumb_size * sizeof(unsigned char));
542 memcpy(res_msg->thumb_data, data, thumb_size);