The download provider daemon is added newly.
[profile/ivi/download-provider.git] / src / agent / download-agent-basic.c
1 /*
2  * Download Agent
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jungki Kwak <jungki.kwak@samsung.com>, Keunsoon Lee <keunsoon.lee@samsung.com>
7  *
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
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
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)
24  ***/
25
26 #include <stdlib.h>
27
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"
37
38 static void* __thread_start_download(void* data);
39 void __thread_clean_up_handler_for_start_download(void *arg);
40
41 static da_result_t __make_source_info_basic_download(
42                 stage_info *stage,
43                 client_input_t *client_input);
44 static da_result_t __download_content(stage_info *stage);
45
46 da_result_t start_download(const char *url , da_handle_t *dl_req_id)
47 {
48         DA_LOG_FUNC_START(Default);
49         return start_download_with_extension(url, dl_req_id, NULL);
50 }
51
52 da_result_t start_download_with_extension(
53                 const char *url,
54                 da_handle_t *dl_req_id,
55                 extension_data_t *extension_data)
56 {
57         da_result_t  ret = DA_RESULT_OK;
58         int download_id = 0;
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;
67
68         DA_LOG_FUNC_START(Default);
69
70         if (extension_data) {
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;
77         }
78
79         ret = get_available_download_id(&download_id);
80         if (DA_RESULT_OK != ret)
81                 return ret;
82
83         *dl_req_id = GET_DL_REQ_ID(download_id);
84
85         client_input = (client_input_t *)calloc(1, sizeof(client_input_t));
86         if (!client_input) {
87                 DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
88                 ret = DA_ERR_FAIL_TO_MEMALLOC;
89                 goto ERR;
90         } else {
91                 client_input->user_data = user_data;
92                 if (install_path) {
93                         int install_path_len = strlen(install_path);
94                         if (install_path[install_path_len-1] == '/')
95                                 install_path_len--;
96
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);
100                 }
101
102                 if (file_name) {
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));
106                 }
107
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;
113                         goto ERR;
114                 }
115                 strncpy(client_input_basic->req_url ,url,strlen(url));
116
117                 if (request_header_count > 0) {
118                         int i = 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;
124                                 goto ERR;
125                         }
126                         for (i = 0; i < request_header_count; i++)
127                         {
128                                 client_input_basic->user_request_header[i] = strdup(request_header[i]);
129                         }
130                         client_input_basic->user_request_header_count = request_header_count;
131                 }
132         }
133
134         thread_info = (download_thread_input *)calloc(1, sizeof(download_thread_input));
135         if(!thread_info) {
136                 DA_LOG_ERR(Default, "DA_ERR_FAIL_TO_MEMALLOC");
137                 ret = DA_ERR_FAIL_TO_MEMALLOC;
138                 goto ERR;
139         } else {
140                 thread_info->download_id = download_id;
141                 thread_info->client_input = client_input;
142         }
143
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;
147         } else {
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.
153                         goto ERR;
154                 }
155         }
156         DA_LOG_CRITICAL(Thread, "download thread create download_id[%d] thread id[%lu]",
157                         download_id,GET_DL_THREAD_ID(download_id));
158
159 ERR:
160         if (DA_RESULT_OK != ret) {
161                 if (client_input) {
162                         clean_up_client_input_info(client_input);
163                         free(client_input);
164                         client_input = DA_NULL;
165                 }
166                 if (thread_info) {
167                         free(thread_info);
168                         thread_info = DA_NULL;
169                 }
170                 destroy_download_info(download_id);
171         }
172         return ret;
173 }
174
175 da_result_t __make_source_info_basic_download(
176                 stage_info *stage,
177                 client_input_t *client_input)
178 {
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;
183
184         DA_LOG_FUNC_START(Default);
185
186         if (!stage) {
187                 DA_LOG_ERR(Default, "no stage; DA_ERR_INVALID_ARGUMENT");
188                 ret = DA_ERR_INVALID_ARGUMENT;
189                 goto ERR;
190         }
191
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;
196                 goto ERR;
197         }
198
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;
203                 goto ERR;
204         }
205
206         source_info_basic->url = client_input_basic->req_url;
207         client_input_basic->req_url = DA_NULL;
208
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;
216         }
217
218         source_info = GET_STAGE_SOURCE_INFO(stage);
219         memset(source_info, 0, sizeof(source_info_t));
220
221         source_info->source_info_type.source_info_basic = source_info_basic;
222
223         DA_LOG(Default, "BASIC HTTP STARTED: URL=%s",
224                         source_info->source_info_type.source_info_basic->url);
225 ERR:
226         return ret;
227 }
228
229 void __thread_clean_up_handler_for_start_download(void *arg)
230 {
231        DA_LOG_CRITICAL(Default, "cleanup for thread id = %d", pthread_self());
232 }
233
234 static void *__thread_start_download(void *data)
235 {
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;
241
242         DA_LOG_FUNC_START(Thread);
243
244         pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, DA_NULL);
245
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;
250                 return DA_NULL;
251         } else {
252                 download_id = thread_info->download_id;
253                 client_input = thread_info->client_input;
254
255                 if(thread_info) {
256                         free(thread_info);
257                         thread_info = DA_NULL;
258                 }
259         }
260
261         pthread_cleanup_push(__thread_clean_up_handler_for_start_download, (void *)NULL);
262
263         if (DA_FALSE == is_valid_dl_ID(download_id)) {
264                 ret = DA_ERR_INVALID_ARGUMENT;
265                 DA_LOG_ERR(Default, "Invalid Download ID");
266                 goto ERR;
267         }
268
269         if (!client_input) {
270                 ret = DA_ERR_INVALID_ARGUMENT;
271                 DA_LOG_ERR(Default, "Invalid client_input");
272                 goto ERR;
273         }
274
275         stage = Add_new_download_stage(download_id);
276         if (!stage) {
277                 ret = DA_ERR_FAIL_TO_MEMALLOC;
278                 DA_LOG_ERR(Default, "STAGE ADDITION FAIL!");
279                 goto ERR;
280         }
281         DA_LOG(Default, "new added Stage : %p", stage);
282
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;
288
289         ret = __make_source_info_basic_download(stage, client_input);
290         /* to save memory */
291         if (client_input) {
292                 clean_up_client_input_info(client_input);
293                 free(client_input);
294                 client_input = DA_NULL;
295         }
296
297         if (ret == DA_RESULT_OK)
298                 ret = __download_content(stage);
299
300 ERR:
301         if (client_input) {
302                 clean_up_client_input_info(client_input);
303                 free(client_input);
304                 client_input = DA_NULL;
305         }
306
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);
310         } else {
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);
314         }
315
316         pthread_cleanup_pop(0);
317         DA_LOG_CRITICAL(Thread, "=====thread_start_download - EXIT=====");
318         pthread_exit((void *)NULL);
319         return DA_NULL;
320 }
321
322 da_result_t __download_content(stage_info *stage)
323 {
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;
328
329         DA_LOG_FUNC_START(Default);
330
331         download_id = GET_STAGE_DL_ID(stage);
332         CHANGE_DOWNLOAD_STATE(DOWNLOAD_STATE_NEW_DOWNLOAD, stage);
333
334         do {
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)]);
340
341                 switch(download_state) {
342                 case DOWNLOAD_STATE_NEW_DOWNLOAD:
343                         ret = requesting_download(stage);
344
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)]);
348
349                         if (download_state == DOWNLOAD_STATE_CANCELED) {
350                                 break;
351                         }       else {
352                                 if (DA_RESULT_OK == ret) {
353                                         ret = handle_after_download(stage);
354                                 }
355                         }
356                         break;
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);
362                         }
363                         break;
364                 default:
365                         isDownloadComplete = DA_TRUE;
366                         break;
367                 }
368         }while ((DA_RESULT_OK == ret) && (DA_FALSE == isDownloadComplete));
369
370         return ret;
371 }