2 * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <sys/types.h>
25 #include "download-provider.h"
26 #include "download-provider-log.h"
27 #include "download-provider-pthread.h"
28 #include "download-provider-socket.h"
29 #include "download-provider-db.h"
30 #include "download-provider-queue.h"
31 #include "download-provider-notification.h"
32 #include "download-provider-request.h"
34 #include "download-agent-defs.h"
35 #include "download-agent-interface.h"
37 int dp_is_file_exist(const char *file_path)
39 struct stat file_state;
42 if (file_path == NULL) {
43 TRACE_ERROR("[NULL-CHECK] file path is NULL");
47 stat_ret = stat(file_path, &file_state);
50 if (file_state.st_mode & S_IFREG)
56 static int __change_error(int err)
58 int ret = DP_ERROR_NONE;
63 case DA_ERR_INVALID_ARGUMENT:
64 ret = DP_ERROR_INVALID_PARAMETER;
66 case DA_ERR_FAIL_TO_MEMALLOC:
67 ret = DP_ERROR_OUT_OF_MEMORY;
69 case DA_ERR_UNREACHABLE_SERVER:
70 ret = DP_ERROR_NETWORK_UNREACHABLE;
72 case DA_ERR_HTTP_TIMEOUT:
73 ret = DP_ERROR_CONNECTION_TIMED_OUT;
75 case DA_ERR_DISK_FULL:
76 ret = DP_ERROR_NO_SPACE;
78 case DA_ERR_INVALID_STATE:
79 ret = DP_ERROR_INVALID_STATE;
81 case DA_ERR_NETWORK_FAIL:
82 ret = DP_ERROR_CONNECTION_FAILED;
84 case DA_ERR_INVALID_URL:
85 ret = DP_ERROR_INVALID_URL;
87 case DA_ERR_INVALID_INSTALL_PATH:
88 ret = DP_ERROR_INVALID_DESTINATION;
90 case DA_ERR_ALREADY_MAX_DOWNLOAD:
91 ret = DP_ERROR_TOO_MANY_DOWNLOADS;
93 case DA_ERR_FAIL_TO_CREATE_THREAD:
94 case DA_ERR_FAIL_TO_OBTAIN_MUTEX:
95 case DA_ERR_FAIL_TO_ACCESS_FILE:
96 case DA_ERR_FAIL_TO_GET_CONF_VALUE:
97 case DA_ERR_FAIL_TO_ACCESS_STORAGE:
98 ret = DP_ERROR_IO_ERROR;
104 static void __download_info_cb(user_download_info_t *info, void *user_data)
107 TRACE_ERROR("[NULL-CHECK] Agent info");
111 TRACE_ERROR("[NULL-CHECK] user_data");
114 dp_request *request = (dp_request *) user_data;
115 if (request->id < 0 || (request->agent_id != info->download_id)) {
116 TRACE_ERROR("[NULL-CHECK] agent_id : %d req_id %d",
117 request->agent_id, info->download_id);
121 int request_id = request->id;
123 // update info before sending event
124 if (info->file_type) {
125 TRACE_INFO("[STARTED][%d] [%s]", request_id, info->file_type);
126 if (dp_db_replace_column(request_id, DP_DB_TABLE_DOWNLOAD_INFO,
128 DP_DB_COL_TYPE_TEXT, info->file_type) == 0) {
130 if (info->tmp_saved_path) {
131 TRACE_INFO("[PATH][%d] being written to [%s]",
132 request_id, info->tmp_saved_path);
134 (request_id, DP_DB_TABLE_DOWNLOAD_INFO,
135 DP_DB_COL_TMP_SAVED_PATH, DP_DB_COL_TYPE_TEXT,
136 info->tmp_saved_path) < 0)
137 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
140 if (info->file_size > 0) {
142 ("[FILE-SIZE][%d] [%lld]", request_id, info->file_size);
143 CLIENT_MUTEX_LOCK(&(request->mutex));
144 request->file_size = info->file_size;
145 CLIENT_MUTEX_UNLOCK(&(request->mutex));
147 (request_id, DP_DB_TABLE_DOWNLOAD_INFO,
148 DP_DB_COL_CONTENT_SIZE,
149 DP_DB_COL_TYPE_INT64, &info->file_size) < 0)
150 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
153 if (info->content_name) {
155 ("[CONTENTNAME][%d] [%s]", request_id, info->content_name);
157 (request_id, DP_DB_TABLE_DOWNLOAD_INFO,
158 DP_DB_COL_CONTENT_NAME,
159 DP_DB_COL_TYPE_TEXT, info->content_name) < 0)
160 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
163 TRACE_INFO("[ETAG][%d] [%s]", request_id, info->etag);
164 if (dp_db_replace_column
165 (request_id, DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_ETAG,
166 DP_DB_COL_TYPE_TEXT, info->etag) < 0)
167 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
171 ("[ERROR][%d][SQL] failed to insert downloadinfo",
176 CLIENT_MUTEX_LOCK(&(request->mutex));
178 request->state = DP_STATE_DOWNLOADING;
179 if (dp_db_set_column(request->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
180 DP_DB_COL_TYPE_INT, &request->state) < 0)
181 TRACE_ERROR("[ERROR][%d][SQL]", request->id);
183 if (request->group && request->group->event_socket >= 0 &&
185 dp_ipc_send_event(request->group->event_socket,
186 request->id, DP_STATE_DOWNLOADING, DP_ERROR_NONE, 0);
188 if (request->auto_notification)
189 request->noti_priv_id =
190 dp_set_downloadinginfo_notification
191 (request->id, request->packagename);
193 CLIENT_MUTEX_UNLOCK(&(request->mutex));
196 static void __progress_cb(user_progress_info_t *info, void *user_data)
199 TRACE_ERROR("[NULL-CHECK] Agent info");
203 TRACE_ERROR("[NULL-CHECK] user_data");
206 dp_request *request = (dp_request *) user_data;
207 if (request->id < 0 || (request->agent_id != info->download_id)) {
208 TRACE_ERROR("[NULL-CHECK][%d] agent_id : %d req_id %d",
209 request->id, request->agent_id, info->download_id);
213 CLIENT_MUTEX_LOCK(&(request->mutex));
214 if (request->state == DP_STATE_DOWNLOADING) {
215 request->received_size = info->received_size;
216 time_t tt = time(NULL);
217 struct tm *localTime = localtime(&tt);
218 // send event every 1 second.
219 if (request->progress_lasttime != localTime->tm_sec) {
220 request->progress_lasttime = localTime->tm_sec;
221 if (request->progress_cb && request->group &&
222 request->group->event_socket >= 0 &&
223 request->received_size > 0)
224 dp_ipc_send_event(request->group->event_socket,
225 request->id, request->state, request->error,
226 request->received_size);
227 if (request->auto_notification)
228 dp_update_downloadinginfo_notification
229 (request->noti_priv_id,
230 (double)request->received_size,
231 (double)request->file_size);
234 CLIENT_MUTEX_UNLOCK(&(request->mutex));
237 static void __finished_cb(user_finished_info_t *info, void *user_data)
240 TRACE_ERROR("[NULL-CHECK] Agent info");
243 TRACE_INFO("Agent ID[%d] err[%d] http_status[%d]",
244 info->download_id, info->err, info->http_status);
246 TRACE_ERROR("[NULL-CHECK] user_data");
249 dp_request *request = (dp_request *) user_data;
250 if (request->id < 0 || (request->agent_id != info->download_id)) {
251 TRACE_ERROR("[NULL-CHECK][%d] agent_id : %d req_id %d",
252 request->id, request->agent_id, info->download_id);
256 CLIENT_MUTEX_LOCK(&(request->mutex));
257 int request_id = request->id;
258 dp_credential cred = request->credential;
259 CLIENT_MUTEX_UNLOCK(&(request->mutex));
260 dp_state_type state = DP_STATE_NONE;
261 dp_error_type errorcode = DP_ERROR_NONE;
263 // update info before sending event
264 if (dp_db_update_date
265 (request_id, DP_DB_TABLE_LOG, DP_DB_COL_ACCESS_TIME) < 0)
266 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
268 if (info->http_status > 0)
269 if (dp_db_replace_column(request_id, DP_DB_TABLE_DOWNLOAD_INFO,
270 DP_DB_COL_HTTP_STATUS,
271 DP_DB_COL_TYPE_INT, &info->http_status) < 0)
272 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
274 if (info->err == DA_RESULT_OK) {
275 if (info->saved_path) {
277 char *content_name = NULL;
279 str = strrchr(info->saved_path, '/');
282 content_name = dp_strdup(str);
283 TRACE_INFO("[PARSE][%d] content_name [%s]",
284 request_id, content_name);
287 ("[chown][%d] [%d][%d]", request_id, cred.uid, cred.gid);
288 if (chown(info->saved_path, cred.uid, cred.gid) < 0)
289 TRACE_STRERROR("[ERROR][%d] chown", request_id);
290 if (dp_db_replace_column
291 (request_id, DP_DB_TABLE_DOWNLOAD_INFO,
292 DP_DB_COL_SAVED_PATH,
293 DP_DB_COL_TYPE_TEXT, info->saved_path) == 0) {
294 if (content_name != NULL) {
296 (request_id, DP_DB_TABLE_DOWNLOAD_INFO,
297 DP_DB_COL_CONTENT_NAME,
298 DP_DB_COL_TYPE_TEXT, content_name) < 0)
299 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
302 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
304 if (content_name != NULL)
307 errorcode = DP_ERROR_NONE;
308 state = DP_STATE_COMPLETED;
310 TRACE_INFO("[COMPLETED][%d] saved to [%s]",
311 request_id, info->saved_path);
313 TRACE_ERROR("Cannot enter here");
314 TRACE_ERROR("[ERROR][%d] No SavedPath", request_id);
315 errorcode = DP_ERROR_INVALID_DESTINATION;
316 state = DP_STATE_FAILED;
318 CLIENT_MUTEX_LOCK(&(request->mutex));
319 if (request->file_size == 0) {
320 request->file_size = request->received_size;
321 if (dp_db_replace_column
322 (request_id, DP_DB_TABLE_DOWNLOAD_INFO,
323 DP_DB_COL_CONTENT_SIZE,
324 DP_DB_COL_TYPE_INT64, &request->file_size ) < 0)
325 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
327 CLIENT_MUTEX_UNLOCK(&(request->mutex));
328 } else if (info->err == DA_RESULT_USER_CANCELED) {
329 state = DP_STATE_CANCELED;
330 errorcode = DP_ERROR_NONE;
331 TRACE_INFO("[CANCELED][%d]", request_id);
333 state = DP_STATE_FAILED;
334 errorcode = __change_error(info->err);
335 TRACE_INFO("[FAILED][%d][%s]", request_id,
336 dp_print_errorcode(errorcode));
340 (request_id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
341 DP_DB_COL_TYPE_INT, &state) < 0)
342 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
344 if (errorcode != DP_ERROR_NONE) {
345 if (dp_db_set_column(request_id, DP_DB_TABLE_LOG,
346 DP_DB_COL_ERRORCODE, DP_DB_COL_TYPE_INT,
348 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
352 CLIENT_MUTEX_LOCK(&(request->mutex));
354 request->state = state;
355 request->error = errorcode;
357 // stay on memory till called destroy by client or timeout
358 if (request->group != NULL && request->group->event_socket >= 0) {
359 /* update the received file size.
360 * The last received file size cannot update
361 * because of reducing update algorithm*/
362 if (request->received_size > 0)
363 dp_ipc_send_event(request->group->event_socket,
364 request->id, DP_STATE_DOWNLOADING, request->error,
365 request->received_size);
366 if (request->state_cb)
367 dp_ipc_send_event(request->group->event_socket,
368 request->id, request->state, request->error, 0);
369 request->group->queued_count--;
372 // to prevent the crash . check packagename of request
373 if (request->auto_notification && request->packagename != NULL)
374 request->noti_priv_id =
375 dp_set_downloadedinfo_notification(request->noti_priv_id,
376 request->id, request->packagename, request->state);
378 request->stop_time = (int)time(NULL);
380 CLIENT_MUTEX_UNLOCK(&(request->mutex));
382 dp_thread_queue_manager_wake_up();
385 static void __paused_cb(user_paused_info_t *info, void *user_data)
388 dp_request *request = (dp_request *) user_data;
390 TRACE_ERROR("[NULL-CHECK] request");
393 if (request->id < 0 || (request->agent_id != info->download_id)) {
394 TRACE_ERROR("[NULL-CHECK][%d] agent_id : %d req_id %d",
395 request->id, request->agent_id, info->download_id);
399 CLIENT_MUTEX_LOCK(&(request->mutex));
400 int request_id = request->id;
401 CLIENT_MUTEX_UNLOCK(&(request->mutex));
403 if (dp_db_update_date
404 (request_id, DP_DB_TABLE_LOG, DP_DB_COL_ACCESS_TIME) < 0)
405 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
408 CLIENT_MUTEX_LOCK(&(request->mutex));
410 request->state = DP_STATE_PAUSED;
413 (request->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
414 DP_DB_COL_TYPE_INT, &request->state) < 0) {
415 TRACE_ERROR("[ERROR][%d][SQL]", request->id);
418 if (request->group &&
419 request->group->event_socket >= 0 && request->state_cb)
420 dp_ipc_send_event(request->group->event_socket,
421 request->id, request->state, request->error, 0);
424 request->group->queued_count--;
426 CLIENT_MUTEX_UNLOCK(&(request->mutex));
428 dp_thread_queue_manager_wake_up();
434 da_client_cb_t da_cb = {
440 da_ret = da_init(&da_cb);
441 if (da_ret != DA_RESULT_OK) {
442 return DP_ERROR_OUT_OF_MEMORY;
444 return DP_ERROR_NONE;
447 void dp_deinit_agent()
454 dp_error_type dp_cancel_agent_download(int req_id)
457 TRACE_ERROR("[NULL-CHECK] req_id");
460 if (da_cancel_download(req_id) == DA_RESULT_OK)
467 dp_error_type dp_pause_agent_download(int req_id)
470 TRACE_ERROR("[NULL-CHECK] req_id");
473 if (da_suspend_download(req_id) == DA_RESULT_OK)
482 dp_error_type dp_start_agent_download(dp_request *request)
486 dp_error_type errorcode = DP_ERROR_NONE;
487 extension_data_t ext_data = {0,};
491 TRACE_ERROR("[NULL-CHECK] download_clientinfo_slot");
492 return DP_ERROR_INVALID_PARAMETER;
495 char *url = dp_request_get_url(request->id, request, &errorcode);
497 TRACE_ERROR("[ERROR][%d] URL is NULL", request->id);
498 return DP_ERROR_INVALID_URL;
501 dp_request_get_destination(request->id, request, &errorcode);
502 if (destination != NULL)
503 ext_data.install_path = destination;
506 dp_request_get_filename(request->id, request, &errorcode);
507 if (filename != NULL)
508 ext_data.file_name = filename;
510 // call start_download() of download-agent
512 char *tmp_saved_path =
513 dp_request_get_tmpsavedpath(request->id, request, &errorcode);
514 if (tmp_saved_path) {
515 char *etag = dp_request_get_etag(request->id, request, &errorcode);
517 TRACE_INFO("[RESUME][%d]", request->id);
518 ext_data.etag = etag;
519 ext_data.temp_file_path = tmp_saved_path;
521 /* FIXME later : It is better to handle the unlink function in download agaent module
522 * or in upload the request data to memory after the download provider process is restarted */
523 TRACE_INFO("[RESTART][%d] try to remove tmp file [%s]",
524 request->id, tmp_saved_path);
525 if (dp_is_file_exist(tmp_saved_path) == 0)
526 if (unlink(tmp_saved_path) != 0)
528 ("[ERROR][%d] remove file", request->id);
532 // get headers list from httpheaders table(DB)
533 int headers_count = dp_db_get_cond_rows_count
534 (request->id, DP_DB_TABLE_HTTP_HEADERS, NULL, 0, NULL);
535 if (headers_count > 0) {
536 ext_data.request_header = calloc(headers_count, sizeof(char*));
537 if (ext_data.request_header != NULL) {
538 ext_data.request_header_count = dp_db_get_http_headers_list
539 (request->id, (char**)ext_data.request_header);
543 ext_data.user_data = (void *)request;
545 // call start API of agent lib
547 da_start_download_with_extension(url, &ext_data, &req_dl_id);
548 if (ext_data.request_header_count > 0) {
551 len = ext_data.request_header_count;
552 for (i = 0; i < len; i++) {
553 if (ext_data.request_header[i])
554 free((void *)(ext_data.request_header[i]));
556 free(ext_data.request_header);
561 free(tmp_saved_path);
563 // if start_download() return error cause of maximun download limitation,
564 // set state to DOWNLOAD_STATE_PENDED.
565 if (da_ret == DA_ERR_ALREADY_MAX_DOWNLOAD) {
566 TRACE_INFO("[PENDING][%d] DA_ERR_ALREADY_MAX_DOWNLOAD [%d]",
567 request->id, da_ret);
568 return DP_ERROR_TOO_MANY_DOWNLOADS;
569 } else if (da_ret != DA_RESULT_OK) {
570 TRACE_ERROR("[ERROR][%d] DP_ERROR_CONNECTION_FAILED [%d]",
571 request->id, da_ret);
572 return __change_error(da_ret);
574 TRACE_INFO("[SUCCESS][%d] agent_id [%d]", request->id, req_dl_id);
575 request->agent_id = req_dl_id;
576 return DP_ERROR_NONE;
579 dp_error_type dp_resume_agent_download(int req_id)
583 TRACE_ERROR("[NULL-CHECK] req_id");
584 return DP_ERROR_INVALID_PARAMETER;
586 da_ret = da_resume_download(req_id);
587 if (da_ret == DA_RESULT_OK)
588 return DP_ERROR_NONE;
589 else if (da_ret == DA_ERR_INVALID_STATE)
590 return DP_ERROR_INVALID_STATE;
591 return __change_error(da_ret);
596 int dp_is_alive_download(int req_id)
600 TRACE_ERROR("[NULL-CHECK] req_id");
603 da_ret = da_is_valid_download_id(req_id);