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_MAX_FILE_PATH_LEN 256
52 #define DP_MAX_MIME_TABLE_NUM 15
59 const char *ambiguous_mime_type_list[] = {
61 "application/octet-stream"
64 mime_table_type mime_table[] = {
66 {"application/pdf", DP_CONTENT_PDF},
68 {"application/msword", DP_CONTENT_WORD},
69 {"application/vnd.openxmlformats-officedocument.wordprocessingml.document", DP_CONTENT_WORD},
71 {"application/vnd.ms-powerpoint", DP_CONTENT_PPT},
72 {"application/vnd.openxmlformats-officedocument.presentationml.presentation", DP_CONTENT_PPT},
74 {"application/vnd.ms-excel", DP_CONTENT_EXCEL},
75 {"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", DP_CONTENT_EXCEL},
77 {"text/html", DP_CONTENT_HTML},
79 {"text/txt", DP_CONTENT_TEXT},
80 {"text/plain", DP_CONTENT_TEXT},
82 {"application/vnd.oma.drm.content", DP_CONTENT_SD_DRM},
83 {"application/vnd.oma.drm.message", DP_CONTENT_DRM},
84 {"application/x-shockwave-flash", DP_CONTENT_FLASH},
85 {"application/vnd.tizen.package", DP_CONTENT_TPK},
86 {"text/calendar", DP_CONTENT_VCAL},
89 static void *g_da_handle = NULL;
90 static int (*download_agent_init)(void) = NULL; // int da_init(da_client_cb_t *da_client_callback);
91 static int (*download_agent_deinit)(void) = NULL; // int da_deinit();
92 static int (*download_agent_is_alive)(int) = NULL; // int da_is_valid_download_id(int download_id);
93 static int (*download_agent_suspend)(int) = NULL; // int da_suspend_download(int download_id);
94 static int (*download_agent_resume)(int) = NULL; // int da_resume_download(int download_id);
95 static int (*download_agent_cancel)(int) = NULL; // int da_cancel_download(int download_id);
96 static int (*download_agent_suspend_without_update)(int) = NULL; // int da_suspend_download_without_update(int download_id);
97 static int (*download_agent_cancel_without_update)(int) = NULL; // int da_cancel_download_without_update(int download_id);
98 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);
99 static dp_content_type __dp_get_content_type(const char *mime, const char *file_path);
101 static int __change_error(int err)
103 int ret = DP_ERROR_NONE;
108 case DA_ERR_INVALID_ARGUMENT:
109 ret = DP_ERROR_INVALID_PARAMETER;
111 case DA_ERR_FAIL_TO_MEMALLOC:
112 ret = DP_ERROR_OUT_OF_MEMORY;
114 case DA_ERR_UNREACHABLE_SERVER:
115 ret = DP_ERROR_NETWORK_UNREACHABLE;
117 case DA_ERR_HTTP_TIMEOUT:
118 ret = DP_ERROR_CONNECTION_TIMED_OUT;
120 case DA_ERR_DISK_FULL:
121 ret = DP_ERROR_NO_SPACE;
123 case DA_ERR_INVALID_STATE:
124 ret = DP_ERROR_INVALID_STATE;
126 case DA_ERR_NETWORK_FAIL:
127 ret = DP_ERROR_NETWORK_ERROR;
129 case DA_ERR_CONNECTION_FAIL:
130 case DA_ERR_NETWORK_UNAUTHORIZED:
131 ret = DP_ERROR_CONNECTION_FAILED;
133 case DA_ERR_INVALID_URL:
134 ret = DP_ERROR_INVALID_URL;
136 case DA_ERR_INVALID_INSTALL_PATH:
137 ret = DP_ERROR_INVALID_DESTINATION;
139 case DA_ERR_ALREADY_MAX_DOWNLOAD:
140 ret = DP_ERROR_TOO_MANY_DOWNLOADS;
142 case DA_ERR_FAIL_TO_CREATE_THREAD:
143 case DA_ERR_FAIL_TO_ACCESS_FILE:
145 ret = DP_ERROR_IO_ERROR;
151 static int __dp_da_state_feedback(dp_client_slots_fmt *slot, dp_request_fmt *request)
153 if (slot == NULL || request == NULL) {
154 TRACE_ERROR("check address");
155 return -1; // try cancel
158 TRACE_INFO("[INFO][%d] state:%s error:%s", request->id,
159 dp_print_state(request->state), dp_print_errorcode(request->error));
161 int errorcode = DP_ERROR_NONE;
162 if (dp_db_update_logging(slot->client.dbhandle, request->id,
163 request->state, request->error, &errorcode) < 0) {
164 TRACE_ERROR("logging failure id:%d error:%d", request->id, errorcode);
165 return -1; // try cancel
168 request->access_time = (int)time(NULL);
170 if (request->state_cb == 1) {
171 if (slot->client.notify < 0 ||
172 dp_notify_feedback(slot->client.notify, slot, request->id, request->state, request->error, 0) < 0) {
173 TRACE_ERROR("id:%d disable state callback by IO_ERROR", request->id);
174 request->state_cb = 0;
181 static int __precheck_request(dp_client_slots_fmt* slot, dp_request_fmt *request, int agentid)
183 if (request == NULL) {
184 TRACE_ERROR("null-check req_id:%d", agentid);
188 dp_client_fmt *client = &slot->client;
190 for (dp_request_fmt *req = client->requests; req; req = req->next) {
191 if (req == request) {
192 if (request->id < 0 || (request->agent_id != agentid)) {
193 TRACE_ERROR("id-check request_id:%d agent_id:%d req_id:%d",
194 request->id, request->agent_id, agentid);
203 static int __set_file_permission_to_client(dp_client_slots_fmt *slot, dp_request_fmt *request, char *saved_path)
205 if (slot == NULL || request == NULL) {
206 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), (request == NULL ? 0 : request->agent_id));
207 return DP_ERROR_INVALID_PARAMETER;
208 } else if (saved_path == NULL) {
209 TRACE_ERROR("check null saved path");
210 return DP_ERROR_INVALID_PARAMETER;
213 struct stat lstat_info;
214 struct stat fstat_info;
216 int errorcode = DP_ERROR_NONE;
217 dp_credential cred = slot->credential;
218 if (lstat(saved_path, &lstat_info) != -1) {
219 fd = open(saved_path, O_RDONLY);
221 if (fstat(fd, &fstat_info) != -1) {
222 if (lstat_info.st_mode == fstat_info.st_mode &&
223 lstat_info.st_ino == fstat_info.st_ino &&
224 lstat_info.st_dev == fstat_info.st_dev) {
226 if (strncmp(saved_path, "/opt/media/", 11) != 0) {
227 if (fchown(fd, cred.uid, cred.gid) != 0) {
228 TRACE_ERROR("[ERROR][%d] permission user:%d group:%d",
229 request->id, cred.uid, cred.gid);
230 errorcode = DP_ERROR_PERMISSION_DENIED;
234 TRACE_ERROR("fstat & lstat info have not matched");
235 errorcode = DP_ERROR_PERMISSION_DENIED;
238 TRACE_ERROR("fstat call failed");
239 errorcode = DP_ERROR_PERMISSION_DENIED;
243 TRACE_SECURE_ERROR("open failed for file : %s", saved_path);
244 errorcode = DP_ERROR_IO_ERROR;
247 TRACE_ERROR("lstat call failed");
248 errorcode = DP_ERROR_PERMISSION_DENIED;
253 static void __finished_cb(finished_info_t *info, void *user_req_data,
254 void *user_client_data)
257 TRACE_ERROR("check download info address");
260 dp_client_slots_fmt *slot = user_client_data;
261 dp_request_fmt *request = user_req_data;
262 if (slot == NULL || request == NULL) {
263 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), info->download_id);
265 free(info->saved_path);
269 CLIENT_MUTEX_LOCK(&slot->mutex);
270 if (__precheck_request(slot, request, info->download_id) < 0) {
271 TRACE_ERROR("error request agent_id:%d", info->download_id);
272 if (dp_cancel_agent_download(info->download_id) < 0)
273 TRACE_ERROR("failed to call cancel_download(%d)", info->download_id);
275 free(info->saved_path);
277 CLIENT_MUTEX_UNLOCK(&slot->mutex);
281 int state = DP_STATE_NONE;
282 int errorcode = DP_ERROR_NONE;
284 if (info->http_status > 0) {
285 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)
286 TRACE_ERROR("id:%d failed to set http_status(%d)", request->id, info->http_status);
289 TRACE_SECURE_DEBUG("[FINISH][%d][%s]", request->id, info->saved_path);
290 if (info->err == DA_RESULT_OK) {
291 if (info->saved_path != NULL) {
292 if (strncmp(DP_SDCARD_MNT_POINT, info->saved_path, strlen(DP_SDCARD_MNT_POINT)) != 0)
293 errorcode = __set_file_permission_to_client(slot, request, info->saved_path);
295 TRACE_ERROR("[ERROR][%d] No SavedPath", request->id);
296 errorcode = DP_ERROR_INVALID_DESTINATION;
298 if (errorcode == DP_ERROR_NONE)
299 state = DP_STATE_COMPLETED;
301 state = DP_STATE_FAILED;
303 if (info->err == DA_RESULT_USER_CANCELED) {
305 TRACE_INFO("[CANCELED][%d]", request->id);
307 // if state is canceled and error is DP_ERROR_IO_EAGAIN mean ip_changed
308 if (request->error == DP_ERROR_IO_EAGAIN) {
309 request->error = DP_ERROR_NONE;
311 state = DP_STATE_CANCELED;
312 errorcode = request->error;
316 state = DP_STATE_FAILED;
317 errorcode = __change_error(info->err);
318 TRACE_ERROR("[FAILED][%d][%s] agent error:%d", request->id,
319 dp_print_errorcode(errorcode), info->err);
324 if (errorcode == DP_ERROR_NONE && info->saved_path != NULL) {
326 char *content_name = NULL;
328 str = strrchr(info->saved_path, '/');
331 content_name = dp_strdup(str);
333 if (request->file_size == 0) {// missed in download_cb
334 request->file_size = request->received_size;
335 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)
336 TRACE_ERROR("id:%d failed to set content_size(%llu)", request->id, request->file_size);
338 // update contentname, savedpath
339 if (content_name != NULL) {
340 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)
341 TRACE_ERROR("id:%d failed to set content_name", request->id);
343 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)
344 TRACE_ERROR("id:%d failed to set saved_path", request->id);
346 /* update the received file size.
347 * The last received file size cannot update
348 * because of reducing update algorithm*/
349 if (request->progress_cb == 1) {
350 if (slot->client.notify < 0 ||
351 dp_notify_feedback(slot->client.notify, slot, request->id, DP_STATE_DOWNLOADING, DP_ERROR_NONE, request->received_size) < 0) {
352 TRACE_ERROR("id:%d disable progress callback by IO_ERROR", request->id);
353 request->progress_cb = 0;
358 request->state = state;
359 request->error = errorcode;
361 if (__dp_da_state_feedback(slot, request) < 0) {
362 TRACE_ERROR("id:%d check notify channel", request->id);
363 if (dp_cancel_agent_download_without_update(request->agent_id) < 0)
364 TRACE_ERROR("[fail][%d]cancel_agent", request->id);
366 if (request->noti_type == DP_NOTIFICATION_TYPE_COMPLETE_ONLY ||
367 request->noti_type == DP_NOTIFICATION_TYPE_ALL) {
368 if (dp_notification_manager_push_notification(slot, request, DP_NOTIFICATION) < 0)
369 TRACE_ERROR("failed to register notification for id:%d", request->id);
372 free(info->saved_path);
374 CLIENT_MUTEX_UNLOCK(&slot->mutex);
377 static void __paused_cb(int download_id, void *user_req_data, void *user_client_data)
379 dp_client_slots_fmt *slot = user_client_data;
380 dp_request_fmt *request = user_req_data;
381 if (slot == NULL || request == NULL) {
382 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), download_id);
385 dp_queue_manager_wake_up();
388 static void __download_info_cb(download_info_t *info, void *user_req_data, void *user_client_data)
391 TRACE_ERROR("check download info address");
394 dp_client_slots_fmt *slot = user_client_data;
395 dp_request_fmt *request = user_req_data;
396 if (slot == NULL || request == NULL) {
397 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), info->download_id);
398 free(info->content_name);
400 free(info->file_type);
401 free(info->tmp_saved_path);
405 CLIENT_MUTEX_LOCK(&slot->mutex);
406 if (__precheck_request(slot, request, info->download_id) < 0) {
407 TRACE_ERROR("error request agent_id:%d", info->download_id);
408 if (dp_cancel_agent_download(info->download_id) < 0)
409 TRACE_ERROR("failed to call cancel_download(%d)", info->download_id);
410 free(info->content_name);
412 free(info->file_type);
413 free(info->tmp_saved_path);
415 CLIENT_MUTEX_UNLOCK(&slot->mutex);
419 // update info before sending event
420 TRACE_SECURE_DEBUG("[DOWNLOAD][%d][%s]", request->id, info->tmp_saved_path);
421 if (info->tmp_saved_path != NULL) {
422 int errorcode = DP_ERROR_NONE;
423 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)
424 TRACE_ERROR("id:%d failed to set mimetype", request->id);
425 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)
426 TRACE_ERROR("id:%d failed to set contentname", request->id);
427 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)
428 TRACE_ERROR("id:%d failed to set tmp_saved_path", request->id);
429 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)
430 TRACE_ERROR("id:%d failed to set file size", request->id);
431 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)
432 TRACE_ERROR("id:%d failed to set etag", request->id);
433 if (strncmp(DP_SDCARD_MNT_POINT, info->tmp_saved_path, strlen(DP_SDCARD_MNT_POINT)) != 0)
434 errorcode = __set_file_permission_to_client(slot, request, info->tmp_saved_path);
435 request->error = errorcode;
437 request->error = DP_ERROR_IO_ERROR;
440 if (request->error != DP_ERROR_NONE) {
441 request->state = DP_STATE_FAILED;
442 TRACE_ERROR("id:%d try to cancel(%d)", request->id, info->download_id);
443 if (dp_cancel_agent_download(request->agent_id) < 0) {
444 TRACE_ERROR("[fail][%d] cancel_agent:%d", request->id,
448 request->state = DP_STATE_DOWNLOADING;
449 request->file_size = info->file_size; // unsigned
450 TRACE_DEBUG("[STARTED] id:%d agentid:%d", request->id, info->download_id);
453 if (__dp_da_state_feedback(slot, request) < 0) {
454 TRACE_ERROR("id:%d check notify channel", request->id);
455 if (dp_cancel_agent_download(request->agent_id) < 0)
456 TRACE_ERROR("[fail][%d]cancel_agent", request->id);
459 if (request->noti_type == DP_NOTIFICATION_TYPE_ALL) {
460 if (dp_notification_manager_push_notification(slot, request, DP_NOTIFICATION_ONGOING_UPDATE) < 0)
461 TRACE_ERROR("failed to register notification for id:%d", request->id);
463 //get the mime type for dp notification
464 if (request->noti_type > DP_NOTIFICATION_TYPE_NONE)
465 request->content_type = __dp_get_content_type(info->file_type, info->tmp_saved_path);
467 free(info->content_name);
469 free(info->file_type);
470 free(info->tmp_saved_path);
472 CLIENT_MUTEX_UNLOCK(&slot->mutex);
475 static void __progress_cb(int download_id, unsigned long long received_size,
476 void *user_req_data, void *user_client_data)
478 dp_client_slots_fmt *slot = user_client_data;
479 dp_request_fmt *request = user_req_data;
480 if (slot == NULL || request == NULL) {
481 TRACE_ERROR("check address slot:%p request:%p id:%d agentid:%d", slot, request, (request == NULL ? 0 : request->id), download_id);
484 CLIENT_MUTEX_LOCK(&slot->mutex);
486 if (CLIENT_MUTEX_TRYLOCK(&slot->mutex) != 0) {
487 TRACE_ERROR("slot busy agent_id:%d", download_id);
491 if (__precheck_request(slot, request, download_id) < 0) {
492 TRACE_ERROR("error request agent_id:%d", download_id);
493 if (dp_cancel_agent_download(download_id) < 0)
494 TRACE_ERROR("failed to call cancel_download(%d)", download_id);
495 CLIENT_MUTEX_UNLOCK(&slot->mutex);
499 // For resume case after pause, it change state from connecting to downloading
500 if (request->state == DP_STATE_CONNECTING) {
501 request->state = DP_STATE_DOWNLOADING;
502 if (__dp_da_state_feedback(slot, request) < 0) {
503 TRACE_ERROR("id:%d check notify channel", request->id);
504 if (dp_cancel_agent_download(request->agent_id) < 0)
505 TRACE_ERROR("[fail][%d]cancel_agent", request->id);
509 if (request->state == DP_STATE_DOWNLOADING) {
510 request->received_size = received_size;
511 time_t tt = time(NULL);
512 struct tm localTime ;
513 if (localtime_r(&tt, &localTime) == NULL) {
514 TRACE_ERROR("Error localtime_r");
515 CLIENT_MUTEX_UNLOCK(&slot->mutex);
518 // send event every 1 second.
519 if (request->progress_lasttime != localTime.tm_sec) {
520 request->progress_lasttime = localTime.tm_sec;
522 if (request->progress_cb == 1) {
523 if (slot->client.notify < 0 ||
524 dp_notify_feedback(slot->client.notify, slot,
525 request->id, DP_STATE_DOWNLOADING, DP_ERROR_NONE, received_size) < 0) {
526 // failed to read from socket // ignore this status
527 TRACE_ERROR("id:%d disable progress callback by IO_ERROR", request->id);
528 request->progress_cb = 0;
532 if (request->noti_type == DP_NOTIFICATION_TYPE_ALL) {
533 if (dp_notification_manager_push_notification(slot, request, DP_NOTIFICATION_ONGOING_PROGRESS) < 0)
534 TRACE_ERROR("failed to register notification for id:%d", request->id);
539 CLIENT_MUTEX_UNLOCK(&slot->mutex);
542 static int __dp_is_ambiguous_mime_type(const char *mime_type)
544 if (mime_type == NULL)
548 int listSize = sizeof(ambiguous_mime_type_list) / sizeof(const char *);
549 for (index = 0; index < listSize; index++) {
550 if (0 == strcmp(mime_type, ambiguous_mime_type_list[index])) {
551 TRACE_DEBUG("It is ambiguous");
558 static dp_content_type __dp_get_content_type(const char *mime, const char *file_path)
561 int type = DP_CONTENT_UNKNOWN;
562 char *temp_mime = NULL;
563 if (mime == NULL || strlen(mime) < 1)
564 return DP_CONTENT_UNKNOWN;
566 if ((file_path != NULL) && (strlen(file_path) > 0) &&
567 (__dp_is_ambiguous_mime_type(mime) == 0)) {
568 const char *ext = strrchr(file_path, '.');
570 TRACE_ERROR("File Extension is NULL");
573 mime_type_get_mime_type(ext + 1, &temp_mime);
575 if (temp_mime == NULL) {
576 temp_mime = (char *)calloc(1, DP_MAX_FILE_PATH_LEN);
577 if (temp_mime == NULL) {
578 TRACE_ERROR("Fail to call calloc");
581 strncpy(temp_mime, mime, DP_MAX_FILE_PATH_LEN - 1);
583 TRACE_SECURE_DEBUG("mime type [%s]", temp_mime);
585 /* Search a content type from mime table. */
586 for (i = 0; i < DP_MAX_MIME_TABLE_NUM; i++) {
587 if (strcmp(mime_table[i].mime, temp_mime) == 0) {
588 type = mime_table[i].content_type;
592 if (type == DP_CONTENT_UNKNOWN) {
593 const char *unaliased_mime = NULL;
594 /* unaliased_mimetype means representative mime among similar types */
595 unaliased_mime = xdg_mime_unalias_mime_type(temp_mime);
597 if (unaliased_mime != NULL) {
598 TRACE_SECURE_DEBUG("unaliased mime type[%s]", unaliased_mime);
599 if (strstr(unaliased_mime, "video/") != NULL)
600 type = DP_CONTENT_VIDEO;
601 else if (strstr(unaliased_mime, "audio/") != NULL)
602 type = DP_CONTENT_MUSIC;
603 else if (strstr(unaliased_mime, "image/") != NULL)
604 type = DP_CONTENT_IMAGE;
608 TRACE_DEBUG("type[%d]", type);
616 g_da_handle = dlopen(LIB_AGENT_PATH, RTLD_LAZY | RTLD_GLOBAL);
618 TRACE_ERROR("[dlopen] %s", dlerror());
620 return DP_ERROR_OUT_OF_MEMORY;
622 dlerror(); /* Clear any existing error */
624 *(void **) (&download_agent_init) = dlsym(g_da_handle, "da_init");
625 if (download_agent_init == NULL) {
626 TRACE_ERROR("[dlsym] da_init:%s", dlerror());
627 dlclose(g_da_handle);
629 return DP_ERROR_OUT_OF_MEMORY;
632 *(void **) (&download_agent_deinit) = dlsym(g_da_handle, "da_deinit");
633 if (download_agent_deinit == NULL) {
634 TRACE_ERROR("[dlsym] da_deinit:%s", dlerror());
635 dlclose(g_da_handle);
637 return DP_ERROR_OUT_OF_MEMORY;
640 *(void **) (&download_agent_is_alive) =
641 dlsym(g_da_handle, "da_is_valid_download_id");
642 if (download_agent_is_alive == NULL) {
643 TRACE_ERROR("[dlsym] da_is_valid_download_id:%s", dlerror());
644 dlclose(g_da_handle);
646 return DP_ERROR_OUT_OF_MEMORY;
649 *(void **) (&download_agent_suspend) =
650 dlsym(g_da_handle, "da_suspend_download");
651 if (download_agent_suspend == NULL) {
652 TRACE_ERROR("[dlsym] da_suspend_download:%s", dlerror());
653 dlclose(g_da_handle);
655 return DP_ERROR_OUT_OF_MEMORY;
658 *(void **) (&download_agent_resume) =
659 dlsym(g_da_handle, "da_resume_download");
660 if (download_agent_resume == NULL) {
661 TRACE_ERROR("[dlsym] da_resume_download:%s", dlerror());
662 dlclose(g_da_handle);
664 return DP_ERROR_OUT_OF_MEMORY;
667 // *(void **) (&download_agent_cancel) = dlsym(g_da_handle, "da_cancel_download_without_update");
668 *(void **) (&download_agent_cancel) =
669 dlsym(g_da_handle, "da_cancel_download");
670 if (download_agent_cancel == NULL) {
671 TRACE_ERROR("[dlsym] da_cancel_download:%s", dlerror());
672 dlclose(g_da_handle);
674 return DP_ERROR_OUT_OF_MEMORY;
677 *(void **) (&download_agent_start) =
678 dlsym(g_da_handle, "da_start_download");
679 if (download_agent_start == NULL) {
680 TRACE_ERROR("[dlsym] da_start_download:%s", dlerror());
681 dlclose(g_da_handle);
683 return DP_ERROR_OUT_OF_MEMORY;
686 *(void **) (&download_agent_cancel_without_update) = dlsym(g_da_handle, "da_cancel_download_without_update");
687 if (download_agent_cancel_without_update == NULL) {
688 TRACE_ERROR("[dlsym] da_cancel_download_without_update:%s", dlerror());
689 dlclose(g_da_handle);
691 return DP_ERROR_OUT_OF_MEMORY;
694 *(void **) (&download_agent_suspend_without_update) = dlsym(g_da_handle, "da_suspend_download_without_update");
695 if (download_agent_suspend_without_update == NULL) {
696 TRACE_ERROR("[dlsym] da_suspend_download_without_update:%s", dlerror());
697 dlclose(g_da_handle);
699 return DP_ERROR_OUT_OF_MEMORY;
703 da_ret = (*download_agent_init)();
704 if (da_ret != DA_RESULT_OK)
705 return DP_ERROR_OUT_OF_MEMORY;
706 return DP_ERROR_NONE;
709 void dp_deinit_agent()
711 if (g_da_handle != NULL) {
712 if (download_agent_deinit != NULL)
713 (*download_agent_deinit)();
715 dlclose(g_da_handle);
722 int dp_is_alive_download(int req_id)
727 if (download_agent_is_alive != NULL)
728 da_ret = (*download_agent_is_alive)(req_id);
734 int dp_cancel_agent_download(int req_id)
737 TRACE_ERROR("[NULL-CHECK] req_id");
740 if (dp_is_alive_download(req_id) == 0) {
741 TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
744 if (download_agent_cancel != NULL) {
745 if ((*download_agent_cancel)(req_id) == DA_RESULT_OK)
753 int dp_pause_agent_download(int req_id)
756 TRACE_ERROR("[NULL-CHECK] req_id");
759 if (dp_is_alive_download(req_id) == 0) {
760 TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
763 if (download_agent_suspend != NULL) {
764 if ((*download_agent_suspend)(req_id) == DA_RESULT_OK)
773 int dp_cancel_agent_download_without_update(int req_id)
776 TRACE_ERROR("[NULL-CHECK] req_id");
779 if (dp_is_alive_download(req_id) == 0) {
780 TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
783 if (download_agent_cancel_without_update != NULL) {
784 if ((*download_agent_cancel_without_update)(req_id) == DA_RESULT_OK)
792 int dp_pause_agent_download_without_update(int req_id)
795 TRACE_ERROR("[NULL-CHECK] req_id");
798 if (dp_is_alive_download(req_id) == 0) {
799 TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
802 if (download_agent_suspend_without_update != NULL) {
803 if ((*download_agent_suspend_without_update)(req_id) == DA_RESULT_OK)
812 int dp_start_agent_download(void *slot, void *request)
816 req_data_t *req_data = NULL;
818 dp_client_slots_fmt *base_slot = slot;
819 dp_request_fmt *base_req = request;
821 if (slot == NULL || request == NULL) {
822 TRACE_ERROR("check slot or request address");
823 return DP_ERROR_INVALID_PARAMETER;
833 req_data = (req_data_t *)calloc(1, sizeof(req_data_t));
834 if (req_data == NULL) {
835 TRACE_ERROR("[ERROR] calloc");
836 return DP_ERROR_OUT_OF_MEMORY;
839 int errorcode = DP_ERROR_NONE;
843 char *destination = NULL;
844 char *tmp_saved_path = NULL;
845 char *user_tmp_file_path = NULL;
846 char *filename = NULL;
848 int user_network_bonding = 0;
850 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 ||
853 if (errorcode == DP_ERROR_NO_DATA) {
854 TRACE_ERROR("url id:%d NO_DATA", base_req->id);
855 return DP_ERROR_INVALID_URL;
857 TRACE_ERROR("url id:%d DISK_BUSY", base_req->id);
858 return DP_ERROR_DISK_BUSY;
861 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 ||
863 TRACE_DEBUG("proxy id:%d NO_DATA", base_req->id);
864 req_data->proxy = NULL;
866 req_data->proxy = proxy;
868 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 ||
869 user_tmp_file_path == NULL) {
870 TRACE_DEBUG("user_tmp_file_path id:%d NO_DATA", base_req->id);
873 if (user_tmp_file_path != NULL)
874 req_data->temp_file_path = user_tmp_file_path;
876 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 ||
878 TRACE_DEBUG("filename id:%d NO_DATA", base_req->id);
880 req_data->file_name = filename;
881 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 ||
882 destination == NULL) {
883 TRACE_DEBUG("destination id:%d NO_DATA", base_req->id);
885 req_data->install_path = destination;
886 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 ||
887 tmp_saved_path == NULL) {
888 TRACE_DEBUG("tmp_saved_path id:%d NO_DATA", base_req->id);
892 if (tmp_saved_path != NULL) {
893 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 ||
895 TRACE_DEBUG("etag id:%d NO_DATA", base_req->id);
898 TRACE_DEBUG("try to resume id:%d", base_req->id);
899 req_data->etag = etag;
900 req_data->temp_file_path = tmp_saved_path;
902 /* FIXME later : It is better to handle the unlink function in download agaent module
903 * or in upload the request data to memory after the download provider process is restarted */
904 TRACE_SECURE_INFO("try to restart id:%d remove tmp file:%s",
905 base_req->id, tmp_saved_path);
906 if (dp_is_file_exist(tmp_saved_path) == 0) {
907 if (unlink(tmp_saved_path) != 0)
908 TRACE_ERROR("failed to remove file id:%d", base_req->id);
912 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 ||
913 user_network_bonding < 0) {
914 TRACE_DEBUG("unable to get network bonding value for id:%d", base_req->id);
916 req_data->network_bonding = user_network_bonding;
918 req_data->pkg_name = base_slot->pkgname;
920 // get headers list from header table(DB)
921 int headers_count = dp_db_check_duplicated_int(base_slot->client.dbhandle, DP_TABLE_HEADERS, DP_DB_COL_ID, base_req->id, &errorcode);
922 if (headers_count > 0) {
923 req_data->request_header = calloc(headers_count, sizeof(char *));
924 if (req_data->request_header != NULL) {
925 headers_count = dp_db_get_http_headers_list(base_slot->client.dbhandle, base_req->id, (char **)req_data->request_header, &errorcode);
926 if (headers_count > 0)
927 req_data->request_header_count = headers_count;
931 req_data->user_client_data = (void *)slot;
932 req_data->user_req_data = (void *)request;
934 // call start API of agent lib
935 if (download_agent_start != NULL)
936 da_ret = (*download_agent_start)(url, req_data, &da_cb, &req_dl_id);
937 if (req_data->request_header_count > 0) {
940 len = req_data->request_header_count;
941 if (req_data->request_header != NULL) {
942 for (i = 0; i < len; i++)
943 free((void *)(req_data->request_header[i]));
945 free(req_data->request_header);
949 free(tmp_saved_path);
950 free(user_tmp_file_path);
955 if (da_ret == DA_RESULT_OK) {
956 TRACE_DEBUG("request id :%d SUCCESS agent_id:%d", base_req->id, req_dl_id);
957 base_req->agent_id = req_dl_id;
959 return __change_error(da_ret);
962 int dp_resume_agent_download(int req_id)
966 TRACE_ERROR("[NULL-CHECK] req_id");
967 return DP_ERROR_INVALID_PARAMETER;
969 if (download_agent_resume != NULL)
970 da_ret = (*download_agent_resume)(req_id);
971 if (da_ret == DA_RESULT_OK)
972 return DP_ERROR_NONE;
973 else if (da_ret == DA_ERR_INVALID_STATE)
974 return DP_ERROR_INVALID_STATE;
975 return __change_error(da_ret);