Remove original width, height parameters from response msg
[platform/core/multimedia/libmedia-thumbnail.git] / server / thumb-server-internal.c
1 /*
2  * media-thumbnail-server
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Hyunjun Ko <zzoon.ko@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 "thumb-server-internal.h"
23 #include "media-thumb-util.h"
24 #include "media-thumb-debug.h"
25
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <dirent.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <Ecore_Evas.h>
32 #include <tzplatform_config.h>
33
34 #ifdef LOG_TAG
35 #undef LOG_TAG
36 #endif
37
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 ""
44
45 GMainLoop *g_thumb_server_mainloop; // defined in thumb-server.c as extern
46
47 static gboolean __thumb_server_send_msg_to_agent(int msg_type);
48 static gboolean _thumb_server_send_deny_message(int sockfd);
49
50 gboolean _thumb_daemon_start_jobs(gpointer data)
51 {
52         thumb_dbg("");
53         /* Initialize ecore-evas to use evas library */
54         ecore_evas_init();
55
56         __thumb_server_send_msg_to_agent(MS_MSG_THUMB_SERVER_READY);
57
58         return FALSE;
59 }
60
61 void _thumb_daemon_finish_jobs(void)
62 {
63         /* Shutdown ecore-evas */
64         ecore_evas_shutdown();
65         g_main_loop_quit(g_thumb_server_mainloop);
66
67         return;
68 }
69
70 int _thumb_daemon_process_job(thumbMsg *req_msg, thumbMsg *res_msg)
71 {
72         int err = MS_MEDIA_ERR_NONE;
73
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);
82         }
83
84         return err;
85 }
86
87 gboolean _thumb_server_read_socket(GIOChannel *src,
88                                                                         GIOCondition condition,
89                                                                         gpointer data)
90 {
91         struct sockaddr_un client_addr;
92         unsigned int client_addr_len;
93         thumbMsg recv_msg;
94         thumbMsg res_msg;
95         ms_peer_credentials credentials;
96
97         int sock = -1;
98         int client_sock = -1;
99
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));
103
104         sock = g_io_channel_unix_get_fd(src);
105         if (sock < 0) {
106                 thumb_err("sock fd is invalid!");
107                 return TRUE;
108         }
109
110         client_addr_len = sizeof(client_addr);
111
112         if ((client_sock = accept(sock, (struct sockaddr*)&client_addr, &client_addr_len)) < 0) {
113                 thumb_stderror("accept failed");
114                 return TRUE;
115         }
116
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");
119                 close(client_sock);
120                 return FALSE;
121         }
122
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);
127                         close(client_sock);
128                         return TRUE;
129                 }
130         }
131
132         SAFE_FREE(credentials.smack);
133         SAFE_FREE(credentials.uid);
134
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);
136
137         if (recv_msg.msg_type != THUMB_REQUEST_KILL_SERVER)
138                 _thumb_daemon_process_job(&recv_msg, &res_msg);
139
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;
148         } else {
149                 res_msg.dest_path_size = 1;
150                 res_msg.dst_path[0] = '\0';
151         }
152
153         int buf_size = 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);
158
159         while (buf_size > 0) {
160                 if (buf_size < THUMB_BLOCK_SIZE) {
161                         block_size = buf_size;
162                 }
163                 if (send(client_sock, buf+sending_block, block_size, 0) != block_size) {
164                         thumb_stderror("sendto failed");
165                 }
166                 sending_block += block_size;
167                 buf_size -= block_size;
168                 if (block_size < THUMB_BLOCK_SIZE) {
169                         block_size = THUMB_BLOCK_SIZE;
170                 }
171         }
172
173         thumb_dbg_slog("Sent data(%d) from %s", res_msg.thumb_size, res_msg.org_path);
174
175         SAFE_FREE(buf);
176         SAFE_FREE(res_msg.thumb_data);
177
178         if (recv_msg.msg_type == THUMB_REQUEST_KILL_SERVER) {
179                 thumb_warn("Shutting down...");
180                 g_main_loop_quit(g_thumb_server_mainloop);
181         }
182
183         close(client_sock);
184
185         return TRUE;
186 }
187
188 static gboolean __thumb_server_send_msg_to_agent(int msg_type)
189 {
190         int sock;
191         struct sockaddr_un serv_addr;
192         ms_thumb_server_msg send_msg;
193
194         if (ms_ipc_create_client_socket(MS_TIMEOUT_SEC_10, &sock) < 0) {
195                 thumb_err("ms_ipc_create_server_socket failed");
196                 return FALSE;
197         }
198
199         memset(&serv_addr, 0, sizeof(serv_addr));
200
201         serv_addr.sun_family = AF_UNIX;
202         SAFE_STRLCPY(serv_addr.sun_path, THUMB_COMM_SOCK_PATH, sizeof(serv_addr.sun_path));
203
204
205         /* Connecting to the thumbnail server */
206         if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
207                 thumb_stderror("connect");
208                 close(sock);
209                 return MS_MEDIA_ERR_SOCKET_CONN;
210         }
211
212         send_msg.msg_type = msg_type;
213
214         if (send(sock, &send_msg, sizeof(ms_thumb_server_msg), 0) != sizeof(ms_thumb_server_msg)) {
215                 thumb_stderror("sendto failed");
216                 close(sock);
217                 return FALSE;
218         }
219
220         thumb_dbg("Sending msg to thumbnail agent[%d] is successful", send_msg.msg_type);
221         close(sock);
222
223         return TRUE;
224 }
225
226 static gboolean _thumb_server_send_deny_message(int sockfd)
227 {
228         thumbMsg msg = {0};
229         int bytes_to_send = sizeof(msg) - sizeof(msg.org_path) - sizeof(msg.dst_path);
230
231         msg.msg_type = THUMB_RESPONSE;
232         msg.status = MS_MEDIA_ERR_PERMISSION_DENIED;
233
234         if (send(sockfd, &msg, bytes_to_send, 0) != bytes_to_send) {
235                 thumb_stderror("send failed");
236                 return FALSE;
237         }
238
239         return TRUE;
240 }
241
242 gboolean _thumb_server_prepare_socket(int *sock_fd)
243 {
244         int sock;
245
246         if (ms_ipc_create_server_socket(MS_THUMB_DAEMON_PORT, &sock) < 0) {
247                 thumb_err("ms_ipc_create_server_socket failed");
248                 return FALSE;
249         }
250
251         if (ms_cynara_enable_credentials_passing(sock) != MS_MEDIA_ERR_NONE) {
252                 thumb_err("ms_cynara_enable_credentials_passing failed");
253                 close(sock);
254                 return FALSE;
255         }
256
257         *sock_fd = sock;
258
259         return TRUE;
260 }
261
262 int _thumbnail_get_data(const char *origin_path,
263                                                 char *thumb_path,
264                                                 unsigned char **data,
265                                                 int *size,
266                                                 int *width,
267                                                 int *height,
268                                                 int *alpha,
269                                                 bool *is_saved)
270 {
271         int err = MS_MEDIA_ERR_NONE;
272         int thumb_width = -1;
273         int thumb_height = -1;
274
275         if (origin_path == NULL || size == NULL || width == NULL || height == NULL) {
276                 thumb_err("Invalid parameter");
277                 return MS_MEDIA_ERR_INVALID_PARAMETER;
278         }
279
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;
283         }
284
285         thumb_dbg("Origin path : %s", origin_path);
286
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;
295         }
296
297         thumb_info.is_raw = FALSE;
298
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");
303                         return err;
304                 }
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");
309                         return err;
310                 }
311         } else {
312                 thumb_err("invalid file type");
313                 return MS_MEDIA_ERR_THUMB_UNSUPPORTED;
314         }
315
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;
322
323         thumb_dbg("Thumb data is generated successfully (Size:%d, W:%d, H:%d) %p", *size, *width, *height, *data);
324
325         return MS_MEDIA_ERR_NONE;
326 }
327
328 int _thumbnail_get_raw_data(const char *origin_path,
329                                                 int *width,
330                                                 int *height,
331                                                 unsigned char **data,
332                                                 int *size)
333 {
334         int err = MS_MEDIA_ERR_NONE;
335         int thumb_width = -1;
336         int thumb_height = -1;
337         const char * thumb_path = NULL;
338
339         if (origin_path == NULL || *width <= 0 || *height <= 0) {
340                 thumb_err("Invalid parameter");
341                 return MS_MEDIA_ERR_INVALID_PARAMETER;
342         }
343
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;
347         }
348
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;
355
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");
360                         return err;
361                 }
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");
366                         return err;
367                 }
368         } else {
369                 thumb_err("invalid file type");
370                 return MS_MEDIA_ERR_THUMB_UNSUPPORTED;
371         }
372
373         if (size) *size = thumb_info.size;
374         *data = thumb_info.data;
375         *width = thumb_info.width;
376         *height = thumb_info.height;
377
378         return MS_MEDIA_ERR_NONE;
379 }
380
381 int _media_thumb_process(thumbMsg *req_msg, thumbMsg *res_msg)
382 {
383         int err = MS_MEDIA_ERR_NONE;
384         unsigned char *data = NULL;
385         int thumb_size = 0;
386         int thumb_w = 0;
387         int thumb_h = 0;
388         int max_length = 0;
389         char *thumb_path = NULL;
390         int alpha = 0;
391         bool is_saved = FALSE;
392
393         if (req_msg == NULL || res_msg == NULL) {
394                 thumb_err("Invalid msg!");
395                 return MS_MEDIA_ERR_INVALID_PARAMETER;
396         }
397
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;
405
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;
410         }
411
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;
416         } else {
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;
423                                 return err;
424                         }
425
426                         thumb_path[strlen(thumb_path)] = '\0';
427                 }
428         }
429
430         thumb_dbg_slog("Thumb path : %s", thumb_path);
431
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);
435         }
436
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);
440                 SAFE_FREE(data);
441                 strncpy(thumb_path, THUMB_EMPTY_STR, max_length);
442                 res_msg->status = err;
443
444                 goto DB_UPDATE;
445         }
446
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;
451
452         /* If the image is transparent PNG format, make png file as thumbnail of this image */
453         if (alpha) {
454                 char file_ext[10];
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';
461                 }
462                 thumb_dbg_slog("Thumb path is changed : %s", thumb_path);
463         }
464
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);
469                         SAFE_FREE(data);
470
471                         strncpy(thumb_path, THUMB_EMPTY_STR, max_length);
472                         res_msg->status = err;
473                         return err;
474                 } else {
475                         thumb_dbg("file save success");
476                 }
477         } else {
478                 thumb_dbg("file is already saved");
479         }
480
481         /* fsync */
482         int fd = 0;
483         fd = open(thumb_path, O_WRONLY);
484         if (fd < 0) {
485                 thumb_warn("open failed");
486         } else {
487                 err = fsync(fd);
488                 if (err == -1) {
489                         thumb_warn("fsync failed");
490                         res_msg->status = MS_MEDIA_ERR_INTERNAL;
491                 }
492
493                 close(fd);
494         }
495         /* End of fsync */
496
497         SAFE_FREE(data);
498 DB_UPDATE:
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;
503         }
504
505         return err;
506 }
507
508 int
509 _media_thumb_process_raw(thumbMsg *req_msg, thumbMsg *res_msg)
510 {
511         int err = MS_MEDIA_ERR_NONE;
512         unsigned char *data = NULL;
513         int thumb_size = 0;
514         int thumb_w = 0;
515         int thumb_h = 0;
516
517         if (req_msg == NULL || res_msg == NULL) {
518                 thumb_err("Invalid msg!");
519                 return MS_MEDIA_ERR_INVALID_PARAMETER;
520         }
521
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;
527
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;
533                 SAFE_FREE(data);
534
535                 return err;
536         }
537
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);
543
544         SAFE_FREE(data);
545
546         return err;
547 }