Merge "Fix Coverity issue" into tizen
[platform/core/multimedia/libmedia-thumbnail.git] / src / ipc / media-thumb-ipc.c
1 /*
2  * libmedia-thumbnail
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 "media-thumbnail.h"
23 #include "media-thumb-ipc.h"
24 #include "media-thumb-util.h"
25 #include "media-thumb-db.h"
26 #include "media-thumb-debug.h"
27 #include <glib.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <grp.h>
32 #include <pwd.h>
33
34 #define THUMB_IPC_PATH tzplatform_mkpath(TZ_SYS_RUN, "media-server/media_ipc_thumbcreator.socket")
35
36 static GQueue *g_manage_queue = NULL;
37 static GQueue *g_manage_raw_queue = NULL;
38
39
40 typedef struct {
41         GIOChannel *channel;
42         int msg_type;
43         unsigned int request_id;
44         bool isCanceled;
45         bool isRequested;
46         int source_id;
47         uid_t uid;
48         char *path;
49         thumbUserData *userData;
50 } thumbReq;
51
52 typedef struct {
53         GIOChannel *channel;
54         int msg_type;
55         bool isCanceled;
56         bool isRequested;
57         int request_id;
58         int source_id;
59         int width;
60         int height;
61         uid_t uid;
62         char *path;
63         thumbRawUserData *userData;
64 } thumbRawReq;
65
66 static int __media_thumb_send_request(void);
67 static int __media_thumb_raw_data_send_request(void);
68
69
70 static int __media_thumb_get_error(void)
71 {
72         if (errno == EWOULDBLOCK) {
73                 thumb_err("Timeout. Can't try any more");
74                 return MS_MEDIA_ERR_SOCKET_RECEIVE_TIMEOUT;
75         } else {
76                 thumb_stderror("recvfrom failed");
77                 return MS_MEDIA_ERR_SOCKET_RECEIVE;
78         }
79 }
80
81 static void __media_thumb_pop(void)
82 {
83         int len = 0;
84         int sock = 0;
85         thumbReq *req = NULL;
86
87         if (!g_manage_queue)
88                 return;
89
90         req = (thumbReq *)g_queue_pop_head(g_manage_queue);
91         if (req != NULL) {
92                 GSource *source_id = g_main_context_find_source_by_id(g_main_context_get_thread_default(), req->source_id);
93                 sock = g_io_channel_unix_get_fd(req->channel);
94
95                 g_io_channel_shutdown(req->channel, TRUE, NULL);
96                 g_io_channel_unref(req->channel);
97                 close(sock);
98                 if (source_id) {
99                         g_source_destroy(source_id);
100                 } else {
101                         thumb_err("G_SOURCE_ID is NULL");
102                 }
103
104                 SAFE_FREE(req->path);
105                 SAFE_FREE(req->userData);
106                 SAFE_FREE(req);
107         }
108
109         /* Check manage queue */
110         len = g_queue_get_length(g_manage_queue);
111         if (len > 0)
112                 __media_thumb_send_request();
113 }
114
115 static int __media_thumb_cancel(unsigned int request_id)
116 {
117         int len = 0, i;
118
119         thumb_retv_if(!g_manage_queue, MS_MEDIA_ERR_NONE);
120
121         len = g_queue_get_length(g_manage_queue);
122
123         for (i = 0; i < len; i++) {
124                 thumbReq *req = NULL;
125                 req = (thumbReq *)g_queue_peek_nth(g_manage_queue, i);
126                 if (req == NULL) continue;
127
128                 if (req->request_id == request_id) {
129                         if (req->isRequested) {
130                                 req->isCanceled = true;
131                         } else {
132                                 g_queue_pop_nth(g_manage_queue, i);
133
134                                 SAFE_FREE(req->path);
135                                 SAFE_FREE(req->userData);
136                                 SAFE_FREE(req);
137                         }
138
139                         return MS_MEDIA_ERR_NONE;
140                 }
141         }
142
143         return MS_MEDIA_ERR_INTERNAL;
144 }
145
146 static void __media_thumb_pop_raw_data(void)
147 {
148         int len = 0;
149         int sock = 0;
150         thumbRawReq *req = NULL;
151
152         if (!g_manage_raw_queue)
153                 return;
154
155         req = (thumbRawReq *)g_queue_pop_head(g_manage_raw_queue);
156         if (req != NULL) {
157                 GSource *source_id = g_main_context_find_source_by_id(g_main_context_get_thread_default(), req->source_id);
158                 sock = g_io_channel_unix_get_fd(req->channel);
159
160                 g_io_channel_shutdown(req->channel, TRUE, NULL);
161                 g_io_channel_unref(req->channel);
162                 close(sock);
163                 if (source_id) {
164                         g_source_destroy(source_id);
165                 } else {
166                         thumb_err("G_SOURCE_ID is NULL");
167                 }
168
169                 SAFE_FREE(req->path);
170                 SAFE_FREE(req->userData);
171                 SAFE_FREE(req);
172         }
173
174         /* Check manage queue */
175         len = g_queue_get_length(g_manage_raw_queue);
176         if (len > 0)
177                 __media_thumb_raw_data_send_request();
178 }
179
180 static int __media_thumb_cancel_raw_data(int request_id)
181 {
182         int len = 0, i;
183
184         thumb_retv_if(!g_manage_raw_queue, MS_MEDIA_ERR_NONE);
185
186         len = g_queue_get_length(g_manage_raw_queue);
187
188         for (i = 0; i < len; i++) {
189                 thumbRawReq *req = NULL;
190                 req = (thumbRawReq *)g_queue_peek_nth(g_manage_raw_queue, i);
191                 if (req == NULL) continue;
192
193                 if (req->request_id == request_id) {
194                         if (req->isRequested) {
195                                 req->isCanceled = true;
196                         } else {
197                                 g_queue_pop_nth(g_manage_raw_queue, i);
198
199                                 SAFE_FREE(req->path);
200                                 SAFE_FREE(req->userData);
201                                 SAFE_FREE(req);
202                         }
203
204                         return MS_MEDIA_ERR_NONE;
205                 }
206         }
207
208         return MS_MEDIA_ERR_INTERNAL;
209 }
210
211 static bool __media_thumb_check_cancel(void)
212 {
213         thumbReq *req = NULL;
214         req = (thumbReq *)g_queue_peek_head(g_manage_queue);
215
216         if (!req)
217                 return false;
218
219         if (req->isCanceled)
220                 return false;
221         else
222                 return true;
223 }
224
225 static bool __media_thumb_check_cancel_for_raw(void)
226 {
227         thumbRawReq *req = NULL;
228         req = (thumbRawReq *)g_queue_peek_head(g_manage_raw_queue);
229
230         if (!req)
231                 return false;
232
233         if (req->isCanceled)
234                 return false;
235         else
236                 return true;
237 }
238
239 int _media_thumb_recv_msg(int sock, int header_size, thumbMsg *msg)
240 {
241         int remain_size = 0;
242         int recv_len = 0;
243         int recv_pos = 0;
244         unsigned char *buf = NULL;
245
246         THUMB_MALLOC(buf, header_size);
247         if (buf == NULL) {
248                 thumb_err("memory allocation failed");
249                 SAFE_FREE(buf);
250                 return MS_MEDIA_ERR_OUT_OF_MEMORY;
251         }
252
253         while (header_size > 0) {
254                 if ((recv_len = recv(sock, buf + recv_pos, header_size, 0)) < 0) {
255                         thumb_stderror("recv failed");
256                         SAFE_FREE(buf);
257                         return __media_thumb_get_error();
258                 }
259                 header_size -= recv_len;
260                 recv_pos += recv_len;
261         }
262
263         header_size = recv_pos;
264         recv_pos = 0;
265
266         memcpy(msg, buf, header_size);
267         SAFE_FREE(buf);
268
269         if (strlen(msg->org_path) == 0 || strlen(msg->org_path) >= MAX_FILEPATH_LEN) {
270                 thumb_err("org_path size is invalid %zu", strlen(msg->org_path));
271                 return MS_MEDIA_ERR_SOCKET_RECEIVE;
272         }
273
274         /* it can be empty string */
275         if (strlen(msg->dst_path) >= MAX_FILEPATH_LEN) {
276                 thumb_err("dst_path size is invalid %zu", strlen(msg->dst_path));
277                 return MS_MEDIA_ERR_SOCKET_RECEIVE;
278         }
279
280         if (msg->thumb_size < 0) {
281                 thumb_err("recv data is wrong");
282                 return MS_MEDIA_ERR_SOCKET_RECEIVE;
283         }
284
285         if (msg->thumb_size > 0) {
286                 remain_size = msg->thumb_size;
287                 THUMB_MALLOC(buf, remain_size);
288                 thumb_retv_if(!buf, MS_MEDIA_ERR_OUT_OF_MEMORY);
289
290                 while (remain_size > 0) {
291                         if ((recv_len = recv(sock, buf + recv_pos, remain_size, 0)) < 0) {
292                                 thumb_stderror("recv failed");
293                                 SAFE_FREE(buf);
294                                 return __media_thumb_get_error();
295                         }
296
297                         fsync(sock);
298                         remain_size -= recv_len;
299                         recv_pos += recv_len;
300                 }
301
302                 SAFE_FREE(msg->thumb_data);
303                 THUMB_MALLOC(msg->thumb_data, msg->thumb_size);
304                 if (msg->thumb_data != NULL) {
305                         memcpy(msg->thumb_data, buf, msg->thumb_size);
306                 } else {
307                         SAFE_FREE(buf);
308
309                         return MS_MEDIA_ERR_OUT_OF_MEMORY;
310                 }
311         }
312
313         SAFE_FREE(buf);
314
315         return MS_MEDIA_ERR_NONE;
316 }
317
318 int _media_thumb_set_buffer(thumbMsg *req_msg, unsigned char **buf, int *buf_size)
319 {
320         if (req_msg == NULL || buf == NULL)
321                 return MS_MEDIA_ERR_INVALID_PARAMETER;
322
323         int thumb_data_len = 0;
324         int size = 0;
325         int header_size = 0;
326
327         header_size = sizeof(thumbMsg) - sizeof(unsigned char *);
328         thumb_data_len = req_msg->thumb_size;
329         if (thumb_data_len < 0)
330                 return MS_MEDIA_ERR_INVALID_PARAMETER;
331
332         //thumb_dbg("Basic Size[%d] org_path[%s] dst_path[%s] thumb_data_len[%d]", header_size, req_msg->org_path, req_msg->dst_path, thumb_data_len);
333
334         size = header_size + thumb_data_len;
335         THUMB_MALLOC(*buf, size);
336         if (*buf == NULL) {
337                 *buf_size = 0;
338                 return 0;
339         }
340         memcpy(*buf, req_msg, header_size);
341         if (thumb_data_len > 0)
342                 memcpy((*buf) + header_size, req_msg->thumb_data, thumb_data_len);
343
344         *buf_size = size;
345
346         return MS_MEDIA_ERR_NONE;
347 }
348
349 gboolean _media_thumb_write_socket(GIOChannel *src, GIOCondition condition, gpointer data)
350 {
351         thumbMsg recv_msg;
352         int header_size = 0;
353         int sock = 0;
354         int err = MS_MEDIA_ERR_NONE;
355
356         memset((void *)&recv_msg, 0, sizeof(thumbMsg));
357         sock = g_io_channel_unix_get_fd(src);
358
359         header_size = sizeof(thumbMsg) - sizeof(unsigned char *);
360
361         thumb_err("_media_thumb_write_socket socket : %d", sock);
362
363         if ((err = _media_thumb_recv_msg(sock, header_size, &recv_msg)) < 0) {
364                 thumb_err("_media_thumb_recv_msg failed ");
365                 __media_thumb_pop();
366
367                 return G_SOURCE_REMOVE;
368         }
369
370         if (recv_msg.status != MS_MEDIA_ERR_NONE) {
371                 err = recv_msg.status;
372                 thumb_err("Failed to make thumbnail (%d)", err);
373         }
374
375         if (__media_thumb_check_cancel()) {
376                 if (data) {
377                         thumbUserData* cb = (thumbUserData*)data;
378                         if (cb->func != NULL)
379                                 cb->func(err, recv_msg.dst_path, cb->user_data);
380                 }
381         }
382
383         __media_thumb_pop();
384
385         thumb_dbg("Done");
386
387         return G_SOURCE_REMOVE;
388 }
389
390 gboolean _media_thumb_raw_data_write_socket(GIOChannel *src, GIOCondition condition, gpointer data)
391 {
392         thumbMsg recv_msg;
393         int header_size = 0;
394         int sock = 0;
395         int err = MS_MEDIA_ERR_NONE;
396
397         memset((void *)&recv_msg, 0, sizeof(thumbMsg));
398         sock = g_io_channel_unix_get_fd(src);
399
400         header_size = sizeof(thumbMsg) - sizeof(unsigned char *);
401
402         thumb_err("_media_thumb_write_socket socket : %d", sock);
403
404         if ((err = _media_thumb_recv_msg(sock, header_size, &recv_msg)) < 0) {
405                 thumb_err("_media_thumb_recv_msg failed ");
406                 __media_thumb_pop_raw_data();
407
408                 return G_SOURCE_REMOVE;
409         }
410
411         if (recv_msg.status != MS_MEDIA_ERR_NONE) {
412                 err = recv_msg.status;
413                 thumb_err("Failed to make thumbnail (%d)", err);
414         }
415
416         if (__media_thumb_check_cancel_for_raw()) {
417                 if (data) {
418                         thumbRawUserData* cb = (thumbRawUserData*)data;
419                         if (cb->func != NULL)
420                                 cb->func(err, recv_msg.request_id, recv_msg.org_path, recv_msg.thumb_width, recv_msg.thumb_height, recv_msg.thumb_data, recv_msg.thumb_size, cb->user_data);
421                 }
422         }
423
424         __media_thumb_pop_raw_data();
425
426         thumb_dbg("Done");
427
428         return G_SOURCE_REMOVE;
429 }
430
431 static int __media_thumb_send_request(void)
432 {
433         int err = MS_MEDIA_ERR_NONE;
434         int sock = -1;
435         struct sockaddr_un serv_addr;
436         thumbReq *req_manager = NULL;
437         int pid;
438
439         err = ms_ipc_create_client_socket(MS_TIMEOUT_SEC_10, &sock);
440         thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "ms_ipc_create_client_socket failed");
441
442         memset(&serv_addr, 0, sizeof(serv_addr));
443         serv_addr.sun_family = AF_UNIX;
444         SAFE_STRLCPY(serv_addr.sun_path, THUMB_IPC_PATH, sizeof(serv_addr.sun_path));
445
446         GIOChannel *channel = NULL;
447         channel = g_io_channel_unix_new(sock);
448         int source_id = -1;
449
450         /* Connecting to the thumbnail server */
451         if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
452                 thumb_stderror("connect");
453                 if (errno == EACCES)
454                         err = MS_MEDIA_ERR_PERMISSION_DENIED;
455                 else
456                         err = MS_MEDIA_ERR_SOCKET_CONN;
457
458                 g_io_channel_shutdown(channel, TRUE, NULL);
459                 g_io_channel_unref(channel);
460                 close(sock);
461
462                 return err;
463         }
464
465         req_manager = (thumbReq *)g_queue_peek_head(g_manage_queue);
466
467         if (req_manager == NULL) {
468                 thumb_err("queue peek fail");
469                 g_io_channel_shutdown(channel, TRUE, NULL);
470                 g_io_channel_unref(channel);
471                 close(sock);
472                 return MS_MEDIA_ERR_INVALID_PARAMETER;
473         }
474
475         GSource *source = NULL;
476         source = g_io_create_watch(channel, G_IO_IN);
477         g_source_set_callback(source, (GSourceFunc)_media_thumb_write_socket, req_manager->userData, NULL);
478         source_id = g_source_attach(source, g_main_context_get_thread_default());
479
480         thumbMsg req_msg;
481         memset((void *)&req_msg, 0, sizeof(thumbMsg));
482
483         pid = getpid();
484         req_msg.pid = pid;
485         req_msg.msg_type = req_manager->msg_type;
486         req_msg.request_id = 0;
487         req_msg.uid = req_manager->uid;
488         SAFE_STRLCPY(req_msg.org_path, req_manager->path, sizeof(req_msg.org_path));
489         req_msg.dst_path[0] = '\0';
490         req_msg.thumb_size = 0;
491
492         unsigned char *buf = NULL;
493         int buf_size = 0;
494         _media_thumb_set_buffer(&req_msg, &buf, &buf_size);
495
496         if (send(sock, buf, buf_size, 0) < 0) {
497                 thumb_err("send failed: %d", errno);
498                 SAFE_FREE(buf);
499                 g_source_destroy(g_main_context_find_source_by_id(g_main_context_get_thread_default(), source_id));
500                 g_io_channel_shutdown(channel, TRUE, NULL);
501                 g_io_channel_unref(channel);
502                 close(sock);
503                 return MS_MEDIA_ERR_SOCKET_SEND;
504         }
505
506         SAFE_FREE(buf);
507         thumb_dbg("Sending msg to thumbnail daemon is successful");
508
509         if (req_manager->msg_type == THUMB_REQUEST_DB_INSERT) {
510                 req_manager->channel = channel;
511                 req_manager->source_id = source_id;
512                 req_manager->isRequested = true;
513         }
514
515         return err;
516 }
517
518 static int __media_thumb_raw_data_send_request(void)
519 {
520         int err = MS_MEDIA_ERR_NONE;
521         int sock = -1;
522         struct sockaddr_un serv_addr;
523         thumbRawReq *req_manager = NULL;
524         int pid;
525
526         err = ms_ipc_create_client_socket(MS_TIMEOUT_SEC_10, &sock);
527         thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "ms_ipc_create_client_socket failed");
528
529         memset(&serv_addr, 0, sizeof(serv_addr));
530         serv_addr.sun_family = AF_UNIX;
531         SAFE_STRLCPY(serv_addr.sun_path, THUMB_IPC_PATH, sizeof(serv_addr.sun_path));
532
533         GIOChannel *channel = NULL;
534         channel = g_io_channel_unix_new(sock);
535         int source_id = -1;
536
537         /* Connecting to the thumbnail server */
538         if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
539                 thumb_stderror("connect error");
540                 if (errno == EACCES)
541                         err = MS_MEDIA_ERR_PERMISSION_DENIED;
542                 else
543                         err = MS_MEDIA_ERR_SOCKET_CONN;
544
545                 g_io_channel_shutdown(channel, TRUE, NULL);
546                 g_io_channel_unref(channel);
547                 close(sock);
548                 return err;
549         }
550
551         req_manager = (thumbRawReq *)g_queue_peek_head(g_manage_raw_queue);
552
553         if (req_manager == NULL) {
554                 thumb_err("queue peek fail");
555                 g_io_channel_shutdown(channel, TRUE, NULL);
556                 g_io_channel_unref(channel);
557                 close(sock);
558                 return MS_MEDIA_ERR_INVALID_PARAMETER;
559         }
560
561         GSource *source = NULL;
562         source = g_io_create_watch(channel, G_IO_IN);
563         g_source_set_callback(source, (GSourceFunc)_media_thumb_raw_data_write_socket, req_manager->userData, NULL);
564         source_id = g_source_attach(source, g_main_context_get_thread_default());
565
566         thumbMsg req_msg;
567         memset((void *)&req_msg, 0, sizeof(thumbMsg));
568
569         pid = getpid();
570         req_msg.pid = pid;
571         req_msg.msg_type = req_manager->msg_type;
572         req_msg.request_id = req_manager->request_id;
573         req_msg.thumb_width = req_manager->width;
574         req_msg.thumb_height = req_manager->height;
575         req_msg.uid = req_manager->uid;
576
577         SAFE_STRLCPY(req_msg.org_path, req_manager->path, sizeof(req_msg.org_path));
578         req_msg.dst_path[0] = '\0';
579         req_msg.thumb_size = 0;
580
581         unsigned char *buf = NULL;
582         int buf_size = 0;
583         _media_thumb_set_buffer(&req_msg, &buf, &buf_size);
584
585         if (send(sock, buf, buf_size, 0) < 0) {
586                 thumb_err("send failed: %d", errno);
587                 SAFE_FREE(buf);
588                 g_source_destroy(g_main_context_find_source_by_id(g_main_context_get_thread_default(), source_id));
589                 g_io_channel_shutdown(channel, TRUE, NULL);
590                 g_io_channel_unref(channel);
591                 return MS_MEDIA_ERR_SOCKET_SEND;
592         }
593
594         SAFE_FREE(buf);
595
596         if (req_manager->msg_type == THUMB_REQUEST_RAW_DATA) {
597                 req_manager->channel = channel;
598                 req_manager->source_id = source_id;
599                 req_manager->isRequested = true;
600         }
601         return MS_MEDIA_ERR_NONE;
602 }
603
604 int _media_thumb_request_async(int msg_type, unsigned int request_id, const char *origin_path, thumbUserData *userData, uid_t uid)
605 {
606         int err = MS_MEDIA_ERR_NONE;
607         int len = 0;
608
609         if (msg_type == THUMB_REQUEST_CANCEL_MEDIA)
610                 return __media_thumb_cancel(request_id);
611
612         if (g_manage_queue == NULL)
613                 g_manage_queue = g_queue_new();
614
615         thumbReq *thumb_req = NULL;
616         THUMB_MALLOC(thumb_req, sizeof(thumbReq));
617         thumb_retvm_if(thumb_req == NULL, MS_MEDIA_ERR_INVALID_PARAMETER, "Failed to create request element");
618
619         thumb_req->msg_type = msg_type;
620         thumb_req->path = g_strdup(origin_path);
621         thumb_req->userData = userData;
622         thumb_req->isCanceled = false;
623         thumb_req->isRequested = false;
624         thumb_req->request_id = request_id;
625         thumb_req->uid = uid;
626
627         len = g_queue_get_length(g_manage_queue);
628         g_queue_push_tail(g_manage_queue, (gpointer)thumb_req);
629
630         if (len == 0)
631                 err = __media_thumb_send_request();
632
633         return err;
634 }
635
636 int _media_thumb_request_raw_data_async(int msg_type, int request_id, const char *origin_path, int width, int height, thumbRawUserData *userData, uid_t uid)
637 {
638         int err = MS_MEDIA_ERR_NONE;
639         int len = 0;
640         thumbRawReq *thumb_req = NULL;
641
642         if (msg_type == THUMB_REQUEST_CANCEL_RAW_DATA)
643                 return __media_thumb_cancel_raw_data(request_id);
644
645         if (g_manage_raw_queue == NULL)
646                 g_manage_raw_queue = g_queue_new();
647
648         THUMB_MALLOC(thumb_req, sizeof(thumbRawReq));
649         if (thumb_req == NULL) {
650                 thumb_err("Failed to create request element");
651                 return MS_MEDIA_ERR_INVALID_PARAMETER;
652         }
653
654         thumb_req->msg_type = msg_type;
655         thumb_req->request_id = request_id;
656         thumb_req->path = g_strdup(origin_path);
657         thumb_req->width = width;
658         thumb_req->height = height;
659         thumb_req->userData = userData;
660         thumb_req->isCanceled = false;
661         thumb_req->isRequested = false;
662         thumb_req->uid = uid;
663
664         len = g_queue_get_length(g_manage_raw_queue);
665         g_queue_push_tail(g_manage_raw_queue, (gpointer)thumb_req);
666
667         if (len == 0)
668                 err = __media_thumb_raw_data_send_request();
669
670         return err;
671 }