Tizen 2.1 base
[framework/multimedia/media-server.git] / lib / media-util-register.c
1 /*
2  *  Media Utility
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Yong Yeon Kim <yy9875.kim@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 /**
23  * This file defines api utilities of contents manager engines.
24  *
25  * @file                media-util-register.c
26  * @author      Yong Yeon Kim(yy9875.kim@samsung.com)
27  * @version     1.0
28  * @brief
29  */
30 #include <errno.h>
31 #include <unistd.h>
32 #include <arpa/inet.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <sys/socket.h>
37 #include <sys/syscall.h>
38 #include <string.h>
39 #include <stdbool.h>
40 #include <dirent.h>
41 #include <vconf.h>
42
43 #include "media-server-ipc.h"
44 #include "media-util-internal.h"
45 #include "media-util-dbg.h"
46 #include "media-util.h"
47
48 typedef struct media_callback_data{
49         GSource *source;
50         scan_complete_cb user_callback;
51         void *user_data;
52 } media_callback_data;
53
54 static bool _is_valid_path(const char *path)
55 {
56        if (path == NULL)
57                return false;
58
59         if (strncmp(path, MEDIA_ROOT_PATH_INTERNAL, strlen(MEDIA_ROOT_PATH_INTERNAL)) == 0) {
60                 return true;
61         } else if (strncmp(path, MEDIA_ROOT_PATH_SDCARD, strlen(MEDIA_ROOT_PATH_SDCARD)) == 0) {
62                 return true;
63         } else
64                 return false;
65
66        return true;
67 }
68
69 static int _check_dir_path(const char *dir_path)
70 {
71         struct stat sb;
72         DIR *dp = NULL;
73
74         if (!_is_valid_path(dir_path)) {
75                 MSAPI_DBG("Invalid path : %s", dir_path);
76                 return MS_MEDIA_ERR_INVALID_PATH;
77         }
78
79         if (stat(dir_path, &sb) == -1) {
80                 MSAPI_DBG("stat failed");
81                 dp = opendir(dir_path);
82                 if (dp == NULL) {
83                         /*if openning directory is failed, check it exists. */
84                         if (errno == ENOENT) {
85                                 /* this directory is deleted */
86                                 return MS_MEDIA_ERR_NONE;
87                         }
88                 } else {
89                         closedir(dp);
90                 }
91                 return MS_MEDIA_ERR_INTERNAL;
92         } else {
93                 if((sb.st_mode & S_IFMT) != S_IFDIR) {
94                         MSAPI_DBG("Invalid path : %s is not directory", dir_path);
95                         return MS_MEDIA_ERR_INVALID_PATH;
96                 }
97         }
98
99         return MS_MEDIA_ERR_NONE;
100 }
101
102
103 /* receive message from media-server[function : ms_receive_message_from_scanner] */
104 gboolean _read_socket(GIOChannel *src, GIOCondition condition, gpointer data)
105 {
106         GSource *source = NULL;
107         scan_complete_cb user_callback;
108         void *user_data = NULL;
109         ms_comm_msg_s recv_msg;
110         media_request_result_s req_result;
111         int ret;
112         int sockfd = -1;
113
114         sockfd = g_io_channel_unix_get_fd(src);
115         if (sockfd < 0) {
116                 MSAPI_DBG("sock fd is invalid!");
117                 return TRUE;
118         }
119
120         memset(&recv_msg, 0x0, sizeof(ms_comm_msg_s));
121
122         /* Socket is readable */
123         ret = ms_ipc_receive_message(sockfd, &recv_msg, sizeof(recv_msg), NULL, NULL);
124         if (ret != MS_MEDIA_ERR_NONE) {
125                 MSAPI_DBG("ms_ipc_receive_message failed");
126                 return TRUE;
127         }
128
129         memset(&req_result, 0x0, sizeof(media_request_result_s));
130         req_result.pid = recv_msg.pid;
131         req_result.result = recv_msg.result;
132         if (recv_msg.msg_type ==MS_MSG_SCANNER_RESULT) {
133                 req_result.complete_path = strdup(recv_msg.msg);
134                 req_result.request_type = MEDIA_DIRECTORY_SCAN;
135                 MSAPI_DBG("complete_path :%d", req_result.complete_path);
136         } else if (recv_msg.msg_type == MS_MSG_SCANNER_BULK_RESULT) {
137                 req_result.complete_path = strdup(recv_msg.msg);
138                 req_result.request_type = MEDIA_FILES_REGISTER;
139         }
140
141         MSAPI_DBG("pid :%d", req_result.pid);
142         MSAPI_DBG("result :%d", req_result.result);
143         MSAPI_DBG("request_type :%d", req_result.request_type);
144
145         source = ((media_callback_data *)data)->source;
146         user_callback = ((media_callback_data *)data)->user_callback;
147         user_data = ((media_callback_data *)data)->user_data;
148
149         /*call user define function*/
150         user_callback(&req_result, user_data);
151
152         MS_SAFE_FREE(req_result.complete_path);
153
154         /*close an IO channel*/
155         g_io_channel_shutdown(src,  FALSE, NULL);
156         g_io_channel_unref(src);
157
158         g_source_destroy(source);
159         close(sockfd);
160         MS_SAFE_FREE(data);
161
162         return TRUE;
163 }
164
165 static int _attach_callback(int *sockfd, scan_complete_cb user_callback, void *user_data)
166 {
167         GIOChannel *channel = NULL;
168         GMainContext *context = NULL;
169         GSource *source = NULL;
170         media_callback_data *cb_data;
171
172         /*get the global default main context*/
173         context = g_main_context_default();
174
175         /* Create new channel to watch udp socket */
176         channel = g_io_channel_unix_new(*sockfd);
177         source = g_io_create_watch(channel, G_IO_IN);
178
179         cb_data = malloc(sizeof(media_callback_data));
180         cb_data->source = source;
181         cb_data->user_callback = user_callback;
182         cb_data->user_data = user_data;
183
184         /* Set callback to be called when socket is readable */
185         g_source_set_callback(source, (GSourceFunc)_read_socket, cb_data, NULL);
186         g_source_attach(source, context);
187         g_source_unref(source);
188
189         return MS_MEDIA_ERR_NONE;
190 }
191
192 static int __media_db_request_update_sync(ms_msg_type_e msg_type, const char *request_msg)
193 {
194         int ret = MS_MEDIA_ERR_NONE;
195         int request_msg_size = 0;
196         int sockfd = -1;
197         int err = -1;
198         struct sockaddr_in serv_addr;
199         unsigned int serv_addr_len = -1;
200         int port = MS_SCANNER_PORT;
201         ms_comm_msg_s send_msg;
202
203         if(!MS_STRING_VALID(request_msg))
204         {
205                 MSAPI_DBG_ERR("invalid query");
206                 return MS_MEDIA_ERR_INVALID_PARAMETER;
207         }
208
209         request_msg_size = strlen(request_msg);
210         if(request_msg_size >= MAX_MSG_SIZE)
211         {
212                 MSAPI_DBG_ERR("Query is Too long. [%d] query size limit is [%d]", request_msg_size, MAX_MSG_SIZE);
213                 return MS_MEDIA_ERR_INVALID_PARAMETER;
214         }
215
216         MSAPI_DBG("querysize[%d] query[%s]", request_msg_size, request_msg);
217
218         memset((void *)&send_msg, 0, sizeof(ms_comm_msg_s));
219         send_msg.msg_type = msg_type;
220         send_msg.pid = syscall(__NR_getpid);
221         send_msg.msg_size= request_msg_size;
222         strncpy(send_msg.msg, request_msg, request_msg_size);
223
224         /*Create Socket*/
225         ret = ms_ipc_create_client_socket(MS_PROTOCOL_UDP, MS_TIMEOUT_SEC_10, &sockfd);
226         MSAPI_RETV_IF(ret != MS_MEDIA_ERR_NONE, ret);
227
228         ret = ms_ipc_send_msg_to_server(sockfd, port, &send_msg, &serv_addr);
229         if (ret != MS_MEDIA_ERR_NONE) {
230                 MSAPI_DBG_ERR("ms_ipc_send_msg_to_server failed : %d", ret);
231                 close(sockfd);
232                 return ret;
233         }
234
235         /*Receive Response*/
236         ms_comm_msg_s recv_msg;
237         serv_addr_len = sizeof(serv_addr);
238
239         memset(&recv_msg, 0x0, sizeof(ms_comm_msg_s));
240         err = ms_ipc_wait_message(sockfd, &recv_msg, sizeof(recv_msg), &serv_addr, NULL);
241         if (err != MS_MEDIA_ERR_NONE) {
242                 ret = err;
243         } else {
244                 MSAPI_DBG("RECEIVE OK [%d]", recv_msg.result);
245                 ret = recv_msg.result;
246         }
247
248         close(sockfd);
249
250         return ret;
251 }
252
253
254 static int __media_db_request_update_async(ms_msg_type_e msg_type, const char *request_msg, scan_complete_cb user_callback, void *user_data)
255 {
256         int ret = MS_MEDIA_ERR_NONE;
257         int request_msg_size = 0;
258         int sockfd = -1;
259         int port = MS_SCANNER_PORT;
260         ms_comm_msg_s send_msg;
261
262         if(!MS_STRING_VALID(request_msg))
263         {
264                 MSAPI_DBG_ERR("invalid query");
265                 return MS_MEDIA_ERR_INVALID_PARAMETER;
266         }
267
268         MSAPI_DBG("REQUEST DIRECTORY SCANNING");
269
270         request_msg_size = strlen(request_msg);
271         if(request_msg_size >= MAX_MSG_SIZE)
272         {
273                 MSAPI_DBG_ERR("Query is Too long. [%d] query size limit is [%d]", request_msg_size, MAX_MSG_SIZE);
274                 return MS_MEDIA_ERR_INVALID_PARAMETER;
275         }
276
277         MSAPI_DBG("querysize[%d] query[%s]", request_msg_size, request_msg);
278
279         memset((void *)&send_msg, 0, sizeof(ms_comm_msg_s));
280         send_msg.msg_type = msg_type;
281         send_msg.pid = syscall(__NR_getpid);
282         send_msg.msg_size = request_msg_size;
283         strncpy(send_msg.msg, request_msg, request_msg_size);
284
285         /*Create Socket*/
286         ret = ms_ipc_create_client_socket(MS_PROTOCOL_UDP, 0, &sockfd);
287         MSAPI_RETV_IF(ret != MS_MEDIA_ERR_NONE, ret);
288
289         ret = ms_ipc_send_msg_to_server(sockfd, port, &send_msg, NULL);
290         if (ret != MS_MEDIA_ERR_NONE) {
291                 MSAPI_DBG_ERR("ms_ipc_send_msg_to_server failed : %d", ret);
292                 close(sockfd);
293                 return ret;
294         }
295
296         ret = _attach_callback(&sockfd, user_callback ,user_data);
297         if(ret != MS_MEDIA_ERR_NONE)
298                 return ret;
299
300         return ret;
301 }
302
303
304 int media_directory_scanning_async(const char *directory_path, bool recusive_on, scan_complete_cb user_callback, void *user_data)
305 {
306         int ret;
307
308         ret = _check_dir_path(directory_path);
309         if(ret != MS_MEDIA_ERR_NONE)
310                 return ret;
311
312         if (recusive_on == TRUE)
313                 ret = __media_db_request_update_async(MS_MSG_DIRECTORY_SCANNING, directory_path, user_callback, user_data);
314         else
315                 ret = __media_db_request_update_async(MS_MSG_DIRECTORY_SCANNING_NON_RECURSIVE, directory_path, user_callback, user_data);
316
317         return ret;
318 }
319
320 static int _check_file_path(const char *file_path)
321 {
322         int exist;
323         struct stat file_st;
324
325         /* check location of file */
326         /* file must exists under "/opt/usr/media" or "/opt/storage/sdcard" */
327         if(!_is_valid_path(file_path)) {
328                 MSAPI_DBG("Invalid path : %s", file_path);
329                 return MS_MEDIA_ERR_INVALID_PATH;
330         }
331
332         /* check the file exits actually */
333         exist = open(file_path, O_RDONLY);
334         if(exist < 0) {
335                 MSAPI_DBG("Not exist path : %s", file_path);
336                 return MS_MEDIA_ERR_INVALID_PATH;
337         }
338         close(exist);
339
340         /* check type of the path */
341         /* It must be a regular file */
342         memset(&file_st, 0, sizeof(struct stat));
343         if(stat(file_path, &file_st) == 0) {
344                 if(!S_ISREG(file_st.st_mode)) {
345                         /* In this case, it is not a regula file */
346                         MSAPI_DBG("this path is not a file");
347                         return MS_MEDIA_ERR_INVALID_PATH;
348                 }
349         } else {
350                 MSAPI_DBG("stat failed [%s]", strerror(errno));
351                 return MS_MEDIA_ERR_INTERNAL;
352         }
353
354         return MS_MEDIA_ERR_NONE;
355 }
356
357 int media_file_register(const char *file_full_path)
358 {
359         int ret;
360
361         ret = _check_file_path(file_full_path);
362         if(ret != MS_MEDIA_ERR_NONE)
363                 return ret;
364
365         ret = __media_db_request_update_sync(MS_MSG_DB_UPDATE, file_full_path);
366
367         MSAPI_DBG("client receive: %d", ret);
368
369         return ret;
370 }
371
372 int media_files_register(const char *list_path, insert_complete_cb user_callback, void *user_data)
373 {
374         int ret;
375
376         ret = __media_db_request_update_async(MS_MSG_BULK_INSERT, list_path, user_callback, user_data);
377
378         MSAPI_DBG("client receive: %d", ret);
379
380         return ret;
381 }
382