Code cleanup
[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         sqlite3 *sqlite_db_handle = _media_thumb_db_get_handle();
64
65         if (sqlite_db_handle != NULL) {
66                 _media_thumb_db_disconnect();
67                 thumb_dbg("sqlite3 handle is alive. So disconnect to sqlite3");
68         }
69
70         /* Shutdown ecore-evas */
71         ecore_evas_shutdown();
72         g_main_loop_quit(g_thumb_server_mainloop);
73
74         return;
75 }
76
77 int _thumb_daemon_process_job(thumbMsg *req_msg, thumbMsg *res_msg)
78 {
79         int err = MS_MEDIA_ERR_NONE;
80
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);
85         } else {
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);
89         }
90
91         return err;
92 }
93
94 gboolean _thumb_server_read_socket(GIOChannel *src,
95                                                                         GIOCondition condition,
96                                                                         gpointer data)
97 {
98         struct sockaddr_un client_addr;
99         unsigned int client_addr_len;
100         thumbMsg recv_msg;
101         thumbMsg res_msg;
102         ms_peer_credentials credentials;
103
104         int sock = -1;
105         int client_sock = -1;
106
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));
110
111         sock = g_io_channel_unix_get_fd(src);
112         if (sock < 0) {
113                 thumb_err("sock fd is invalid!");
114                 return TRUE;
115         }
116
117         client_addr_len = sizeof(client_addr);
118
119         if ((client_sock = accept(sock, (struct sockaddr*)&client_addr, &client_addr_len)) < 0) {
120                 thumb_stderror("accept failed : %s");
121                 return TRUE;
122         }
123
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");
126                 close(client_sock);
127                 return FALSE;
128         }
129
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);
134                         close(client_sock);
135                         return TRUE;
136                 }
137         }
138
139         SAFE_FREE(credentials.smack);
140         SAFE_FREE(credentials.uid);
141
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);
143
144         if (recv_msg.msg_type != THUMB_REQUEST_KILL_SERVER)
145                 _thumb_daemon_process_job(&recv_msg, &res_msg);
146
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;
155         } else {
156                 res_msg.dest_path_size = 1;
157                 res_msg.dst_path[0] = '\0';
158         }
159
160         int buf_size = 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);
165
166         while (buf_size > 0) {
167                 if (buf_size < THUMB_BLOCK_SIZE) {
168                         block_size = buf_size;
169                 }
170                 if (send(client_sock, buf+sending_block, block_size, 0) != block_size) {
171                         thumb_stderror("sendto failed : %s");
172                 }
173                 sending_block += block_size;
174                 buf_size -= block_size;
175                 if (block_size < THUMB_BLOCK_SIZE) {
176                         block_size = THUMB_BLOCK_SIZE;
177                 }
178         }
179
180         thumb_dbg_slog("Sent data(%d) from %s", res_msg.thumb_size, res_msg.org_path);
181
182         SAFE_FREE(buf);
183         SAFE_FREE(res_msg.thumb_data);
184
185         if (recv_msg.msg_type == THUMB_REQUEST_KILL_SERVER) {
186                 thumb_warn("Shutting down...");
187                 g_main_loop_quit(g_thumb_server_mainloop);
188         }
189
190         close(client_sock);
191
192         return TRUE;
193 }
194
195 static gboolean __thumb_server_send_msg_to_agent(int msg_type)
196 {
197         int sock;
198         struct sockaddr_un serv_addr;
199         ms_thumb_server_msg send_msg;
200
201         if (ms_ipc_create_client_socket(MS_TIMEOUT_SEC_10, &sock) < 0) {
202                 thumb_err("ms_ipc_create_server_socket failed");
203                 return FALSE;
204         }
205
206         memset(&serv_addr, 0, sizeof(serv_addr));
207
208         serv_addr.sun_family = AF_UNIX;
209         SAFE_STRLCPY(serv_addr.sun_path, THUMB_COMM_SOCK_PATH, sizeof(serv_addr.sun_path));
210
211
212         /* Connecting to the thumbnail server */
213         if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
214                 thumb_stderror("connect");
215                 close(sock);
216                 return MS_MEDIA_ERR_SOCKET_CONN;
217         }
218
219         send_msg.msg_type = msg_type;
220
221         if (send(sock, &send_msg, sizeof(ms_thumb_server_msg), 0) != sizeof(ms_thumb_server_msg)) {
222                 thumb_stderror("sendto failed");
223                 close(sock);
224                 return FALSE;
225         }
226
227         thumb_dbg("Sending msg to thumbnail agent[%d] is successful", send_msg.msg_type);
228         close(sock);
229
230         return TRUE;
231 }
232
233 static gboolean _thumb_server_send_deny_message(int sockfd)
234 {
235         thumbMsg msg = {0};
236         int bytes_to_send = sizeof(msg) - sizeof(msg.org_path) - sizeof(msg.dst_path);
237
238         msg.msg_type = THUMB_RESPONSE;
239         msg.status = MS_MEDIA_ERR_PERMISSION_DENIED;
240
241         if (send(sockfd, &msg, bytes_to_send, 0) != bytes_to_send) {
242                 thumb_stderror("send failed");
243                 return FALSE;
244         }
245
246         return TRUE;
247 }
248
249 gboolean _thumb_server_prepare_socket(int *sock_fd)
250 {
251         int sock;
252
253         if (ms_ipc_create_server_socket(MS_THUMB_DAEMON_PORT, &sock) < 0) {
254                 thumb_err("ms_ipc_create_server_socket failed");
255                 return FALSE;
256         }
257
258         if (ms_cynara_enable_credentials_passing(sock) != MS_MEDIA_ERR_NONE) {
259                 thumb_err("ms_cynara_enable_credentials_passing failed");
260                 close(sock);
261                 return FALSE;
262         }
263
264         *sock_fd = sock;
265
266         return TRUE;
267 }
268
269 int _thumbnail_get_data(const char *origin_path,
270                                                 char *thumb_path,
271                                                 unsigned char **data,
272                                                 int *size,
273                                                 int *width,
274                                                 int *height,
275                                                 int *origin_width,
276                                                 int *origin_height,
277                                                 int *alpha,
278                                                 bool *is_saved)
279 {
280         int err = MS_MEDIA_ERR_NONE;
281         int thumb_width = -1;
282         int thumb_height = -1;
283
284         if (origin_path == NULL || size == NULL || width == NULL || height == NULL) {
285                 thumb_err("Invalid parameter");
286                 return MS_MEDIA_ERR_INVALID_PARAMETER;
287         }
288
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;
292         }
293
294         thumb_dbg("Origin path : %s", origin_path);
295
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;
304         }
305
306         thumb_info.is_raw = FALSE;
307
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");
312                         return err;
313                 }
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");
318                         return err;
319                 }
320         } else {
321                 thumb_err("invalid file type");
322                 return MS_MEDIA_ERR_THUMB_UNSUPPORTED;
323         }
324
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;
333
334         thumb_dbg("Thumb data is generated successfully (Size:%d, W:%d, H:%d) 0x%x", *size, *width, *height, *data);
335
336         return MS_MEDIA_ERR_NONE;
337 }
338
339 int _thumbnail_get_raw_data(const char *origin_path,
340                                                 int *width,
341                                                 int *height,
342                                                 unsigned char **data,
343                                                 int *size)
344 {
345         int err = MS_MEDIA_ERR_NONE;
346         int thumb_width = -1;
347         int thumb_height = -1;
348         const char * thumb_path = NULL;
349
350         if (origin_path == NULL || *width <= 0 || *height <= 0) {
351                 thumb_err("Invalid parameter");
352                 return MS_MEDIA_ERR_INVALID_PARAMETER;
353         }
354
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;
358         }
359
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;
366
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");
371                         return err;
372                 }
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");
377                         return err;
378                 }
379         } else {
380                 thumb_err("invalid file type");
381                 return MS_MEDIA_ERR_THUMB_UNSUPPORTED;
382         }
383
384         if (size) *size = thumb_info.size;
385         *data = thumb_info.data;
386         *width = thumb_info.width;
387         *height = thumb_info.height;
388
389         return MS_MEDIA_ERR_NONE;
390 }
391
392 int _media_thumb_process(thumbMsg *req_msg, thumbMsg *res_msg)
393 {
394         int err = MS_MEDIA_ERR_NONE;
395         unsigned char *data = NULL;
396         int thumb_size = 0;
397         int thumb_w = 0;
398         int thumb_h = 0;
399         int origin_w = 0;
400         int origin_h = 0;
401         int max_length = 0;
402         char *thumb_path = NULL;
403         int need_update_db = 0;
404         int alpha = 0;
405         bool is_saved = FALSE;
406
407         if (req_msg == NULL || res_msg == NULL) {
408                 thumb_err("Invalid msg!");
409                 return MS_MEDIA_ERR_INVALID_PARAMETER;
410         }
411
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;
420
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;
425         }
426
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;
431                 return err;
432         }
433
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;
441                 } else {
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;
449                                         return err;
450                                 }
451
452                                 thumb_path[strlen(thumb_path)] = '\0';
453                         }
454                 }
455
456         }
457
458         thumb_dbg_slog("Thumb path : %s", thumb_path);
459
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);
463         }
464
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);
468                 SAFE_FREE(data);
469                 strncpy(thumb_path, THUMB_EMPTY_STR, max_length);
470                 res_msg->status = err;
471
472                 goto DB_UPDATE;
473         }
474
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;
481
482         /* If the image is transparent PNG format, make png file as thumbnail of this image */
483         if (alpha) {
484                 char file_ext[10];
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';
491                 }
492                 thumb_dbg_slog("Thumb path is changed : %s", thumb_path);
493         }
494
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);
499                         SAFE_FREE(data);
500
501                         if (msg_type == THUMB_REQUEST_DB_INSERT) {
502                                 strncpy(thumb_path, THUMB_EMPTY_STR, max_length);
503                         }
504                         _media_thumb_db_disconnect();
505                         res_msg->status = err;
506                         return err;
507                 } else {
508                         thumb_dbg("file save success");
509                 }
510         } else {
511                 thumb_dbg("file is already saved");
512         }
513
514         /* fsync */
515         int fd = 0;
516         fd = open(thumb_path, O_WRONLY);
517         if (fd < 0) {
518                 thumb_warn("open failed");
519         } else {
520                 err = fsync(fd);
521                 if (err == -1) {
522                         thumb_warn("fsync failed");
523                         res_msg->status = MS_MEDIA_ERR_INTERNAL;
524                 }
525
526                 close(fd);
527         }
528         /* End of fsync */
529
530         SAFE_FREE(data);
531 DB_UPDATE:
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;
538                 }
539         }
540
541         _media_thumb_db_disconnect();
542
543         return err;
544 }
545
546 int
547 _media_thumb_process_raw(thumbMsg *req_msg, thumbMsg *res_msg)
548 {
549         int err = MS_MEDIA_ERR_NONE;
550         unsigned char *data = NULL;
551         int thumb_size = 0;
552         int thumb_w = 0;
553         int thumb_h = 0;
554
555         if (req_msg == NULL || res_msg == NULL) {
556                 thumb_err("Invalid msg!");
557                 return MS_MEDIA_ERR_INVALID_PARAMETER;
558         }
559
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;
564
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;
569                 SAFE_FREE(data);
570         }
571
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);
578
579         SAFE_FREE(data);
580
581         return err;
582 }