4 * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jungki Kwak <jungki.kwak@samsung.com>, Keunsoon Lee <keunsoon.lee@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
20 * @file download-agent-basic.c
21 * @brief functions for basic (http) download
22 * @author Keunsoon Lee(keunsoon.lee@samsung.com)
23 * @author Jungki Kwak(jungki.kwak@samsung.com)
28 #include "download-agent-basic.h"
29 #include "download-agent-debug.h"
30 #include "download-agent-client-mgr.h"
31 #include "download-agent-utils.h"
32 #include "download-agent-http-mgr.h"
33 #include "download-agent-http-misc.h"
34 #include "download-agent-dl-mgr.h"
35 #include "download-agent-installation.h"
36 #include "download-agent-pthread.h"
38 static void* __thread_start_download(void* data);
39 void __thread_clean_up_handler_for_start_download(void *arg);
41 static da_result_t __make_source_info_basic_download(
43 client_input_t *client_input);
44 static da_result_t __download_content(stage_info *stage);
46 da_result_t start_download(const char *url , da_handle_t *dl_req_id)
48 DA_LOG_FUNC_START(Default);
49 return start_download_with_extension(url, dl_req_id, NULL);
52 da_result_t start_download_with_extension(
54 da_handle_t *dl_req_id,
55 extension_data_t *extension_data)
57 da_result_t ret = DA_RESULT_OK;
59 const char **request_header = DA_NULL;
60 const char *install_path = DA_NULL;
61 const char *file_name = DA_NULL;
62 int request_header_count = 0;
63 void *user_data = DA_NULL;
64 client_input_t *client_input = DA_NULL;
65 client_input_basic_t *client_input_basic = DA_NULL;
66 download_thread_input *thread_info = DA_NULL;
68 DA_LOG_FUNC_START(Default);
71 request_header = extension_data->request_header;
72 if (extension_data->request_header_count)
73 request_header_count = *(extension_data->request_header_count);
74 install_path = extension_data->install_path;
75 file_name = extension_data->file_name;
76 user_data = extension_data->user_data;
79 ret = get_available_download_id(&download_id);
80 if (DA_RESULT_OK != ret)
83 *dl_req_id = GET_DL_REQ_ID(download_id);
85 client_input = (client_input_t *)calloc(1, sizeof(client_input_t));
87 DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
88 ret = DA_ERR_FAIL_TO_MEMALLOC;
91 client_input->user_data = user_data;
93 int install_path_len = strlen(install_path);
94 if (install_path[install_path_len-1] == '/')
97 client_input->install_path = (char *)calloc(1, install_path_len+1);
98 if (client_input->install_path)
99 snprintf(client_input->install_path, install_path_len+1, install_path);
103 client_input->file_name = (char *)calloc(1, strlen(file_name)+1);
104 if (client_input->file_name)
105 strncpy(client_input->file_name, file_name, strlen(file_name));
108 client_input_basic = &(client_input->client_input_basic);
109 client_input_basic->req_url = (char *)calloc(1, strlen(url)+1);
110 if(DA_NULL == client_input_basic->req_url) {
111 DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
112 ret = DA_ERR_FAIL_TO_MEMALLOC;
115 strncpy(client_input_basic->req_url ,url,strlen(url));
117 if (request_header_count > 0) {
119 client_input_basic->user_request_header =
120 (char **)calloc(1, sizeof(char *)*request_header_count);
121 if(DA_NULL == client_input_basic->user_request_header) {
122 DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
123 ret = DA_ERR_FAIL_TO_MEMALLOC;
126 for (i = 0; i < request_header_count; i++)
128 client_input_basic->user_request_header[i] = strdup(request_header[i]);
130 client_input_basic->user_request_header_count = request_header_count;
134 thread_info = (download_thread_input *)calloc(1, sizeof(download_thread_input));
136 DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
137 ret = DA_ERR_FAIL_TO_MEMALLOC;
140 thread_info->download_id = download_id;
141 thread_info->client_input = client_input;
144 if(pthread_create(&GET_DL_THREAD_ID(download_id), DA_NULL, __thread_start_download, thread_info) < 0) {
145 DA_LOG_ERR(Thread, "making thread failed..");
146 ret = DA_ERR_FAIL_TO_CREATE_THREAD;
148 if (GET_DL_THREAD_ID(download_id) < 1) {
149 DA_LOG_ERR(Thread, "The thread start is failed before calling this");
150 // When http resource is leaked, the thread ID is initialized at error handling section of thread_start_download()
151 // Because the thread ID is initialized, the ptrhead_detach should not be called. This is something like timing issue between threads.
152 // thread info and basic_dl_input is freed at thread_start_download(). And it should not returns error code in this case.
156 DA_LOG_CRITICAL(Thread, "download thread create download_id[%d] thread id[%lu]",
157 download_id,GET_DL_THREAD_ID(download_id));
160 if (DA_RESULT_OK != ret) {
162 clean_up_client_input_info(client_input);
164 client_input = DA_NULL;
168 thread_info = DA_NULL;
170 destroy_download_info(download_id);
175 da_result_t __make_source_info_basic_download(
177 client_input_t *client_input)
179 da_result_t ret = DA_RESULT_OK;
180 client_input_basic_t *client_input_basic = DA_NULL;
181 source_info_t *source_info = DA_NULL;
182 source_info_basic_t *source_info_basic = DA_NULL;
184 DA_LOG_FUNC_START(Default);
187 DA_LOG_ERR(Default, "no stage; DA_ERR_INVALID_ARGUMENT");
188 ret = DA_ERR_INVALID_ARGUMENT;
192 client_input_basic = &(client_input->client_input_basic);
193 if (DA_NULL == client_input_basic->req_url) {
194 DA_LOG_ERR(Default, "DA_ERR_INVALID_URL");
195 ret = DA_ERR_INVALID_URL;
199 source_info_basic = (source_info_basic_t*)calloc(1, sizeof(source_info_basic_t));
200 if (DA_NULL == source_info_basic) {
201 DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
202 ret = DA_ERR_FAIL_TO_MEMALLOC;
206 source_info_basic->url = client_input_basic->req_url;
207 client_input_basic->req_url = DA_NULL;
209 if (client_input_basic->user_request_header) {
210 source_info_basic->user_request_header =
211 client_input_basic->user_request_header;
212 source_info_basic->user_request_header_count =
213 client_input_basic->user_request_header_count;
214 client_input_basic->user_request_header = DA_NULL;
215 client_input_basic->user_request_header_count = 0;
218 source_info = GET_STAGE_SOURCE_INFO(stage);
219 memset(source_info, 0, sizeof(source_info_t));
221 source_info->source_info_type.source_info_basic = source_info_basic;
223 DA_LOG(Default, "BASIC HTTP STARTED: URL=%s",
224 source_info->source_info_type.source_info_basic->url);
229 void __thread_clean_up_handler_for_start_download(void *arg)
231 DA_LOG_CRITICAL(Default, "cleanup for thread id = %d", pthread_self());
234 static void *__thread_start_download(void *data)
236 da_result_t ret = DA_RESULT_OK;
237 download_thread_input *thread_info = DA_NULL;
238 client_input_t *client_input = DA_NULL;
239 stage_info *stage = DA_NULL;
240 int download_id = DA_INVALID_ID;
242 DA_LOG_FUNC_START(Thread);
244 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, DA_NULL);
246 thread_info = (download_thread_input*)data;
247 if (DA_NULL == thread_info) {
248 DA_LOG_ERR(Thread, "thread_info is NULL..");
249 ret = DA_ERR_INVALID_ARGUMENT;
252 download_id = thread_info->download_id;
253 client_input = thread_info->client_input;
257 thread_info = DA_NULL;
261 pthread_cleanup_push(__thread_clean_up_handler_for_start_download, (void *)NULL);
263 if (DA_FALSE == is_valid_dl_ID(download_id)) {
264 ret = DA_ERR_INVALID_ARGUMENT;
265 DA_LOG_ERR(Default, "Invalid Download ID");
270 ret = DA_ERR_INVALID_ARGUMENT;
271 DA_LOG_ERR(Default, "Invalid client_input");
275 stage = Add_new_download_stage(download_id);
277 ret = DA_ERR_FAIL_TO_MEMALLOC;
278 DA_LOG_ERR(Default, "STAGE ADDITION FAIL!");
281 DA_LOG(Default, "new added Stage : %p", stage);
283 GET_DL_USER_DATA(download_id) = client_input->user_data;
284 GET_DL_USER_INSTALL_PATH(download_id) = client_input->install_path;
285 client_input->install_path = DA_NULL;
286 GET_DL_USER_FILE_NAME(download_id) = client_input->file_name;
287 client_input->file_name = DA_NULL;
289 ret = __make_source_info_basic_download(stage, client_input);
292 clean_up_client_input_info(client_input);
294 client_input = DA_NULL;
297 if (ret == DA_RESULT_OK)
298 ret = __download_content(stage);
302 clean_up_client_input_info(client_input);
304 client_input = DA_NULL;
307 if (DA_RESULT_OK == ret) {
308 DA_LOG_CRITICAL(Default, "Whole download flow is finished.");
309 send_user_noti_and_finish_download_flow(download_id);
311 DA_LOG_CRITICAL(Default, "DA_STATE_FAILED -Return = %d", ret);
312 send_client_da_state(download_id, DA_STATE_FAILED, ret);
313 destroy_download_info(download_id);
316 pthread_cleanup_pop(0);
317 DA_LOG_CRITICAL(Thread, "=====thread_start_download - EXIT=====");
318 pthread_exit((void *)NULL);
322 da_result_t __download_content(stage_info *stage)
324 da_result_t ret = DA_RESULT_OK;
325 download_state_t download_state = 0;
326 da_bool_t isDownloadComplete = DA_FALSE;
327 int download_id = DA_INVALID_ID;
329 DA_LOG_FUNC_START(Default);
331 download_id = GET_STAGE_DL_ID(stage);
332 CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_NEW_DOWNLOAD, stage);
335 stage = GET_DL_CURRENT_STAGE(download_id);
336 _da_thread_mutex_lock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
337 download_state = GET_DL_STATE_ON_STAGE(stage);
338 DA_LOG(Default, "download_state to - [%d] ", download_state);
339 _da_thread_mutex_unlock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
341 switch(download_state) {
342 case DOWNLOAD_STATE_NEW_DOWNLOAD:
343 ret = requesting_download(stage);
345 _da_thread_mutex_lock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
346 download_state = GET_DL_STATE_ON_STAGE(stage);
347 _da_thread_mutex_unlock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
349 if (download_state == DOWNLOAD_STATE_CANCELED) {
352 if (DA_RESULT_OK == ret) {
353 ret = handle_after_download(stage);
357 case DOWNLOAD_STATE_READY_TO_INSTAL:
358 send_client_da_state(download_id, DA_STATE_DOWNLOAD_COMPLETE, DA_RESULT_OK);
359 ret = process_install(stage);
360 if (DA_RESULT_OK == ret) {
361 CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_FINISH,stage);
365 isDownloadComplete = DA_TRUE;
368 }while ((DA_RESULT_OK == ret) && (DA_FALSE == isDownloadComplete));