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:
99 ret = DP_ERROR_IO_ERROR;
105 static void __download_info_cb(user_download_info_t *info, void *user_data)
108 TRACE_ERROR("[NULL-CHECK] Agent info");
112 TRACE_ERROR("[NULL-CHECK] user_data");
115 dp_request *request = (dp_request *) user_data;
116 if (request->id < 0 || (request->agent_id != info->download_id)) {
117 TRACE_ERROR("[NULL-CHECK] agent_id : %d req_id %d",
118 request->agent_id, info->download_id);
122 int request_id = request->id;
124 // update info before sending event
125 if (info->file_type) {
126 TRACE_INFO("[STARTED][%d] [%s]", request_id, info->file_type);
127 if (dp_db_replace_column(request_id, DP_DB_TABLE_DOWNLOAD_INFO,
129 DP_DB_COL_TYPE_TEXT, info->file_type) == 0) {
131 if (info->tmp_saved_path) {
132 TRACE_INFO("[PATH][%d] being written to [%s]",
133 request_id, info->tmp_saved_path);
135 (request_id, DP_DB_TABLE_DOWNLOAD_INFO,
136 DP_DB_COL_TMP_SAVED_PATH, DP_DB_COL_TYPE_TEXT,
137 info->tmp_saved_path) < 0)
138 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
141 if (info->file_size > 0) {
143 ("[FILE-SIZE][%d] [%lld]", request_id, info->file_size);
144 CLIENT_MUTEX_LOCK(&(request->mutex));
145 request->file_size = info->file_size;
146 CLIENT_MUTEX_UNLOCK(&(request->mutex));
148 (request_id, DP_DB_TABLE_DOWNLOAD_INFO,
149 DP_DB_COL_CONTENT_SIZE,
150 DP_DB_COL_TYPE_INT64, &info->file_size) < 0)
151 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
154 if (info->content_name) {
156 ("[CONTENTNAME][%d] [%s]", request_id, info->content_name);
158 (request_id, DP_DB_TABLE_DOWNLOAD_INFO,
159 DP_DB_COL_CONTENT_NAME,
160 DP_DB_COL_TYPE_TEXT, info->content_name) < 0)
161 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
164 TRACE_INFO("[ETAG][%d] [%s]", request_id, info->etag);
165 if (dp_db_replace_column
166 (request_id, DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_ETAG,
167 DP_DB_COL_TYPE_TEXT, info->etag) < 0)
168 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
172 ("[ERROR][%d][SQL] failed to insert downloadinfo",
177 CLIENT_MUTEX_LOCK(&(request->mutex));
179 request->state = DP_STATE_DOWNLOADING;
180 if (dp_db_set_column(request->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
181 DP_DB_COL_TYPE_INT, &request->state) < 0)
182 TRACE_ERROR("[ERROR][%d][SQL]", request->id);
184 if (request->group && request->group->event_socket >= 0 &&
186 dp_ipc_send_event(request->group->event_socket,
187 request->id, DP_STATE_DOWNLOADING, DP_ERROR_NONE, 0);
189 if (request->auto_notification)
190 request->noti_priv_id =
191 dp_set_downloadinginfo_notification
192 (request->id, request->packagename);
194 CLIENT_MUTEX_UNLOCK(&(request->mutex));
197 static void __progress_cb(user_progress_info_t *info, void *user_data)
200 TRACE_ERROR("[NULL-CHECK] Agent info");
204 TRACE_ERROR("[NULL-CHECK] user_data");
207 dp_request *request = (dp_request *) user_data;
208 if (request->id < 0 || (request->agent_id != info->download_id)) {
209 TRACE_ERROR("[NULL-CHECK][%d] agent_id : %d req_id %d",
210 request->id, request->agent_id, info->download_id);
214 CLIENT_MUTEX_LOCK(&(request->mutex));
215 if (request->state == DP_STATE_DOWNLOADING) {
216 request->received_size = info->received_size;
217 time_t tt = time(NULL);
218 struct tm *localTime = localtime(&tt);
219 // send event every 1 second.
220 if (request->progress_lasttime != localTime->tm_sec) {
221 request->progress_lasttime = localTime->tm_sec;
222 if (request->progress_cb && request->group &&
223 request->group->event_socket >= 0 &&
224 request->received_size > 0)
225 dp_ipc_send_event(request->group->event_socket,
226 request->id, request->state, request->error,
227 request->received_size);
228 if (request->auto_notification)
229 dp_update_downloadinginfo_notification
230 (request->noti_priv_id,
231 (double)request->received_size,
232 (double)request->file_size);
235 CLIENT_MUTEX_UNLOCK(&(request->mutex));
238 static void __finished_cb(user_finished_info_t *info, void *user_data)
241 TRACE_ERROR("[NULL-CHECK] Agent info");
244 TRACE_INFO("Agent ID[%d] err[%d] http_status[%d]",
245 info->download_id, info->err, info->http_status);
247 TRACE_ERROR("[NULL-CHECK] user_data");
250 dp_request *request = (dp_request *) user_data;
251 if (request->id < 0 || (request->agent_id != info->download_id)) {
252 TRACE_ERROR("[NULL-CHECK][%d] agent_id : %d req_id %d",
253 request->id, request->agent_id, info->download_id);
257 CLIENT_MUTEX_LOCK(&(request->mutex));
258 int request_id = request->id;
259 dp_credential cred = request->credential;
260 CLIENT_MUTEX_UNLOCK(&(request->mutex));
261 dp_state_type state = DP_STATE_NONE;
262 dp_error_type errorcode = DP_ERROR_NONE;
264 // update info before sending event
265 if (dp_db_update_date
266 (request_id, DP_DB_TABLE_LOG, DP_DB_COL_ACCESS_TIME) < 0)
267 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
269 if (info->http_status > 0)
270 if (dp_db_replace_column(request_id, DP_DB_TABLE_DOWNLOAD_INFO,
271 DP_DB_COL_HTTP_STATUS,
272 DP_DB_COL_TYPE_INT, &info->http_status) < 0)
273 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
275 if (info->err == DA_RESULT_OK) {
276 if (info->saved_path) {
278 char *content_name = NULL;
280 str = strrchr(info->saved_path, '/');
283 content_name = dp_strdup(str);
284 TRACE_INFO("[PARSE][%d] content_name [%s]",
285 request_id, content_name);
288 ("[chown][%d] [%d][%d]", request_id, cred.uid, cred.gid);
289 if (chown(info->saved_path, cred.uid, cred.gid) < 0)
290 TRACE_STRERROR("[ERROR][%d] chown", request_id);
291 if (dp_db_replace_column
292 (request_id, DP_DB_TABLE_DOWNLOAD_INFO,
293 DP_DB_COL_SAVED_PATH,
294 DP_DB_COL_TYPE_TEXT, info->saved_path) == 0) {
295 if (content_name != NULL) {
297 (request_id, DP_DB_TABLE_DOWNLOAD_INFO,
298 DP_DB_COL_CONTENT_NAME,
299 DP_DB_COL_TYPE_TEXT, content_name) < 0)
300 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
303 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
305 if (content_name != NULL)
308 errorcode = DP_ERROR_NONE;
309 state = DP_STATE_COMPLETED;
311 TRACE_INFO("[COMPLETED][%d] saved to [%s]",
312 request_id, info->saved_path);
314 TRACE_ERROR("Cannot enter here");
315 TRACE_ERROR("[ERROR][%d] No SavedPath", request_id);
316 errorcode = DP_ERROR_INVALID_DESTINATION;
317 state = DP_STATE_FAILED;
319 CLIENT_MUTEX_LOCK(&(request->mutex));
320 if (request->file_size == 0) {
321 request->file_size = request->received_size;
322 if (dp_db_replace_column
323 (request_id, DP_DB_TABLE_DOWNLOAD_INFO,
324 DP_DB_COL_CONTENT_SIZE,
325 DP_DB_COL_TYPE_INT64, &request->file_size ) < 0)
326 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
328 CLIENT_MUTEX_UNLOCK(&(request->mutex));
329 } else if (info->err == DA_RESULT_USER_CANCELED) {
330 state = DP_STATE_CANCELED;
331 errorcode = DP_ERROR_NONE;
332 TRACE_INFO("[CANCELED][%d]", request_id);
334 state = DP_STATE_FAILED;
335 errorcode = __change_error(info->err);
336 TRACE_INFO("[FAILED][%d][%s]", request_id,
337 dp_print_errorcode(errorcode));
341 (request_id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
342 DP_DB_COL_TYPE_INT, &state) < 0)
343 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
345 if (errorcode != DP_ERROR_NONE) {
346 if (dp_db_set_column(request_id, DP_DB_TABLE_LOG,
347 DP_DB_COL_ERRORCODE, DP_DB_COL_TYPE_INT,
349 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
353 CLIENT_MUTEX_LOCK(&(request->mutex));
355 request->state = state;
356 request->error = errorcode;
358 // stay on memory till called destroy by client or timeout
359 if (request->group != NULL && request->group->event_socket >= 0) {
360 /* update the received file size.
361 * The last received file size cannot update
362 * because of reducing update algorithm*/
363 if (request->received_size > 0)
364 dp_ipc_send_event(request->group->event_socket,
365 request->id, DP_STATE_DOWNLOADING, request->error,
366 request->received_size);
367 if (request->state_cb)
368 dp_ipc_send_event(request->group->event_socket,
369 request->id, request->state, request->error, 0);
370 request->group->queued_count--;
373 // to prevent the crash . check packagename of request
374 if (request->auto_notification && request->packagename != NULL)
375 request->noti_priv_id =
376 dp_set_downloadedinfo_notification(request->noti_priv_id,
377 request->id, request->packagename, request->state);
379 request->stop_time = (int)time(NULL);
381 CLIENT_MUTEX_UNLOCK(&(request->mutex));
383 dp_thread_queue_manager_wake_up();
386 static void __paused_cb(user_paused_info_t *info, void *user_data)
389 dp_request *request = (dp_request *) user_data;
391 TRACE_ERROR("[NULL-CHECK] request");
394 if (request->id < 0 || (request->agent_id != info->download_id)) {
395 TRACE_ERROR("[NULL-CHECK][%d] agent_id : %d req_id %d",
396 request->id, request->agent_id, info->download_id);
400 CLIENT_MUTEX_LOCK(&(request->mutex));
401 int request_id = request->id;
402 CLIENT_MUTEX_UNLOCK(&(request->mutex));
404 if (dp_db_update_date
405 (request_id, DP_DB_TABLE_LOG, DP_DB_COL_ACCESS_TIME) < 0)
406 TRACE_ERROR("[ERROR][%d][SQL]", request_id);
409 CLIENT_MUTEX_LOCK(&(request->mutex));
411 request->state = DP_STATE_PAUSED;
414 (request->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
415 DP_DB_COL_TYPE_INT, &request->state) < 0) {
416 TRACE_ERROR("[ERROR][%d][SQL]", request->id);
419 if (request->group &&
420 request->group->event_socket >= 0 && request->state_cb)
421 dp_ipc_send_event(request->group->event_socket,
422 request->id, request->state, request->error, 0);
425 request->group->queued_count--;
427 CLIENT_MUTEX_UNLOCK(&(request->mutex));
429 dp_thread_queue_manager_wake_up();
435 da_client_cb_t da_cb = {
441 da_ret = da_init(&da_cb);
442 if (da_ret != DA_RESULT_OK) {
443 return DP_ERROR_OUT_OF_MEMORY;
445 return DP_ERROR_NONE;
448 void dp_deinit_agent()
455 dp_error_type dp_cancel_agent_download(int req_id)
458 TRACE_ERROR("[NULL-CHECK] req_id");
461 if (da_cancel_download(req_id) == DA_RESULT_OK)
468 dp_error_type dp_pause_agent_download(int req_id)
471 TRACE_ERROR("[NULL-CHECK] req_id");
474 if (da_suspend_download(req_id) == DA_RESULT_OK)
483 dp_error_type dp_start_agent_download(dp_request *request)
487 dp_error_type errorcode = DP_ERROR_NONE;
488 extension_data_t ext_data = {0,};
492 TRACE_ERROR("[NULL-CHECK] download_clientinfo_slot");
493 return DP_ERROR_INVALID_PARAMETER;
496 char *url = dp_request_get_url(request->id, request, &errorcode);
498 TRACE_ERROR("[ERROR][%d] URL is NULL", request->id);
499 return DP_ERROR_INVALID_URL;
502 dp_request_get_destination(request->id, request, &errorcode);
503 if (destination != NULL)
504 ext_data.install_path = destination;
507 dp_request_get_filename(request->id, request, &errorcode);
508 if (filename != NULL)
509 ext_data.file_name = filename;
511 // call start_download() of download-agent
513 char *tmp_saved_path =
514 dp_request_get_tmpsavedpath(request->id, request, &errorcode);
515 if (tmp_saved_path) {
516 char *etag = dp_request_get_etag(request->id, request, &errorcode);
518 TRACE_INFO("[RESUME][%d]", request->id);
519 ext_data.etag = etag;
520 ext_data.temp_file_path = tmp_saved_path;
522 /* FIXME later : It is better to handle the unlink function in download agaent module
523 * or in upload the request data to memory after the download provider process is restarted */
524 TRACE_INFO("[RESTART][%d] try to remove tmp file [%s]",
525 request->id, tmp_saved_path);
526 if (dp_is_file_exist(tmp_saved_path) == 0)
527 if (unlink(tmp_saved_path) != 0)
529 ("[ERROR][%d] remove file", request->id);
533 // get headers list from httpheaders table(DB)
534 int headers_count = dp_db_get_cond_rows_count
535 (request->id, DP_DB_TABLE_HTTP_HEADERS, NULL, 0, NULL);
536 if (headers_count > 0) {
537 ext_data.request_header = calloc(headers_count, sizeof(char*));
538 if (ext_data.request_header != NULL) {
539 ext_data.request_header_count = dp_db_get_http_headers_list
540 (request->id, (char**)ext_data.request_header);
544 ext_data.user_data = (void *)request;
546 // call start API of agent lib
548 da_start_download_with_extension(url, &ext_data, &req_dl_id);
549 if (ext_data.request_header_count > 0) {
552 len = ext_data.request_header_count;
553 for (i = 0; i < len; i++) {
554 if (ext_data.request_header[i])
555 free((void *)(ext_data.request_header[i]));
557 free(ext_data.request_header);
562 free(tmp_saved_path);
564 // if start_download() return error cause of maximun download limitation,
565 // set state to DOWNLOAD_STATE_PENDED.
566 if (da_ret == DA_ERR_ALREADY_MAX_DOWNLOAD) {
567 TRACE_INFO("[PENDING][%d] DA_ERR_ALREADY_MAX_DOWNLOAD [%d]",
568 request->id, da_ret);
569 return DP_ERROR_TOO_MANY_DOWNLOADS;
570 } else if (da_ret != DA_RESULT_OK) {
571 TRACE_ERROR("[ERROR][%d] DP_ERROR_CONNECTION_FAILED [%d]",
572 request->id, da_ret);
573 return __change_error(da_ret);
575 TRACE_INFO("[SUCCESS][%d] agent_id [%d]", request->id, req_dl_id);
576 request->agent_id = req_dl_id;
577 return DP_ERROR_NONE;
580 dp_error_type dp_resume_agent_download(int req_id)
584 TRACE_ERROR("[NULL-CHECK] req_id");
585 return DP_ERROR_INVALID_PARAMETER;
587 da_ret = da_resume_download(req_id);
588 if (da_ret == DA_RESULT_OK)
589 return DP_ERROR_NONE;
590 else if (da_ret == DA_ERR_INVALID_STATE)
591 return DP_ERROR_INVALID_STATE;
592 return __change_error(da_ret);
597 int dp_is_alive_download(int req_id)
601 TRACE_ERROR("[NULL-CHECK] req_id");
604 da_ret = da_is_valid_download_id(req_id);