summaryrefslogtreecommitdiff
path: root/agent/download-agent-basic.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/download-agent-basic.c')
-rwxr-xr-xagent/download-agent-basic.c431
1 files changed, 431 insertions, 0 deletions
diff --git a/agent/download-agent-basic.c b/agent/download-agent-basic.c
new file mode 100755
index 0000000..73fc892
--- /dev/null
+++ b/agent/download-agent-basic.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include "download-agent-basic.h"
+#include "download-agent-debug.h"
+#include "download-agent-client-mgr.h"
+#include "download-agent-utils.h"
+#include "download-agent-http-mgr.h"
+#include "download-agent-http-misc.h"
+#include "download-agent-dl-mgr.h"
+#include "download-agent-pthread.h"
+#include "download-agent-file.h"
+
+static void* __thread_start_download(void* data);
+void __thread_clean_up_handler_for_start_download(void *arg);
+
+static da_result_t __make_source_info_basic_download(
+ stage_info *stage,
+ client_input_t *client_input);
+static da_result_t __download_content(stage_info *stage);
+
+da_result_t start_download(const char *url , int *dl_id)
+{
+ DA_LOG_FUNC_LOGD(Default);
+ return start_download_with_extension(url, dl_id, NULL);
+}
+
+da_result_t start_download_with_extension(
+ const char *url,
+ int *dl_id,
+ extension_data_t *extension_data)
+{
+ da_result_t ret = DA_RESULT_OK;
+ int slot_id = 0;
+ const char **request_header = DA_NULL;
+ const char *install_path = DA_NULL;
+ const char *file_name = DA_NULL;
+ const char *etag = DA_NULL;
+ const char *temp_file_path = DA_NULL;
+ const char *pkg_name = DA_NULL;
+ int request_header_count = 0;
+ void *user_data = DA_NULL;
+ client_input_t *client_input = DA_NULL;
+ client_input_basic_t *client_input_basic = DA_NULL;
+ download_thread_input *thread_info = DA_NULL;
+ pthread_attr_t thread_attr;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (extension_data) {
+ request_header = extension_data->request_header;
+ if (extension_data->request_header_count)
+ request_header_count = extension_data->request_header_count;
+ install_path = extension_data->install_path;
+ file_name = extension_data->file_name;
+ user_data = extension_data->user_data;
+ etag = extension_data->etag;
+ temp_file_path = extension_data->temp_file_path;
+ pkg_name = extension_data->pkg_name;
+ }
+
+ ret = get_available_slot_id(&slot_id);
+ if (DA_RESULT_OK != ret)
+ return ret;
+
+ *dl_id = GET_DL_ID(slot_id);
+
+ client_input = (client_input_t *)calloc(1, sizeof(client_input_t));
+ if (!client_input) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ } else {
+ client_input->user_data = user_data;
+ if (install_path) {
+ int install_path_len = strlen(install_path);
+ if (install_path[install_path_len-1] == '/')
+ install_path_len--;
+
+ client_input->install_path = (char *)calloc(install_path_len+1, sizeof(char));
+ if (client_input->install_path)
+ strncpy(client_input->install_path, install_path, install_path_len);
+ }
+
+ if (file_name) {
+ client_input->file_name = (char *)calloc(strlen(file_name)+1, sizeof(char));
+ if (client_input->file_name)
+ strncpy(client_input->file_name, file_name, strlen(file_name));
+ }
+
+ if (etag) {
+ client_input->etag = (char *)calloc(strlen(etag)+1, sizeof(char));
+ if (client_input->etag)
+ strncpy(client_input->etag, etag, strlen(etag));
+
+ }
+
+ if (temp_file_path) {
+ client_input->temp_file_path = (char *)calloc(strlen(temp_file_path)+1, sizeof(char));
+ if (client_input->temp_file_path)
+ strncpy(client_input->temp_file_path, temp_file_path, strlen(temp_file_path));
+ }
+
+ if (pkg_name) {
+ client_input->pkg_name = (char *)calloc(strlen(pkg_name)+1, sizeof(char));
+ if (client_input->pkg_name)
+ strncpy(client_input->pkg_name, pkg_name, strlen(pkg_name));
+ }
+ client_input_basic = &(client_input->client_input_basic);
+ client_input_basic->req_url = (char *)calloc(strlen(url)+1, sizeof(char));
+ if(DA_NULL == client_input_basic->req_url) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ }
+ strncpy(client_input_basic->req_url ,url,strlen(url));
+
+ if (request_header_count > 0) {
+ int i = 0;
+ client_input_basic->user_request_header =
+ (char **)calloc(1, sizeof(char *)*request_header_count);
+ if(DA_NULL == client_input_basic->user_request_header) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ }
+ for (i = 0; i < request_header_count; i++)
+ {
+ client_input_basic->user_request_header[i] = strdup(request_header[i]);
+ }
+ client_input_basic->user_request_header_count = request_header_count;
+ }
+ }
+
+ thread_info = (download_thread_input *)calloc(1, sizeof(download_thread_input));
+ if (!thread_info) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ } else {
+ thread_info->slot_id = slot_id;
+ thread_info->client_input = client_input;
+ }
+ if (pthread_attr_init(&thread_attr) != 0) {
+ ret = DA_ERR_FAIL_TO_CREATE_THREAD;
+ goto ERR;
+ }
+
+ if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED) != 0) {
+ ret = DA_ERR_FAIL_TO_CREATE_THREAD;
+ goto ERR;
+ }
+
+ if (pthread_create(&GET_DL_THREAD_ID(slot_id), &thread_attr,
+ __thread_start_download, thread_info) < 0) {
+ DA_LOG_ERR(Thread, "making thread failed..");
+ ret = DA_ERR_FAIL_TO_CREATE_THREAD;
+ } else {
+ if (GET_DL_THREAD_ID(slot_id) < 1) {
+ DA_LOG_ERR(Thread, "The thread start is failed before calling this");
+// When http resource is leaked, the thread ID is initialized at error handling section of thread_start_download()
+// Because the thread ID is initialized, the ptrhead_detach should not be called. This is something like timing issue between threads.
+// thread info and basic_dl_input is freed at thread_start_download(). And it should not returns error code in this case.
+ goto ERR;
+ }
+ }
+ DA_LOG_DEBUG(Thread, "download thread create slot_id[%d] thread id[%lu]",
+ slot_id,GET_DL_THREAD_ID(slot_id));
+
+ERR:
+ if (DA_RESULT_OK != ret) {
+ if (client_input) {
+ clean_up_client_input_info(client_input);
+ free(client_input);
+ client_input = DA_NULL;
+ }
+ if (thread_info) {
+ free(thread_info);
+ thread_info = DA_NULL;
+ }
+ destroy_download_info(slot_id);
+ }
+ return ret;
+}
+
+da_result_t __make_source_info_basic_download(
+ stage_info *stage,
+ client_input_t *client_input)
+{
+ da_result_t ret = DA_RESULT_OK;
+ client_input_basic_t *client_input_basic = DA_NULL;
+ source_info_t *source_info = DA_NULL;
+ source_info_basic_t *source_info_basic = DA_NULL;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ if (!stage) {
+ DA_LOG_ERR(Default, "no stage; DA_ERR_INVALID_ARGUMENT");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ goto ERR;
+ }
+
+ client_input_basic = &(client_input->client_input_basic);
+ if (DA_NULL == client_input_basic->req_url) {
+ DA_LOG_ERR(Default, "DA_ERR_INVALID_URL");
+ ret = DA_ERR_INVALID_URL;
+ goto ERR;
+ }
+
+ source_info_basic = (source_info_basic_t*)calloc(1, sizeof(source_info_basic_t));
+ if (DA_NULL == source_info_basic) {
+ DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ goto ERR;
+ }
+
+ source_info_basic->url = client_input_basic->req_url;
+ client_input_basic->req_url = DA_NULL;
+
+ if (client_input_basic->user_request_header) {
+ source_info_basic->user_request_header =
+ client_input_basic->user_request_header;
+ source_info_basic->user_request_header_count =
+ client_input_basic->user_request_header_count;
+ client_input_basic->user_request_header = DA_NULL;
+ client_input_basic->user_request_header_count = 0;
+ }
+
+ source_info = GET_STAGE_SOURCE_INFO(stage);
+ memset(source_info, 0, sizeof(source_info_t));
+
+ source_info->source_info_type.source_info_basic = source_info_basic;
+
+// DA_SECURE_LOGI("BASIC HTTP STARTED: URL=%s",
+// source_info->source_info_type.source_info_basic->url);
+ERR:
+ return ret;
+}
+
+void __thread_clean_up_handler_for_start_download(void *arg)
+{
+ DA_LOG_CRITICAL(Default, "cleanup for thread id = %d", pthread_self());
+}
+
+static void *__thread_start_download(void *data)
+{
+ da_result_t ret = DA_RESULT_OK;
+ download_thread_input *thread_info = DA_NULL;
+ client_input_t *client_input = DA_NULL;
+ stage_info *stage = DA_NULL;
+ download_state_t download_state = 0;
+
+ int slot_id = DA_INVALID_ID;
+
+ DA_LOG_FUNC_LOGV(Thread);
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, DA_NULL);
+
+ thread_info = (download_thread_input*)data;
+ if (DA_NULL == thread_info) {
+ DA_LOG_ERR(Thread, "thread_info is NULL..");
+ ret = DA_ERR_INVALID_ARGUMENT;
+ return DA_NULL;
+ } else {
+ slot_id = thread_info->slot_id;
+ client_input = thread_info->client_input;
+
+ if(thread_info) {
+ free(thread_info);
+ thread_info = DA_NULL;
+ }
+ }
+
+ pthread_cleanup_push(__thread_clean_up_handler_for_start_download, (void *)NULL);
+
+ if (DA_FALSE == is_valid_slot_id(slot_id)) {
+ ret = DA_ERR_INVALID_ARGUMENT;
+ DA_LOG_ERR(Default, "Invalid Download ID");
+ goto ERR;
+ }
+
+ if (!client_input) {
+ ret = DA_ERR_INVALID_ARGUMENT;
+ DA_LOG_ERR(Default, "Invalid client_input");
+ goto ERR;
+ }
+
+ stage = Add_new_download_stage(slot_id);
+ if (!stage) {
+ ret = DA_ERR_FAIL_TO_MEMALLOC;
+ DA_LOG_ERR(Default, "STAGE ADDITION FAIL!");
+ goto ERR;
+ }
+ DA_LOG_VERBOSE(Default, "new added Stage : %p", stage);
+
+ GET_DL_USER_DATA(slot_id) = client_input->user_data;
+ client_input->user_data = DA_NULL;
+ GET_DL_USER_INSTALL_PATH(slot_id) = client_input->install_path;
+ client_input->install_path = DA_NULL;
+ GET_DL_USER_FILE_NAME(slot_id) = client_input->file_name;
+ client_input->file_name = DA_NULL;
+ GET_DL_USER_ETAG(slot_id) = client_input->etag;
+ client_input->etag = DA_NULL;
+ GET_DL_USER_TEMP_FILE_PATH(slot_id) = client_input->temp_file_path;
+ client_input->temp_file_path = DA_NULL;
+
+ ret = __make_source_info_basic_download(stage, client_input);
+
+ if (ret == DA_RESULT_OK) {
+ /* to save memory */
+ if (client_input) {
+ clean_up_client_input_info(client_input);
+ free(client_input);
+ client_input = DA_NULL;
+ }
+
+ ret = __download_content(stage);
+ if (stage != GET_DL_CURRENT_STAGE(slot_id)) {
+ DA_LOG_ERR(Default,"Playready download case. The next stage is present stage");
+ stage = GET_DL_CURRENT_STAGE(slot_id);
+ }
+ }
+ERR:
+ if (client_input) {
+ clean_up_client_input_info(client_input);
+ free(client_input);
+ client_input = DA_NULL;
+ }
+
+ if (DA_RESULT_OK == ret) {
+ char *installed_path = NULL;
+ char *etag = DA_NULL;
+ req_dl_info *request_info = NULL;
+ file_info *file_storage = NULL;
+ DA_LOG_VERBOSE(Default, "Whole download flow is finished.");
+ _da_thread_mutex_lock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
+ download_state = GET_DL_STATE_ON_STAGE(stage);
+ _da_thread_mutex_unlock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
+ if (download_state == DOWNLOAD_STATE_ABORTED) {
+ DA_LOG(Default, "Abort case. Do not call client callback");
+#ifdef PAUSE_EXIT
+ } else if (download_state == DOWNLOAD_STATE_PAUSED) {
+ DA_LOG(Default, "Finish case from paused state");
+ destroy_download_info(slot_id);
+#endif
+ } else {
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+ etag = GET_REQUEST_HTTP_HDR_ETAG(request_info);
+ file_storage = GET_STAGE_CONTENT_STORE_INFO(stage);
+ installed_path = GET_CONTENT_STORE_ACTUAL_FILE_NAME(file_storage);
+ send_user_noti_and_finish_download_flow(slot_id, installed_path,
+ etag);
+ }
+ } else {
+ char *etag = DA_NULL;
+ req_dl_info *request_info = NULL;
+ request_info = GET_STAGE_TRANSACTION_INFO(stage);
+ DA_LOG_CRITICAL(Default, "Download Failed -Return = %d", ret);
+ if (request_info) {
+ etag = GET_REQUEST_HTTP_HDR_ETAG(request_info);
+ send_client_finished_info(slot_id, GET_DL_ID(slot_id),
+ DA_NULL, etag, ret, get_http_status(slot_id));
+ }
+ destroy_download_info(slot_id);
+ }
+
+ pthread_cleanup_pop(0);
+ DA_LOG_CRITICAL(Thread, "==thread_start_download - EXIT==");
+ pthread_exit((void *)NULL);
+ return DA_NULL;
+}
+
+da_result_t __download_content(stage_info *stage)
+{
+ da_result_t ret = DA_RESULT_OK;
+ download_state_t download_state = 0;
+ da_bool_t isDownloadComplete = DA_FALSE;
+ int slot_id = DA_INVALID_ID;
+
+ DA_LOG_FUNC_LOGV(Default);
+
+ slot_id = GET_STAGE_DL_ID(stage);
+ CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_NEW_DOWNLOAD, stage);
+
+ do {
+ stage = GET_DL_CURRENT_STAGE(slot_id);
+ _da_thread_mutex_lock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
+ download_state = GET_DL_STATE_ON_STAGE(stage);
+ DA_LOG_VERBOSE(Default, "download_state to - [%d] ", download_state);
+ _da_thread_mutex_unlock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
+
+ switch(download_state) {
+ case DOWNLOAD_STATE_NEW_DOWNLOAD:
+ ret = requesting_download(stage);
+
+ _da_thread_mutex_lock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
+ download_state = GET_DL_STATE_ON_STAGE(stage);
+ _da_thread_mutex_unlock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
+ if (download_state == DOWNLOAD_STATE_CANCELED ||
+ download_state == DOWNLOAD_STATE_ABORTED ||
+ download_state == DOWNLOAD_STATE_PAUSED) {
+ break;
+ } else {
+ if (DA_RESULT_OK == ret) {
+ ret = handle_after_download(stage);
+ }
+ }
+ break;
+ default:
+ isDownloadComplete = DA_TRUE;
+ break;
+ }
+ }while ((DA_RESULT_OK == ret) && (DA_FALSE == isDownloadComplete));
+
+ return ret;
+}