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