2 * Copyright (c) 2013 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 <dlfcn.h> // dlopen
28 #include <download-provider.h>
29 #include <download-provider-log.h>
30 #include <download-provider-pthread.h>
31 #include <download-provider-ipc.h>
32 #include <download-provider-db-defs.h>
33 #include <download-provider-db.h>
34 #include <download-provider-utils.h>
35 #include <download-provider-notify.h>
36 #include <download-provider-security.h>
37 #include <download-provider-client.h>
38 #include <download-provider-client-manager.h>
39 #include <download-provider-plugin-download-agent.h>
40 #include <download-provider-notification-manager.h>
41 #include <download-provider-queue-manager.h>
43 #include <download-agent-defs.h>
44 #include <download-agent-interface.h>
45 #include <tzplatform_config.h>
48 #include "content/mime_type.h"
50 #define DP_SDCARD_MNT_POINT tzplatform_mkpath(TZ_SYS_STORAGE, "sdcard")
51 #define DP_EXTERNAL_STORAGE "/opt/media/"
52 #define DP_MAX_FILE_PATH_LEN 256
53 #define DP_MAX_MIME_TABLE_NUM 15
60 static const char *ambiguous_mime_type_list[] = {
62 "application/octet-stream"
65 static mime_table_type mime_table[] = {
67 {"application/pdf", DP_CONTENT_PDF},
69 {"application/msword", DP_CONTENT_WORD},
70 {"application/vnd.openxmlformats-officedocument.wordprocessingml.document", DP_CONTENT_WORD},
72 {"application/vnd.ms-powerpoint", DP_CONTENT_PPT},
73 {"application/vnd.openxmlformats-officedocument.presentationml.presentation", DP_CONTENT_PPT},
75 {"application/vnd.ms-excel", DP_CONTENT_EXCEL},
76 {"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", DP_CONTENT_EXCEL},
78 {"text/html", DP_CONTENT_HTML},
80 {"text/txt", DP_CONTENT_TEXT},
81 {"text/plain", DP_CONTENT_TEXT},
83 {"application/vnd.oma.drm.content", DP_CONTENT_SD_DRM},
84 {"application/vnd.oma.drm.message", DP_CONTENT_DRM},
85 {"application/x-shockwave-flash", DP_CONTENT_FLASH},
86 {"application/vnd.tizen.package", DP_CONTENT_TPK},
87 {"text/calendar", DP_CONTENT_VCAL},
90 static void *g_da_handle = NULL;
91 static int (*download_agent_init)(void) = NULL; // int da_init(da_client_cb_t *da_client_callback);
92 static int (*download_agent_deinit)(void) = NULL; // int da_deinit();
93 static int (*download_agent_is_alive)(int) = NULL; // int da_is_valid_download_id(int download_id);
94 static int (*download_agent_suspend)(int) = NULL; // int da_suspend_download(int download_id);
95 static int (*download_agent_resume)(int) = NULL; // int da_resume_download(int download_id);
96 static int (*download_agent_cancel)(int) = NULL; // int da_cancel_download(int download_id);
97 static int (*download_agent_suspend_without_update)(int) = NULL; // int da_suspend_download_without_update(int download_id);
98 static int (*download_agent_cancel_without_update)(int) = NULL; // int da_cancel_download_without_update(int download_id);
99 static int (*download_agent_start)(const char *url, req_data_t *ext_data, da_cb_t *da_cb_data, int *download_id) = NULL; // int da_start_download_with_extension(const char *url, extension_data_t *ext_data, int *download_id);
100 static dp_content_type __dp_get_content_type(const char *mime, const char *file_path);
102 static int __change_error(int err)
104 int ret = DP_ERROR_NONE;
109 case DA_ERR_INVALID_ARGUMENT:
110 ret = DP_ERROR_INVALID_PARAMETER;
112 case DA_ERR_FAIL_TO_MEMALLOC:
113 ret = DP_ERROR_OUT_OF_MEMORY;
115 case DA_ERR_UNREACHABLE_SERVER:
116 ret = DP_ERROR_NETWORK_UNREACHABLE;
118 case DA_ERR_HTTP_TIMEOUT:
119 ret = DP_ERROR_CONNECTION_TIMED_OUT;
121 case DA_ERR_DISK_FULL:
122 ret = DP_ERROR_NO_SPACE;
124 case DA_ERR_INVALID_STATE:
125 ret = DP_ERROR_INVALID_STATE;
127 case DA_ERR_NETWORK_FAIL:
128 ret = DP_ERROR_NETWORK_ERROR;
130 case DA_ERR_CONNECTION_FAIL:
131 case DA_ERR_NETWORK_UNAUTHORIZED:
132 ret = DP_ERROR_CONNECTION_FAILED;
134 case DA_ERR_INVALID_URL:
135 ret = DP_ERROR_INVALID_URL;
137 case DA_ERR_INVALID_INSTALL_PATH:
138 ret = DP_ERROR_INVALID_DESTINATION;
140 case DA_ERR_ALREADY_MAX_DOWNLOAD:
141 ret = DP_ERROR_TOO_MANY_DOWNLOADS;
143 case DA_ERR_FAIL_TO_CREATE_THREAD:
144 case DA_ERR_FAIL_TO_ACCESS_FILE:
146 ret = DP_ERROR_IO_ERROR;
152 static int __dp_da_state_feedback(dp_client_slots_fmt *slot, dp_request_fmt *request)
154 if (slot == NULL || request == NULL) {
155 TRACE_ERROR("check address");
156 return -1; // try cancel
159 TRACE_INFO("[INFO][%d] state:%s error:%s", request->id,
160 dp_print_state(request->state), dp_print_errorcode(request->error));
162 int errorcode = DP_ERROR_NONE;
163 if (dp_db_update_logging(slot->client.dbhandle, request->id,
164 request->state, request->error, &errorcode) < 0) {
165 TRACE_ERROR("logging failure id:%d error:%d", request->id, errorcode);
166 return -1; // try cancel
169 request->access_time = (int)time(NULL);
171 if (request->state_cb == 1) {
172 if (slot->client.notify < 0 ||
173 dp_notify_feedback(slot->client.notify, slot, request->id, request->state, request->error, 0) < 0) {
174 TRACE_ERROR("id:%d disable state callback by IO_ERROR", request->id);
175 request->state_cb = 0;
182 static int __precheck_request(dp_client_slots_fmt* slot, dp_request_fmt *request, int agentid)
184 if (request == NULL) {
185 TRACE_ERROR("null-check req_id:%d", agentid);
189 dp_client_fmt *client = &slot->client;
191 for (dp_request_fmt *req = client->requests; req; req = req->next) {
192 if (req == request) {
193 if (request->id < 0 || (request->agent_id != agentid)) {
194 TRACE_ERROR("id-check request_id:%d agent_id:%d req_id:%d",
195 request->id, request->agent_id, agentid);
204 static int __set_file_permission_to_client(dp_client_slots_fmt *slot, dp_request_fmt *request, char *saved_path)
206 if (slot == NULL || request == NULL || saved_path == NULL) {
207 TRACE_ERROR("slot:%p request:%p id:%d agentid:%d saved_path:%s",
208 slot, request, (request == NULL ? 0 : request->id),
209 (request == NULL ? 0 : request->agent_id), saved_path ? saved_path : "");
210 return DP_ERROR_INVALID_PARAMETER;
213 if (strncmp(saved_path, DP_EXTERNAL_STORAGE, strlen(DP_EXTERNAL_STORAGE)) == 0
214 || strncmp(DP_SDCARD_MNT_POINT,
215 saved_path, strlen(DP_SDCARD_MNT_POINT)) == 0) {
216 TRACE_INFO("Do not change permission for %s", saved_path);
217 return DP_ERROR_NONE;
220 struct stat lstat_info;
222 dp_credential cred = slot->credential;
224 if (lstat(saved_path, &lstat_info) == -1) {
225 TRACE_ERROR("Cannot access to %s", saved_path);
226 return DP_ERROR_PERMISSION_DENIED;
229 if ((lstat_info.st_mode & S_IFMT) == S_IFLNK) {
230 TRACE_ERROR("%s is a symbolic link.", saved_path);
231 return DP_ERROR_PERMISSION_DENIED;
234 fd = open(saved_path, O_RDONLY);
236 TRACE_SECURE_ERROR("open failed for file : %s", saved_path);
237 return DP_ERROR_IO_ERROR;
240 // Change the owner to client's uid.
241 if (fchown(fd, cred.uid, lstat_info.st_gid) != 0) {
242 TRACE_ERROR("[ERROR][%d] permission user:%d group:%d",
243 request->id, cred.uid, lstat_info.st_gid);
245 return DP_ERROR_PERMISSION_DENIED;
248 TRACE_INFO("file owner has been changed to %d:%d", cred.uid, lstat_info.st_gid);
251 return DP_ERROR_NONE;
254 static void __finished_cb(finished_info_t *info, void *user_req_data,
255 void *user_client_data)
258 TRACE_ERROR("check download info address");
261 dp_client_slots_fmt *slot = user_client_data;
262 dp_request_fmt *request = user_req_data;
263 if (slot == NULL || request == NULL) {
264 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), info->download_id);
266 free(info->saved_path);
270 CLIENT_MUTEX_LOCK(&slot->mutex);
271 if (__precheck_request(slot, request, info->download_id) < 0) {
272 TRACE_ERROR("error request agent_id:%d", info->download_id);
273 if (dp_cancel_agent_download(info->download_id) < 0)
274 TRACE_ERROR("failed to call cancel_download(%d)", info->download_id);
276 free(info->saved_path);
278 CLIENT_MUTEX_UNLOCK(&slot->mutex);
282 int state = DP_STATE_NONE;
283 int errorcode = DP_ERROR_NONE;
285 if (info->http_status > 0) {
286 if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_HTTP_STATUS, (void *)&info->http_status, 0, 0, &errorcode) < 0)
287 TRACE_ERROR("id:%d failed to set http_status(%d)", request->id, info->http_status);
290 TRACE_SECURE_DEBUG("[FINISH][%d][%s]", request->id, info->saved_path);
291 if (info->err == DA_RESULT_OK) {
292 if (info->saved_path != NULL) {
293 errorcode = __set_file_permission_to_client(slot,
294 request, info->saved_path);
296 TRACE_ERROR("[ERROR][%d] No SavedPath", request->id);
297 errorcode = DP_ERROR_INVALID_DESTINATION;
299 if (errorcode == DP_ERROR_NONE)
300 state = DP_STATE_COMPLETED;
302 state = DP_STATE_FAILED;
304 if (info->err == DA_RESULT_USER_CANCELED) {
306 TRACE_INFO("[CANCELED][%d]", request->id);
308 // if state is canceled and error is DP_ERROR_IO_EAGAIN mean ip_changed
309 if (request->error == DP_ERROR_IO_EAGAIN) {
310 request->error = DP_ERROR_NONE;
312 state = DP_STATE_CANCELED;
313 errorcode = request->error;
317 state = DP_STATE_FAILED;
318 errorcode = __change_error(info->err);
319 TRACE_ERROR("[FAILED][%d][%s] agent error:%d", request->id,
320 dp_print_errorcode(errorcode), info->err);
325 if (errorcode == DP_ERROR_NONE && info->saved_path != NULL) {
327 char *content_name = NULL;
329 str = strrchr(info->saved_path, '/');
332 content_name = dp_strdup(str);
334 if (request->file_size == 0) {// missed in download_cb
335 request->file_size = request->received_size;
336 if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_CONTENT_SIZE, (void *)&request->file_size, 0, 1, &errorcode) < 0)
337 TRACE_ERROR("id:%d failed to set content_size(%llu)", request->id, request->file_size);
339 // update contentname, savedpath
340 if (content_name != NULL) {
341 if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_CONTENT_NAME, (void *)content_name, 0, 2, &errorcode) < 0)
342 TRACE_ERROR("id:%d failed to set content_name", request->id);
344 if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_SAVED_PATH, (void *)info->saved_path, 0, 2, &errorcode) < 0)
345 TRACE_ERROR("id:%d failed to set saved_path", request->id);
347 /* update the received file size.
348 * The last received file size cannot update
349 * because of reducing update algorithm*/
350 if (request->progress_cb == 1) {
351 if (slot->client.notify < 0 ||
352 dp_notify_feedback(slot->client.notify, slot, request->id, DP_STATE_DOWNLOADING, DP_ERROR_NONE, request->received_size) < 0) {
353 TRACE_ERROR("id:%d disable progress callback by IO_ERROR", request->id);
354 request->progress_cb = 0;
359 request->state = state;
360 request->error = errorcode;
362 if (__dp_da_state_feedback(slot, request) < 0) {
363 TRACE_ERROR("id:%d check notify channel", request->id);
364 if (dp_cancel_agent_download_without_update(request->agent_id) < 0)
365 TRACE_ERROR("[fail][%d]cancel_agent", request->id);
367 if (request->noti_type == DP_NOTIFICATION_TYPE_COMPLETE_ONLY ||
368 request->noti_type == DP_NOTIFICATION_TYPE_ALL) {
369 if (dp_notification_manager_push_notification(slot, request, DP_NOTIFICATION) < 0)
370 TRACE_ERROR("failed to register notification for id:%d", request->id);
373 free(info->saved_path);
375 CLIENT_MUTEX_UNLOCK(&slot->mutex);
378 static void __paused_cb(int download_id, void *user_req_data, void *user_client_data)
380 dp_client_slots_fmt *slot = user_client_data;
381 dp_request_fmt *request = user_req_data;
382 if (slot == NULL || request == NULL) {
383 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), download_id);
386 dp_queue_manager_wake_up();
389 static void __download_info_cb(download_info_t *info, void *user_req_data, void *user_client_data)
392 TRACE_ERROR("check download info address");
395 dp_client_slots_fmt *slot = user_client_data;
396 dp_request_fmt *request = user_req_data;
397 if (slot == NULL || request == NULL) {
398 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), info->download_id);
399 free(info->content_name);
401 free(info->file_type);
402 free(info->tmp_saved_path);
406 CLIENT_MUTEX_LOCK(&slot->mutex);
407 if (__precheck_request(slot, request, info->download_id) < 0) {
408 TRACE_ERROR("error request agent_id:%d", info->download_id);
409 if (dp_cancel_agent_download(info->download_id) < 0)
410 TRACE_ERROR("failed to call cancel_download(%d)", info->download_id);
411 free(info->content_name);
413 free(info->file_type);
414 free(info->tmp_saved_path);
416 CLIENT_MUTEX_UNLOCK(&slot->mutex);
420 // update info before sending event
421 TRACE_SECURE_DEBUG("[DOWNLOAD][%d][%s]", request->id, info->tmp_saved_path);
422 if (info->tmp_saved_path != NULL) {
423 int errorcode = DP_ERROR_NONE;
424 if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_MIMETYPE, (void *)info->file_type, 0, 2, &errorcode) < 0)
425 TRACE_ERROR("id:%d failed to set mimetype", request->id);
426 if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_CONTENT_NAME, (void *)info->content_name, 0, 2, &errorcode) < 0)
427 TRACE_ERROR("id:%d failed to set contentname", request->id);
428 if (dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_TMP_SAVED_PATH, (void *)info->tmp_saved_path, 0, 2, &errorcode) < 0)
429 TRACE_ERROR("id:%d failed to set tmp_saved_path", request->id);
430 if (info->file_size > 0 && dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_CONTENT_SIZE, (void *)&(info->file_size), 0, 1, &errorcode) < 0)
431 TRACE_ERROR("id:%d failed to set file size", request->id);
432 if (info->etag && dp_db_replace_property(slot->client.dbhandle, request->id, DP_TABLE_DOWNLOAD, DP_DB_COL_ETAG, (void *)info->etag, 0, 2, &errorcode) < 0)
433 TRACE_ERROR("id:%d failed to set etag", request->id);
434 if (strncmp(DP_SDCARD_MNT_POINT, info->tmp_saved_path, strlen(DP_SDCARD_MNT_POINT)) != 0)
435 errorcode = __set_file_permission_to_client(slot, request, info->tmp_saved_path);
436 request->error = errorcode;
438 request->error = DP_ERROR_IO_ERROR;
441 if (request->error != DP_ERROR_NONE) {
442 request->state = DP_STATE_FAILED;
443 TRACE_ERROR("id:%d try to cancel(%d)", request->id, info->download_id);
444 if (dp_cancel_agent_download(request->agent_id) < 0) {
445 TRACE_ERROR("[fail][%d] cancel_agent:%d", request->id,
449 request->state = DP_STATE_DOWNLOADING;
450 request->file_size = info->file_size; // unsigned
451 TRACE_DEBUG("[STARTED] id:%d agentid:%d", request->id, info->download_id);
454 if (__dp_da_state_feedback(slot, request) < 0) {
455 TRACE_ERROR("id:%d check notify channel", request->id);
456 if (dp_cancel_agent_download(request->agent_id) < 0)
457 TRACE_ERROR("[fail][%d]cancel_agent", request->id);
460 if (request->noti_type == DP_NOTIFICATION_TYPE_ALL) {
461 if (dp_notification_manager_push_notification(slot, request, DP_NOTIFICATION_ONGOING_UPDATE) < 0)
462 TRACE_ERROR("failed to register notification for id:%d", request->id);
464 //get the mime type for dp notification
465 if (request->noti_type > DP_NOTIFICATION_TYPE_NONE)
466 request->content_type = __dp_get_content_type(info->file_type, info->tmp_saved_path);
468 free(info->content_name);
470 free(info->file_type);
471 free(info->tmp_saved_path);
473 CLIENT_MUTEX_UNLOCK(&slot->mutex);
476 static void __progress_cb(int download_id, unsigned long long received_size,
477 void *user_req_data, void *user_client_data)
479 dp_client_slots_fmt *slot = user_client_data;
480 dp_request_fmt *request = user_req_data;
481 if (slot == NULL || request == NULL) {
482 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), download_id);
485 CLIENT_MUTEX_LOCK(&slot->mutex);
487 if (CLIENT_MUTEX_TRYLOCK(&slot->mutex) != 0) {
488 TRACE_ERROR("slot busy agent_id:%d", download_id);
492 if (__precheck_request(slot, request, download_id) < 0) {
493 TRACE_ERROR("error request agent_id:%d", download_id);
494 if (dp_cancel_agent_download(download_id) < 0)
495 TRACE_ERROR("failed to call cancel_download(%d)", download_id);
496 CLIENT_MUTEX_UNLOCK(&slot->mutex);
500 // For resume case after pause, it change state from connecting to downloading
501 if (request->state == DP_STATE_CONNECTING) {
502 request->state = DP_STATE_DOWNLOADING;
503 if (__dp_da_state_feedback(slot, request) < 0) {
504 TRACE_ERROR("id:%d check notify channel", request->id);
505 if (dp_cancel_agent_download(request->agent_id) < 0)
506 TRACE_ERROR("[fail][%d]cancel_agent", request->id);
510 if (request->state == DP_STATE_DOWNLOADING) {
511 request->received_size = received_size;
512 time_t tt = time(NULL);
513 struct tm localTime ;
514 if (localtime_r(&tt, &localTime) == NULL) {
515 TRACE_ERROR("Error localtime_r");
516 CLIENT_MUTEX_UNLOCK(&slot->mutex);
519 // send event every 1 second.
520 if (request->progress_lasttime != localTime.tm_sec) {
521 request->progress_lasttime = localTime.tm_sec;
523 if (request->progress_cb == 1) {
524 if (slot->client.notify < 0 ||
525 dp_notify_feedback(slot->client.notify, slot,
526 request->id, DP_STATE_DOWNLOADING, DP_ERROR_NONE, received_size) < 0) {
527 // failed to read from socket // ignore this status
528 TRACE_ERROR("id:%d disable progress callback by IO_ERROR", request->id);
529 request->progress_cb = 0;
533 if (request->noti_type == DP_NOTIFICATION_TYPE_ALL) {
534 if (dp_notification_manager_push_notification(slot, request, DP_NOTIFICATION_ONGOING_PROGRESS) < 0)
535 TRACE_ERROR("failed to register notification for id:%d", request->id);
540 CLIENT_MUTEX_UNLOCK(&slot->mutex);
543 static int __dp_is_ambiguous_mime_type(const char *mime_type)
545 if (mime_type == NULL)
549 int listSize = sizeof(ambiguous_mime_type_list) / sizeof(const char *);
550 for (index = 0; index < listSize; index++) {
551 if (0 == strcmp(mime_type, ambiguous_mime_type_list[index])) {
552 TRACE_DEBUG("It is ambiguous");
559 static dp_content_type __dp_get_content_type(const char *mime, const char *file_path)
562 int type = DP_CONTENT_UNKNOWN;
563 char *temp_mime = NULL;
564 if (mime == NULL || strlen(mime) < 1)
565 return DP_CONTENT_UNKNOWN;
567 if ((file_path != NULL) && (strlen(file_path) > 0) &&
568 (__dp_is_ambiguous_mime_type(mime) == 0)) {
569 const char *ext = strrchr(file_path, '.');
571 TRACE_ERROR("File Extension is NULL");
574 mime_type_get_mime_type(ext + 1, &temp_mime);
576 if (temp_mime == NULL) {
577 temp_mime = (char *)calloc(1, DP_MAX_FILE_PATH_LEN);
578 if (temp_mime == NULL) {
579 TRACE_ERROR("Fail to call calloc");
582 strncpy(temp_mime, mime, DP_MAX_FILE_PATH_LEN - 1);
584 TRACE_SECURE_DEBUG("mime type [%s]", temp_mime);
586 /* Search a content type from mime table. */
587 for (i = 0; i < DP_MAX_MIME_TABLE_NUM; i++) {
588 if (strcmp(mime_table[i].mime, temp_mime) == 0) {
589 type = mime_table[i].content_type;
593 if (type == DP_CONTENT_UNKNOWN) {
594 const char *unaliased_mime = NULL;
595 /* unaliased_mimetype means representative mime among similar types */
596 unaliased_mime = xdg_mime_unalias_mime_type(temp_mime);
598 if (unaliased_mime != NULL) {
599 TRACE_SECURE_DEBUG("unaliased mime type[%s]", unaliased_mime);
600 if (strstr(unaliased_mime, "video/") != NULL)
601 type = DP_CONTENT_VIDEO;
602 else if (strstr(unaliased_mime, "audio/") != NULL)
603 type = DP_CONTENT_MUSIC;
604 else if (strstr(unaliased_mime, "image/") != NULL)
605 type = DP_CONTENT_IMAGE;
609 TRACE_DEBUG("type[%d]", type);
617 g_da_handle = dlopen(LIB_AGENT_PATH, RTLD_LAZY | RTLD_GLOBAL);
619 TRACE_ERROR("[dlopen] %s", dlerror());
621 return DP_ERROR_OUT_OF_MEMORY;
623 dlerror(); /* Clear any existing error */
625 *(void **) (&download_agent_init) = dlsym(g_da_handle, "da_init");
626 if (download_agent_init == NULL) {
627 TRACE_ERROR("[dlsym] da_init:%s", dlerror());
628 dlclose(g_da_handle);
630 return DP_ERROR_OUT_OF_MEMORY;
633 *(void **) (&download_agent_deinit) = dlsym(g_da_handle, "da_deinit");
634 if (download_agent_deinit == NULL) {
635 TRACE_ERROR("[dlsym] da_deinit:%s", dlerror());
636 dlclose(g_da_handle);
638 return DP_ERROR_OUT_OF_MEMORY;
641 *(void **) (&download_agent_is_alive) =
642 dlsym(g_da_handle, "da_is_valid_download_id");
643 if (download_agent_is_alive == NULL) {
644 TRACE_ERROR("[dlsym] da_is_valid_download_id:%s", dlerror());
645 dlclose(g_da_handle);
647 return DP_ERROR_OUT_OF_MEMORY;
650 *(void **) (&download_agent_suspend) =
651 dlsym(g_da_handle, "da_suspend_download");
652 if (download_agent_suspend == NULL) {
653 TRACE_ERROR("[dlsym] da_suspend_download:%s", dlerror());
654 dlclose(g_da_handle);
656 return DP_ERROR_OUT_OF_MEMORY;
659 *(void **) (&download_agent_resume) =
660 dlsym(g_da_handle, "da_resume_download");
661 if (download_agent_resume == NULL) {
662 TRACE_ERROR("[dlsym] da_resume_download:%s", dlerror());
663 dlclose(g_da_handle);
665 return DP_ERROR_OUT_OF_MEMORY;
668 // *(void **) (&download_agent_cancel) = dlsym(g_da_handle, "da_cancel_download_without_update");
669 *(void **) (&download_agent_cancel) =
670 dlsym(g_da_handle, "da_cancel_download");
671 if (download_agent_cancel == NULL) {
672 TRACE_ERROR("[dlsym] da_cancel_download:%s", dlerror());
673 dlclose(g_da_handle);
675 return DP_ERROR_OUT_OF_MEMORY;
678 *(void **) (&download_agent_start) =
679 dlsym(g_da_handle, "da_start_download");
680 if (download_agent_start == NULL) {
681 TRACE_ERROR("[dlsym] da_start_download:%s", dlerror());
682 dlclose(g_da_handle);
684 return DP_ERROR_OUT_OF_MEMORY;
687 *(void **) (&download_agent_cancel_without_update) = dlsym(g_da_handle, "da_cancel_download_without_update");
688 if (download_agent_cancel_without_update == NULL) {
689 TRACE_ERROR("[dlsym] da_cancel_download_without_update:%s", dlerror());
690 dlclose(g_da_handle);
692 return DP_ERROR_OUT_OF_MEMORY;
695 *(void **) (&download_agent_suspend_without_update) = dlsym(g_da_handle, "da_suspend_download_without_update");
696 if (download_agent_suspend_without_update == NULL) {
697 TRACE_ERROR("[dlsym] da_suspend_download_without_update:%s", dlerror());
698 dlclose(g_da_handle);
700 return DP_ERROR_OUT_OF_MEMORY;
704 da_ret = (*download_agent_init)();
705 if (da_ret != DA_RESULT_OK)
706 return DP_ERROR_OUT_OF_MEMORY;
707 return DP_ERROR_NONE;
710 void dp_deinit_agent()
712 if (g_da_handle != NULL) {
713 if (download_agent_deinit != NULL)
714 (*download_agent_deinit)();
716 // Do not unload a symbol file here.
717 //dlclose(g_da_handle);
718 //g_da_handle = NULL;
724 int dp_is_alive_download(int req_id)
729 if (download_agent_is_alive != NULL)
730 da_ret = (*download_agent_is_alive)(req_id);
736 int dp_cancel_agent_download(int req_id)
739 TRACE_ERROR("[NULL-CHECK] req_id");
742 if (dp_is_alive_download(req_id) == 0) {
743 TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
746 if (download_agent_cancel != NULL) {
747 if ((*download_agent_cancel)(req_id) == DA_RESULT_OK)
755 int dp_pause_agent_download(int req_id)
758 TRACE_ERROR("[NULL-CHECK] req_id");
761 if (dp_is_alive_download(req_id) == 0) {
762 TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
765 if (download_agent_suspend != NULL) {
766 if ((*download_agent_suspend)(req_id) == DA_RESULT_OK)
775 int dp_cancel_agent_download_without_update(int req_id)
778 TRACE_ERROR("[NULL-CHECK] req_id");
781 if (dp_is_alive_download(req_id) == 0) {
782 TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
785 if (download_agent_cancel_without_update != NULL) {
786 if ((*download_agent_cancel_without_update)(req_id) == DA_RESULT_OK)
794 int dp_pause_agent_download_without_update(int req_id)
797 TRACE_ERROR("[NULL-CHECK] req_id");
800 if (dp_is_alive_download(req_id) == 0) {
801 TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
804 if (download_agent_suspend_without_update != NULL) {
805 if ((*download_agent_suspend_without_update)(req_id) == DA_RESULT_OK)
814 int dp_start_agent_download(void *slot, void *request)
818 req_data_t *req_data = NULL;
820 dp_client_slots_fmt *base_slot = slot;
821 dp_request_fmt *base_req = request;
823 if (slot == NULL || request == NULL) {
824 TRACE_ERROR("check slot or request address");
825 return DP_ERROR_INVALID_PARAMETER;
835 req_data = (req_data_t *)calloc(1, sizeof(req_data_t));
836 if (req_data == NULL) {
837 TRACE_ERROR("[ERROR] calloc");
838 return DP_ERROR_OUT_OF_MEMORY;
841 int errorcode = DP_ERROR_NONE;
845 char *destination = NULL;
846 char *tmp_saved_path = NULL;
847 char *user_tmp_file_path = NULL;
848 char *filename = NULL;
850 int user_network_bonding = 0;
852 if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_REQUEST, DP_DB_COL_URL, (unsigned char **)&url, &length, &errorcode) < 0 ||
855 if (errorcode == DP_ERROR_NO_DATA) {
856 TRACE_ERROR("url id:%d NO_DATA", base_req->id);
857 return DP_ERROR_INVALID_URL;
859 TRACE_ERROR("url id:%d DISK_BUSY", base_req->id);
860 return DP_ERROR_DISK_BUSY;
863 if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_REQUEST, DP_DB_COL_PROXY, (unsigned char **)&proxy, &length, &errorcode) < 0 ||
865 TRACE_DEBUG("proxy id:%d NO_DATA", base_req->id);
866 req_data->proxy = NULL;
868 req_data->proxy = proxy;
870 if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_REQUEST, DP_DB_COL_TEMP_FILE_PATH, (unsigned char **)&user_tmp_file_path, &length, &errorcode) < 0 ||
871 user_tmp_file_path == NULL) {
872 TRACE_DEBUG("user_tmp_file_path id:%d NO_DATA", base_req->id);
875 if (user_tmp_file_path != NULL)
876 req_data->temp_file_path = user_tmp_file_path;
878 if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_REQUEST, DP_DB_COL_FILENAME, (unsigned char **)&filename, &length, &errorcode) < 0 ||
880 TRACE_DEBUG("filename id:%d NO_DATA", base_req->id);
882 req_data->file_name = filename;
883 if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_REQUEST, DP_DB_COL_DESTINATION, (unsigned char **)&destination, &length, &errorcode) < 0 ||
884 destination == NULL) {
885 TRACE_DEBUG("destination id:%d NO_DATA", base_req->id);
887 req_data->install_path = destination;
888 if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_DOWNLOAD, DP_DB_COL_TMP_SAVED_PATH, (unsigned char **)&tmp_saved_path, &length, &errorcode) < 0 ||
889 tmp_saved_path == NULL) {
890 TRACE_DEBUG("tmp_saved_path id:%d NO_DATA", base_req->id);
894 if (tmp_saved_path != NULL) {
895 if (dp_db_get_property_string(base_slot->client.dbhandle, base_req->id, DP_TABLE_DOWNLOAD, DP_DB_COL_ETAG, (unsigned char **)&etag, &length, &errorcode) < 0 ||
897 TRACE_DEBUG("etag id:%d NO_DATA", base_req->id);
900 TRACE_DEBUG("try to resume id:%d", base_req->id);
901 req_data->etag = etag;
902 req_data->temp_file_path = tmp_saved_path;
904 /* FIXME later : It is better to handle the unlink function in download agaent module
905 * or in upload the request data to memory after the download provider process is restarted */
906 TRACE_SECURE_INFO("try to restart id:%d remove tmp file:%s",
907 base_req->id, tmp_saved_path);
908 if (dp_is_file_exist(tmp_saved_path) == 0) {
909 if (unlink(tmp_saved_path) != 0)
910 TRACE_ERROR("failed to remove file id:%d", base_req->id);
914 if (dp_db_get_property_int(base_slot->client.dbhandle, base_req->id, DP_TABLE_REQUEST, DP_DB_COL_NETWORK_BONDING, (int *)&user_network_bonding, &errorcode) < 0 ||
915 user_network_bonding < 0) {
916 TRACE_DEBUG("unable to get network bonding value for id:%d", base_req->id);
918 req_data->network_bonding = user_network_bonding;
920 req_data->disable_verify_host = base_req->disable_verify_host;
921 req_data->pkg_name = base_slot->pkgname;
923 // get headers list from header table(DB)
924 int headers_count = dp_db_check_duplicated_int(base_slot->client.dbhandle, DP_TABLE_HEADERS, DP_DB_COL_ID, base_req->id, &errorcode);
925 if (headers_count > 0) {
926 req_data->request_header = calloc(headers_count, sizeof(char *));
927 if (req_data->request_header != NULL) {
928 headers_count = dp_db_get_http_headers_list(base_slot->client.dbhandle, base_req->id, (char **)req_data->request_header, &errorcode);
929 if (headers_count > 0)
930 req_data->request_header_count = headers_count;
934 req_data->user_client_data = (void *)slot;
935 req_data->user_req_data = (void *)request;
937 // call start API of agent lib
938 if (download_agent_start != NULL)
939 da_ret = (*download_agent_start)(url, req_data, &da_cb, &req_dl_id);
940 if (req_data->request_header_count > 0) {
943 len = req_data->request_header_count;
944 if (req_data->request_header != NULL) {
945 for (i = 0; i < len; i++)
946 free((void *)(req_data->request_header[i]));
948 free(req_data->request_header);
952 free(tmp_saved_path);
953 free(user_tmp_file_path);
958 if (da_ret == DA_RESULT_OK) {
959 TRACE_DEBUG("request id :%d SUCCESS agent_id:%d", base_req->id, req_dl_id);
960 base_req->agent_id = req_dl_id;
962 return __change_error(da_ret);
965 int dp_resume_agent_download(int req_id)
969 TRACE_ERROR("[NULL-CHECK] req_id");
970 return DP_ERROR_INVALID_PARAMETER;
972 if (download_agent_resume != NULL)
973 da_ret = (*download_agent_resume)(req_id);
974 if (da_ret == DA_RESULT_OK)
975 return DP_ERROR_NONE;
976 else if (da_ret == DA_ERR_INVALID_STATE)
977 return DP_ERROR_INVALID_STATE;
978 return __change_error(da_ret);