Modify DCM message structure and so on
[platform/core/multimedia/media-server.git] / lib / media-util-dcm.c
1 /*
2  * Media Utility for DCM
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Ji Yong Min <jiyong.min@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 <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <glib.h>
26 #include <unistd.h>
27 #include <media-server-ipc.h>
28 #include <media-util.h>
29 #include <media-util-internal.h>
30 #include <media-util-dbg.h>
31 #include <media-util-dcm.h>
32 #include <media-util-err.h>
33 #include <media-util-ipc.h>
34 #include <tzplatform_config.h>
35
36 #define DCM_MSG_MAX_SIZE 4096
37
38 static GQueue *g_request_queue = NULL;
39 static GQueue *g_manage_queue = NULL;
40
41 typedef struct {
42         FaceFunc func;
43         void *user_data;
44 } faceUserData;
45
46 typedef struct {
47         GIOChannel *channel;
48         int msg_type;
49         gboolean isCanceled;
50         int request_id;
51         int source_id;
52         uid_t uid;
53         char *path;
54         faceUserData *userData;
55 } dcmReq;
56
57 typedef enum
58 {
59         DCM_PHONE,                      /**< Stored only in phone */
60         DCM_MMC                         /**< Stored only in MMC */
61 } media_dcm_store_type;
62
63 extern char MEDIA_IPC_PATH[][70];
64
65 int __media_dcm_check_req_queue(const char *path);
66 int __media_dcm_pop_manage_queue(const unsigned int request_id, const char *path);
67 int _media_dcm_send_request();
68
69 gboolean __media_dcm_check_cancel(void)
70 {
71         dcmReq *req = NULL;
72         req = (dcmReq *)g_queue_peek_head(g_request_queue);
73
74         if (req == NULL) {
75                 return FALSE;
76         } else {
77                 if (req->isCanceled)
78                         return FALSE;
79                 else
80                         return TRUE;
81         }
82 }
83
84 void __media_dcm_shutdown_channel(gboolean only_shutdown)
85 {
86         int len = -1;
87         dcmReq *req = (dcmReq *)g_queue_peek_head(g_request_queue);
88
89         len = g_queue_get_length(g_manage_queue);
90
91         if (req != NULL) {
92                 if (!only_shutdown) {
93                         if (len == 0 && req->isCanceled == TRUE) {
94                                 MSAPI_DBG("The manage queue will be released");
95                         } else {
96                                 MSAPI_DBG("There is remain item in the manage queue");
97                                 return;
98                         }
99                 }
100                 GSource *source_id = g_main_context_find_source_by_id(g_main_context_get_thread_default(), req->source_id);
101                 if (source_id != NULL) {
102                         g_source_destroy(source_id);
103                 } else {
104                         MSAPI_DBG_ERR("G_SOURCE_ID is NULL");
105                 }
106
107                 g_io_channel_shutdown(req->channel, TRUE, NULL);
108                 g_io_channel_unref(req->channel);
109                 g_queue_pop_head(g_request_queue);
110
111                 MS_SAFE_FREE(req->path);
112                 MS_SAFE_FREE(req->userData);
113                 MS_SAFE_FREE(req);
114
115                 if(g_manage_queue && len == 0) {
116                         g_queue_free(g_manage_queue);
117                         g_manage_queue = NULL;
118                 }
119         }
120 }
121
122 int __media_dcm_pop_req_queue(const char *path)
123 {
124         int req_len = 0;
125
126         req_len = g_queue_get_length(g_request_queue);
127
128         if (req_len <= 0) {
129                 MSAPI_DBG("There is no request in the queue");
130         } else {
131                 __media_dcm_shutdown_channel(TRUE);
132         }
133
134         /* Check manage queue */
135         if(g_manage_queue) {
136                 req_len = g_queue_get_length(g_manage_queue);
137
138                 if(req_len > 0)
139                         _media_dcm_send_request();
140         }
141
142         return MS_MEDIA_ERR_NONE;
143 }
144
145 int __media_dcm_check_req_queue_for_cancel(unsigned int request_id, const char *path)
146 {
147         int req_len = 0;
148
149         req_len = g_queue_get_length(g_request_queue);
150
151         if (req_len <= 0) {
152                 MSAPI_DBG("There is no request in the queue");
153         } else {
154                 dcmReq *req = NULL;
155                 req = (dcmReq *)g_queue_peek_head(g_request_queue);
156
157                 if (req != NULL && strncmp(path, req->path, strlen(path)) == 0 && request_id == req->request_id) {
158                         req->isCanceled = true;
159                         __media_dcm_shutdown_channel(false);
160
161                         return MS_MEDIA_ERR_NONE;
162                 }
163         }
164
165         return MS_MEDIA_ERR_INTERNAL;
166 }
167
168 gboolean __media_dcm_write_socket(GIOChannel *src, GIOCondition condition, gpointer data)
169 {
170         dcmMsg recv_msg;
171         int sock = 0;
172         int err = MS_MEDIA_ERR_NONE;
173
174         memset((void *)&recv_msg, 0, sizeof(dcmMsg));
175         sock = g_io_channel_unix_get_fd(src);
176
177         MSAPI_DBG("__media_dcm_write_socket socket : %d", sock);
178
179         if ((err = recv(sock, &recv_msg, sizeof(dcmMsg), 0)) < 0) {
180                 MSAPI_DBG_STRERROR("recv failed ");
181                 if (recv_msg.msg_size > 0) {
182                         __media_dcm_pop_req_queue(recv_msg.msg);
183                 } else {
184                         MSAPI_DBG_ERR("origin path size is wrong.");
185                 }
186
187                 return FALSE;
188         }
189
190         MSAPI_DBG("Completed.. %d, %s, %d", recv_msg.msg_type, recv_msg.msg, recv_msg.result);
191
192         if (__media_dcm_check_cancel()) {
193                 MSAPI_DBG_ERR("__media_dcm_check_cancel is true");
194                 if (data) {
195                         faceUserData* cb = (faceUserData*)data;
196                         if (cb->func != NULL) {
197                                 cb->func(recv_msg.msg_type, (int)(recv_msg.result), cb->user_data);
198                         }
199                 }
200         }
201
202         __media_dcm_pop_req_queue(recv_msg.msg);
203
204         MSAPI_DBG("Done");
205
206         return FALSE;
207 }
208
209 int __media_dcm_check_req_queue(const char *path)
210 {
211         int req_len = 0, i;
212
213         req_len = g_queue_get_length(g_request_queue);
214
215         MSAPI_DBG("Queue length : %d", req_len);
216         MSAPI_DBG("Queue path : %s", path);
217
218         if (req_len <= 0) {
219                 MSAPI_DBG("There is no request in the queue");
220         } else {
221
222                 for (i = 0; i < req_len; i++) {
223                         dcmReq *req = NULL;
224                         req = (dcmReq *)g_queue_peek_nth(g_request_queue, i);
225                         if (req == NULL) continue;
226
227                         if (strncmp(path, req->path, strlen(path)) == 0) {
228                                 MSAPI_DBG("Same Request - %s", path);
229                                 return MS_MEDIA_ERR_INVALID_PARAMETER;
230                         }
231                 }
232         }
233
234         return MS_MEDIA_ERR_NONE;
235 }
236
237 int __media_dcm_pop_manage_queue(const unsigned int request_id, const char *path)
238 {
239         int req_len = 0, i;
240         gboolean flag = FALSE;
241
242         req_len = g_queue_get_length(g_manage_queue);
243
244         if (req_len < 0) {
245                 MSAPI_DBG("There is no request in the queue");
246         } else {
247                 for (i = 0; i < req_len; i++) {
248                         dcmReq *req = NULL;
249                         req = (dcmReq *)g_queue_peek_nth(g_manage_queue, i);
250                         if (req == NULL) continue;
251
252                         if (strncmp(path, req->path, strlen(path)) == 0) {
253                                 g_queue_pop_nth(g_manage_queue, i);
254
255                                 MS_SAFE_FREE(req->path);
256                                 MS_SAFE_FREE(req->userData);
257                                 MS_SAFE_FREE(req);
258                                 flag = TRUE;
259                                 break;
260                         }
261                 }
262                 if (!flag) {
263                         return __media_dcm_check_req_queue_for_cancel(request_id, path);
264                 } else {
265                         __media_dcm_shutdown_channel(FALSE);
266
267                         return MS_MEDIA_ERR_NONE;
268                 }
269         }
270
271         return MS_MEDIA_ERR_NONE;
272 }
273
274 int __media_dcm_get_store_type_by_path(const char *full_path)
275 {
276         if (full_path != NULL && MEDIA_ROOT_PATH_INTERNAL != NULL && MEDIA_ROOT_PATH_SDCARD != NULL) {
277                 if (strncmp(full_path, MEDIA_ROOT_PATH_INTERNAL, strlen(MEDIA_ROOT_PATH_INTERNAL)) == 0) {
278                         return DCM_PHONE;
279                 } else if (strncmp(full_path, MEDIA_ROOT_PATH_SDCARD, strlen(MEDIA_ROOT_PATH_SDCARD)) == 0) {
280                         return DCM_MMC;
281                 }
282         }
283
284         return -1;
285 }
286
287 int _media_dcm_send_request()
288 {
289         int err = MS_MEDIA_ERR_NONE;
290         int sock = -1;
291         struct sockaddr_un serv_addr;
292         ms_sock_info_s sock_info;
293         dcmReq *req_manager = NULL;
294         sock_info.port = MS_DCM_CREATOR_PORT;
295
296         MSAPI_DBG("_media_dcm_send_request start");
297
298         err = ms_ipc_create_client_socket(MS_PROTOCOL_TCP, MS_TIMEOUT_SEC_60, &sock_info);
299         if (err != MS_MEDIA_ERR_NONE) {
300                 MSAPI_DBG_ERR("ms_ipc_create_client_socket failed");
301                 return err;
302         }
303
304         memset(&serv_addr, 0, sizeof(serv_addr));
305         sock = sock_info.sock_fd;
306         serv_addr.sun_family = AF_UNIX;
307         strncpy(serv_addr.sun_path, tzplatform_mkpath(TZ_SYS_RUN, MEDIA_IPC_PATH[sock_info.port]), strlen(tzplatform_mkpath(TZ_SYS_RUN, MEDIA_IPC_PATH[sock_info.port])));
308
309         GIOChannel *channel = NULL;
310         channel = g_io_channel_unix_new(sock);
311         int source_id = -1;
312
313         /* Connecting to the dcm service */
314         if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
315                 MSAPI_DBG_STRERROR("connect");
316                 g_io_channel_shutdown(channel, TRUE, NULL);
317                 g_io_channel_unref(channel);
318                 ms_ipc_delete_client_socket(&sock_info);
319                 return MS_MEDIA_ERR_SOCKET_CONN;
320         }
321
322         req_manager = (dcmReq *)g_queue_pop_head(g_manage_queue);
323
324         if (req_manager == NULL) {
325                 MSAPI_DBG_ERR("queue pop fail");
326                 g_io_channel_shutdown(channel, TRUE, NULL);
327                 g_io_channel_unref(channel);
328                 ms_ipc_delete_client_socket(&sock_info);
329                 return MS_MEDIA_ERR_INVALID_PARAMETER;
330         }
331
332         GSource *source = NULL;
333         source = g_io_create_watch(channel, G_IO_IN);
334         g_source_set_callback(source, (GSourceFunc)__media_dcm_write_socket, req_manager->userData, NULL);
335         source_id = g_source_attach(source, g_main_context_get_thread_default());
336
337         dcmMsg req_msg;
338
339         memset((void *)&req_msg, 0, sizeof(dcmMsg));
340
341         req_msg.pid = getpid();
342         req_msg.msg_type = req_manager->msg_type;
343         req_msg.uid = req_manager->uid;
344         strncpy(req_msg.msg, req_manager->path, sizeof(req_msg.msg));
345         req_msg.msg[strlen(req_msg.msg)] = '\0';
346         req_msg.msg_size = strlen(req_msg.msg) + 1;
347
348         if (send(sock, &req_msg, sizeof(req_msg), 0) != sizeof(req_msg)) {
349                 MSAPI_DBG_STRERROR("send failed");
350
351                 g_source_destroy(g_main_context_find_source_by_id(g_main_context_get_thread_default(), source_id));
352                 g_io_channel_shutdown(channel, TRUE, NULL);
353                 g_io_channel_unref(channel);
354                 ms_ipc_delete_client_socket(&sock_info);
355                 return MS_MEDIA_ERR_SOCKET_SEND;
356         }
357
358         MSAPI_DBG("Sending msg to dcm service is successful");
359
360
361         if (req_manager->msg_type == DCM_REQUEST_MEDIA/*DCM_REQUEST_INSERT_FACE*/) {
362                 if (g_request_queue == NULL) {
363                         g_request_queue = g_queue_new();
364                 }
365
366                 dcmReq *dcm_req = calloc(1, sizeof(dcmReq));
367                 if (dcm_req == NULL) {
368                         MSAPI_DBG_ERR("Failed to create request element");
369                         return MS_MEDIA_ERR_INVALID_PARAMETER;
370                 }
371
372                 dcm_req->channel = channel;
373                 dcm_req->path = strdup(req_manager->path);
374                 dcm_req->source_id = source_id;
375                 dcm_req->userData = req_manager->userData;
376
377                 g_queue_push_tail(g_request_queue, (gpointer)dcm_req);
378         }
379
380         return err;
381 }
382
383 int _media_dcm_request(int msg_type, const char *path, uid_t uid)
384 {
385         int sock = -1;
386         struct sockaddr_un serv_addr;
387         ms_sock_info_s sock_info;
388         int err = MS_MEDIA_ERR_NONE;
389         int pid;
390         sock_info.port = MS_DCM_CREATOR_PORT;
391
392         err = ms_ipc_create_client_socket(MS_PROTOCOL_TCP, MS_TIMEOUT_SEC_60, &sock_info);
393         if (err != MS_MEDIA_ERR_NONE) {
394                 MSAPI_DBG_ERR("ms_ipc_create_client_socket failed");
395                 return err;
396         }
397
398         memset(&serv_addr, 0, sizeof(serv_addr));
399         sock = sock_info.sock_fd;
400         serv_addr.sun_family = AF_UNIX;
401         strncpy(serv_addr.sun_path, tzplatform_mkpath(TZ_SYS_RUN, MEDIA_IPC_PATH[sock_info.port]), strlen(tzplatform_mkpath(TZ_SYS_RUN, MEDIA_IPC_PATH[sock_info.port])));
402
403         /* Connecting to the dcm service */
404         if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
405                 MSAPI_DBG_STRERROR("connect");
406                 ms_ipc_delete_client_socket(&sock_info);
407                 return MS_MEDIA_ERR_SOCKET_CONN;
408         }
409
410         dcmMsg req_msg;
411         dcmMsg recv_msg;
412
413         memset((void *)&req_msg, 0, sizeof(dcmMsg));
414         memset((void *)&recv_msg, 0, sizeof(dcmMsg));
415
416         /* Get PID of client*/
417         pid = getpid();
418         req_msg.pid = pid;
419
420         /* Set requset message */
421         req_msg.msg_type = msg_type;
422         req_msg.uid = uid;
423         if (path != NULL) {
424                 req_msg.msg_size = strlen(path);
425                 memcpy(req_msg.msg, path, strlen(path));
426                 req_msg.msg[strlen(path)+1] = '\0';
427         }
428
429         if (req_msg.msg_size > DCM_MSG_MAX_SIZE) {
430                 MSAPI_DBG_ERR("path's length exceeds %d", DCM_MSG_MAX_SIZE);
431                 ms_ipc_delete_client_socket(&sock_info);
432                 return MS_MEDIA_ERR_INVALID_PARAMETER;
433         }
434
435         if (send(sock, &req_msg, sizeof(dcmMsg), 0) != sizeof(dcmMsg)) {
436                 MSAPI_DBG_STRERROR("sendto failed");
437                 ms_ipc_delete_client_socket(&sock_info);
438                 return MS_MEDIA_ERR_SOCKET_SEND;
439         }
440
441         MSAPI_DBG("Sending msg to dcm service is successful");
442
443         if ((err = recv(sock, &recv_msg, sizeof(dcmMsg), 0)) < 0) {
444                 MSAPI_DBG_ERR("recv failed ");
445                 ms_ipc_delete_client_socket(&sock_info);
446                 return MS_MEDIA_ERR_SOCKET_RECEIVE;
447         }
448
449         MSAPI_DBG("recv %d from dcm service is successful", recv_msg.msg_type);
450
451         ms_ipc_delete_client_socket(&sock_info);
452
453         return MS_MEDIA_ERR_NONE;
454 }
455
456 int _media_dcm_request_async(int msg_type, const unsigned int request_id, const char *path, faceUserData *userData, uid_t uid)
457 {
458         int err = MS_MEDIA_ERR_NONE;
459
460         MSAPI_DBG("Path : %s", path);
461
462         if (g_manage_queue == NULL) {
463                 MSAPI_DBG("g_manage_queue is NULL");
464                 if (msg_type == DCM_REQUEST_CANCEL_FACE)
465                         return MS_MEDIA_ERR_INTERNAL;
466
467                 g_manage_queue = g_queue_new();
468
469                 dcmReq *dcm_req = NULL;
470                 dcm_req = calloc(1, sizeof(dcmReq));
471                 if (dcm_req == NULL) {
472                         MSAPI_DBG_ERR("Failed to create request element");
473                         return MS_MEDIA_ERR_INVALID_PARAMETER;
474                 }
475
476                 dcm_req->msg_type = msg_type;
477                 dcm_req->path = strdup(path);
478                 dcm_req->userData = userData;
479                 dcm_req->isCanceled = FALSE;
480                 dcm_req->request_id = request_id;
481                 dcm_req->uid = uid;
482
483                 MSAPI_DBG("Enqueue");
484                 g_queue_push_tail(g_manage_queue, (gpointer)dcm_req);
485
486                 /* directly request at first time */
487                 err = _media_dcm_send_request();
488
489         } else {
490                 MSAPI_DBG("g_manage_queue is not NULL");
491                 if (msg_type != DCM_REQUEST_CANCEL_FACE) {
492                         /* Enqueue */
493                         dcmReq *dcm_req = NULL;
494                         dcm_req = calloc(1, sizeof(dcmReq));
495                         if (dcm_req == NULL) {
496                                 MSAPI_DBG_ERR("Failed to create request element");
497                                 return MS_MEDIA_ERR_INVALID_PARAMETER;
498                         }
499
500                         dcm_req->msg_type = msg_type;
501                         dcm_req->path = strdup(path);
502                         dcm_req->userData = userData;
503                         dcm_req->isCanceled = FALSE;
504                         dcm_req->request_id = request_id;
505                         dcm_req->uid = uid;
506
507                         MSAPI_DBG("Enqueue");
508                         g_queue_push_tail(g_manage_queue, (gpointer)dcm_req);
509                 } else {
510                         /* Dequeue */
511                         MSAPI_DBG("Dequeue");
512                         err = __media_dcm_pop_manage_queue(request_id, path);
513                 }
514         }
515
516         return err;
517 }
518
519 int dcm_request_extract_all(uid_t uid)
520 {
521         int err = MS_MEDIA_ERR_NONE;
522
523         /* Request for image file to the daemon "Dcm generator" */
524         err = _media_dcm_request(DCM_REQUEST_ALL_MEDIA, NULL, uid);
525         if (err != MS_MEDIA_ERR_NONE) {
526                 MSAPI_DBG_ERR("_media_dcm_request failed : %d", err);
527                 return err;
528         }
529
530         return MS_MEDIA_ERR_NONE;
531 }
532
533 int dcm_request_extract_media(const char *path, uid_t uid)
534 {
535         int err = MS_MEDIA_ERR_NONE;
536
537         /* Request for image file to the daemon "Dcm generator" */
538         err = _media_dcm_request(DCM_REQUEST_MEDIA, path, uid);
539         if (err != MS_MEDIA_ERR_NONE) {
540                 MSAPI_DBG_ERR("_media_dcm_request failed : %d", err);
541                 return err;
542         }
543
544         return MS_MEDIA_ERR_NONE;
545 }
546
547 int dcm_request_extract_face_async(const unsigned int request_id, const char *path, FaceFunc func, void *user_data, uid_t uid)
548 {
549         int err = MS_MEDIA_ERR_NONE;
550         int exist = -1;
551
552         if (path == NULL) {
553                 MSAPI_DBG_ERR("Invalid parameter");
554                 return MS_MEDIA_ERR_INVALID_PARAMETER;
555         }
556
557         exist = open(path, O_RDONLY);
558         if (exist < 0) {
559                 MSAPI_DBG_ERR("The path(%s) doesn't exist.", path);
560                 if (errno == EACCES || errno == EPERM)
561                         return  MS_MEDIA_ERR_PERMISSION_DENIED;
562                 else
563                         return MS_MEDIA_ERR_INVALID_PARAMETER;
564         }
565         close(exist);
566
567         MSAPI_DBG("Path : %s", path);
568
569         int store_type = -1;
570         store_type = __media_dcm_get_store_type_by_path(path);
571
572         if ((store_type != DCM_PHONE) && (store_type != DCM_MMC)) {
573                 MSAPI_DBG_ERR("The path(%s) is invalid", path);
574                 return MS_MEDIA_ERR_INVALID_PARAMETER;
575         }
576
577         MSAPI_DBG("Path : %s", path);
578
579         faceUserData *userData = (faceUserData*)malloc(sizeof(faceUserData));
580         if (userData == NULL) {
581                 MSAPI_DBG_ERR("memory allocation failed");
582                 return MS_MEDIA_ERR_OUT_OF_MEMORY;
583         }
584         userData->func = (FaceFunc)func;
585         userData->user_data = user_data;
586
587         /* Request for image file to the daemon "Dcm generator" */
588         err = _media_dcm_request_async(DCM_REQUEST_MEDIA/*DCM_REQUEST_INSERT_FACE*/, request_id, path, userData, uid);
589         if (err != MS_MEDIA_ERR_NONE) {
590                 MSAPI_DBG_ERR("_media_dcm_request failed : %d", err);
591                 return err;
592         }
593
594         return MS_MEDIA_ERR_NONE;
595 }
596
597 int dcm_request_cancel_face(const unsigned int request_id, const char *path)
598 {
599         int err = MS_MEDIA_ERR_NONE;
600
601         /* Request for image file to the daemon "Dcm generator" */
602         err = _media_dcm_request_async(DCM_REQUEST_CANCEL_FACE, request_id, path, NULL, request_id);
603         if (err != MS_MEDIA_ERR_NONE) {
604                 MSAPI_DBG_ERR("_media_dcm_request failed : %d", err);
605                 return err;
606         }
607
608         return MS_MEDIA_ERR_NONE;
609 }
610