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 "download-agent-basic.h"
20 #include "download-agent-debug.h"
21 #include "download-agent-client-mgr.h"
22 #include "download-agent-utils.h"
23 #include "download-agent-http-mgr.h"
24 #include "download-agent-http-misc.h"
25 #include "download-agent-dl-mgr.h"
26 #include "download-agent-pthread.h"
27 #include "download-agent-file.h"
29 static void* __thread_start_download(void* data);
30 void __thread_clean_up_handler_for_start_download(void *arg);
32 static da_result_t __make_source_info_basic_download(
34 client_input_t *client_input);
35 static da_result_t __download_content(stage_info *stage);
37 da_result_t start_download(const char *url , int *dl_id)
39 DA_LOG_FUNC_START(Default);
40 return start_download_with_extension(url, dl_id, NULL);
43 da_result_t start_download_with_extension(
46 extension_data_t *extension_data)
48 da_result_t ret = DA_RESULT_OK;
50 const char **request_header = DA_NULL;
51 const char *install_path = DA_NULL;
52 const char *file_name = DA_NULL;
53 const char *etag = DA_NULL;
54 const char *temp_file_path = DA_NULL;
55 int request_header_count = 0;
56 void *user_data = DA_NULL;
57 client_input_t *client_input = DA_NULL;
58 client_input_basic_t *client_input_basic = DA_NULL;
59 download_thread_input *thread_info = DA_NULL;
60 pthread_attr_t thread_attr;
62 DA_LOG_FUNC_START(Default);
65 request_header = extension_data->request_header;
66 if (extension_data->request_header_count)
67 request_header_count = extension_data->request_header_count;
68 install_path = extension_data->install_path;
69 file_name = extension_data->file_name;
70 user_data = extension_data->user_data;
71 etag = extension_data->etag;
72 temp_file_path = extension_data->temp_file_path;
75 ret = get_available_slot_id(&slot_id);
76 if (DA_RESULT_OK != ret)
79 *dl_id = GET_DL_ID(slot_id);
81 client_input = (client_input_t *)calloc(1, sizeof(client_input_t));
83 DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
84 ret = DA_ERR_FAIL_TO_MEMALLOC;
87 client_input->user_data = user_data;
89 int install_path_len = strlen(install_path);
90 if (install_path[install_path_len-1] == '/')
93 client_input->install_path = (char *)calloc(install_path_len+1, sizeof(char));
94 if (client_input->install_path)
95 snprintf(client_input->install_path, install_path_len+1, install_path);
99 client_input->file_name = (char *)calloc(strlen(file_name)+1, sizeof(char));
100 if (client_input->file_name)
101 strncpy(client_input->file_name, file_name, strlen(file_name));
105 client_input->etag = (char *)calloc(strlen(etag)+1, sizeof(char));
106 if (client_input->etag)
107 strncpy(client_input->etag, etag, strlen(etag));
111 if (temp_file_path) {
112 client_input->temp_file_path = (char *)calloc(strlen(temp_file_path)+1, sizeof(char));
113 if (client_input->temp_file_path)
114 strncpy(client_input->temp_file_path, temp_file_path, strlen(temp_file_path));
117 client_input_basic = &(client_input->client_input_basic);
118 client_input_basic->req_url = (char *)calloc(strlen(url)+1, sizeof(char));
119 if(DA_NULL == client_input_basic->req_url) {
120 DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
121 ret = DA_ERR_FAIL_TO_MEMALLOC;
124 strncpy(client_input_basic->req_url ,url,strlen(url));
126 if (request_header_count > 0) {
128 client_input_basic->user_request_header =
129 (char **)calloc(1, sizeof(char *)*request_header_count);
130 if(DA_NULL == client_input_basic->user_request_header) {
131 DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
132 ret = DA_ERR_FAIL_TO_MEMALLOC;
135 for (i = 0; i < request_header_count; i++)
137 client_input_basic->user_request_header[i] = strdup(request_header[i]);
139 client_input_basic->user_request_header_count = request_header_count;
143 thread_info = (download_thread_input *)calloc(1, sizeof(download_thread_input));
145 DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
146 ret = DA_ERR_FAIL_TO_MEMALLOC;
149 thread_info->slot_id = slot_id;
150 thread_info->client_input = client_input;
152 if (pthread_attr_init(&thread_attr) != 0) {
153 ret = DA_ERR_FAIL_TO_CREATE_THREAD;
157 if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED) != 0) {
158 ret = DA_ERR_FAIL_TO_CREATE_THREAD;
162 if (pthread_create(&GET_DL_THREAD_ID(slot_id), &thread_attr,
163 __thread_start_download, thread_info) < 0) {
164 DA_LOG_ERR(Thread, "making thread failed..");
165 ret = DA_ERR_FAIL_TO_CREATE_THREAD;
167 if (GET_DL_THREAD_ID(slot_id) < 1) {
168 DA_LOG_ERR(Thread, "The thread start is failed before calling this");
169 // When http resource is leaked, the thread ID is initialized at error handling section of thread_start_download()
170 // Because the thread ID is initialized, the ptrhead_detach should not be called. This is something like timing issue between threads.
171 // thread info and basic_dl_input is freed at thread_start_download(). And it should not returns error code in this case.
175 DA_LOG_CRITICAL(Thread, "download thread create slot_id[%d] thread id[%lu]",
176 slot_id,GET_DL_THREAD_ID(slot_id));
179 if (DA_RESULT_OK != ret) {
181 clean_up_client_input_info(client_input);
183 client_input = DA_NULL;
187 thread_info = DA_NULL;
189 destroy_download_info(slot_id);
194 da_result_t __make_source_info_basic_download(
196 client_input_t *client_input)
198 da_result_t ret = DA_RESULT_OK;
199 client_input_basic_t *client_input_basic = DA_NULL;
200 source_info_t *source_info = DA_NULL;
201 source_info_basic_t *source_info_basic = DA_NULL;
203 DA_LOG_FUNC_START(Default);
206 DA_LOG_ERR(Default, "no stage; DA_ERR_INVALID_ARGUMENT");
207 ret = DA_ERR_INVALID_ARGUMENT;
211 client_input_basic = &(client_input->client_input_basic);
212 if (DA_NULL == client_input_basic->req_url) {
213 DA_LOG_ERR(Default, "DA_ERR_INVALID_URL");
214 ret = DA_ERR_INVALID_URL;
218 source_info_basic = (source_info_basic_t*)calloc(1, sizeof(source_info_basic_t));
219 if (DA_NULL == source_info_basic) {
220 DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
221 ret = DA_ERR_FAIL_TO_MEMALLOC;
225 source_info_basic->url = client_input_basic->req_url;
226 client_input_basic->req_url = DA_NULL;
228 if (client_input_basic->user_request_header) {
229 source_info_basic->user_request_header =
230 client_input_basic->user_request_header;
231 source_info_basic->user_request_header_count =
232 client_input_basic->user_request_header_count;
233 client_input_basic->user_request_header = DA_NULL;
234 client_input_basic->user_request_header_count = 0;
237 source_info = GET_STAGE_SOURCE_INFO(stage);
238 memset(source_info, 0, sizeof(source_info_t));
240 source_info->source_info_type.source_info_basic = source_info_basic;
242 DA_LOG(Default, "BASIC HTTP STARTED: URL=%s",
243 source_info->source_info_type.source_info_basic->url);
248 void __thread_clean_up_handler_for_start_download(void *arg)
250 DA_LOG_CRITICAL(Default, "cleanup for thread id = %d", pthread_self());
253 static void *__thread_start_download(void *data)
255 da_result_t ret = DA_RESULT_OK;
256 download_thread_input *thread_info = DA_NULL;
257 client_input_t *client_input = DA_NULL;
258 stage_info *stage = DA_NULL;
259 download_state_t download_state = 0;
261 int slot_id = DA_INVALID_ID;
263 DA_LOG_FUNC_START(Thread);
265 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, DA_NULL);
267 thread_info = (download_thread_input*)data;
268 if (DA_NULL == thread_info) {
269 DA_LOG_ERR(Thread, "thread_info is NULL..");
270 ret = DA_ERR_INVALID_ARGUMENT;
273 slot_id = thread_info->slot_id;
274 client_input = thread_info->client_input;
278 thread_info = DA_NULL;
282 pthread_cleanup_push(__thread_clean_up_handler_for_start_download, (void *)NULL);
284 if (DA_FALSE == is_valid_slot_id(slot_id)) {
285 ret = DA_ERR_INVALID_ARGUMENT;
286 DA_LOG_ERR(Default, "Invalid Download ID");
291 ret = DA_ERR_INVALID_ARGUMENT;
292 DA_LOG_ERR(Default, "Invalid client_input");
296 stage = Add_new_download_stage(slot_id);
298 ret = DA_ERR_FAIL_TO_MEMALLOC;
299 DA_LOG_ERR(Default, "STAGE ADDITION FAIL!");
302 DA_LOG(Default, "new added Stage : %p", stage);
304 GET_DL_USER_DATA(slot_id) = client_input->user_data;
305 client_input->user_data = DA_NULL;
306 GET_DL_USER_INSTALL_PATH(slot_id) = client_input->install_path;
307 client_input->install_path = DA_NULL;
308 GET_DL_USER_FILE_NAME(slot_id) = client_input->file_name;
309 client_input->file_name = DA_NULL;
310 GET_DL_USER_ETAG(slot_id) = client_input->etag;
311 client_input->etag = DA_NULL;
312 GET_DL_USER_TEMP_FILE_PATH(slot_id) = client_input->temp_file_path;
313 client_input->temp_file_path = DA_NULL;
314 ret = __make_source_info_basic_download(stage, client_input);
317 clean_up_client_input_info(client_input);
319 client_input = DA_NULL;
322 if (ret == DA_RESULT_OK)
323 ret = __download_content(stage);
327 clean_up_client_input_info(client_input);
329 client_input = DA_NULL;
332 if (DA_RESULT_OK == ret) {
333 char *installed_path = NULL;
334 char *etag = DA_NULL;
335 req_dl_info *request_info = NULL;
336 file_info *file_storage = NULL;
337 DA_LOG_CRITICAL(Default, "Whole download flow is finished.");
338 _da_thread_mutex_lock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
339 download_state = GET_DL_STATE_ON_STAGE(stage);
340 _da_thread_mutex_unlock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
341 if (download_state == DOWNLOAD_STATE_ABORTED) {
342 DA_LOG(Default, "Abort case. Do not call client callback");
344 } else if (download_state == DOWNLOAD_STATE_PAUSED) {
345 DA_LOG(Default, "Finish case from paused state");
346 destroy_download_info(slot_id);
349 request_info = GET_STAGE_TRANSACTION_INFO(stage);
350 etag = GET_REQUEST_HTTP_HDR_ETAG(request_info);
351 file_storage = GET_STAGE_CONTENT_STORE_INFO(stage);
352 installed_path = GET_CONTENT_STORE_ACTUAL_FILE_NAME(file_storage);
353 send_user_noti_and_finish_download_flow(slot_id, installed_path,
357 char *etag = DA_NULL;
358 req_dl_info *request_info = NULL;
359 request_info = GET_STAGE_TRANSACTION_INFO(stage);
360 DA_LOG_CRITICAL(Default, "Download Failed -Return = %d", ret);
362 etag = GET_REQUEST_HTTP_HDR_ETAG(request_info);
363 send_client_finished_info(slot_id, GET_DL_ID(slot_id),
364 DA_NULL, etag, ret, get_http_status(slot_id));
366 destroy_download_info(slot_id);
369 pthread_cleanup_pop(0);
370 DA_LOG_CRITICAL(Thread, "=====thread_start_download - EXIT=====");
371 pthread_exit((void *)NULL);
375 da_result_t __download_content(stage_info *stage)
377 da_result_t ret = DA_RESULT_OK;
378 download_state_t download_state = 0;
379 da_bool_t isDownloadComplete = DA_FALSE;
380 int slot_id = DA_INVALID_ID;
382 DA_LOG_FUNC_START(Default);
384 slot_id = GET_STAGE_DL_ID(stage);
385 CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_NEW_DOWNLOAD, stage);
388 stage = GET_DL_CURRENT_STAGE(slot_id);
389 _da_thread_mutex_lock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
390 download_state = GET_DL_STATE_ON_STAGE(stage);
391 DA_LOG(Default, "download_state to - [%d] ", download_state);
392 _da_thread_mutex_unlock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
394 switch(download_state) {
395 case DOWNLOAD_STATE_NEW_DOWNLOAD:
396 ret = requesting_download(stage);
398 _da_thread_mutex_lock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
399 download_state = GET_DL_STATE_ON_STAGE(stage);
400 _da_thread_mutex_unlock (&mutex_download_state[GET_STAGE_DL_ID(stage)]);
401 if (download_state == DOWNLOAD_STATE_CANCELED ||
402 download_state == DOWNLOAD_STATE_ABORTED ||
403 download_state == DOWNLOAD_STATE_PAUSED) {
406 if (DA_RESULT_OK == ret) {
407 ret = handle_after_download(stage);
412 isDownloadComplete = DA_TRUE;
415 }while ((DA_RESULT_OK == ret) && (DA_FALSE == isDownloadComplete));