Retry read() when getting EAGAIN
[platform/framework/web/download-provider.git] / agent / download-agent-dl-info.c
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <string.h>
18 #include <stdlib.h>
19 #include <curl/curl.h>
20 #include <pthread.h>
21
22 #ifdef USE_SSL_THREAD_LOCKING
23 #include <openssl/crypto.h>
24 #endif
25
26 #include "download-agent-dl-info.h"
27 #include "download-agent-http-mgr.h"
28 #include "download-agent-http-msg-handler.h"
29
30 static pthread_mutex_t mutex_da_info_list = PTHREAD_MUTEX_INITIALIZER;
31 da_info_t *da_info_list[DA_MAX_ID];
32
33 #ifdef USE_SSL_THREAD_LOCKING
34 static pthread_mutex_t *g_openssl_locks_list;
35
36 /* locking mechnism for safe use of openssl context */
37 static void openssl_lock_callback(int mode, int type, char *file, int line)
38 {
39         DA_LOGV("type [%d], mode [%d]", type, mode);
40         (void)file;
41         (void)line;
42
43         if (mode & CRYPTO_LOCK)
44                 pthread_mutex_lock(&(g_openssl_locks_list[type]));
45         else
46                 pthread_mutex_unlock(&(g_openssl_locks_list[type]));
47 }
48
49 static unsigned long thread_id(void)
50 {
51         unsigned long ret = (unsigned long)pthread_self();
52         return ret;
53 }
54
55 da_ret_t init_openssl_locks(void)
56 {
57         DA_LOGD("");
58         int index;
59         int crypto_num_locks = CRYPTO_num_locks();
60         DA_LOGD("crypto_num_locks [%d]", crypto_num_locks);
61         g_openssl_locks_list = (pthread_mutex_t *)OPENSSL_malloc(crypto_num_locks * sizeof(pthread_mutex_t));
62         if (g_openssl_locks_list == DA_NULL) {
63                 DA_LOGE("Failed to OPENSSL_malloc");
64                 return DA_ERR_FAIL_TO_MEMALLOC;
65         }
66         for (index = 0; index < crypto_num_locks; index++)
67                 pthread_mutex_init(&(g_openssl_locks_list[index]), NULL);
68
69         CRYPTO_set_id_callback((unsigned long (*)())thread_id);
70         CRYPTO_set_locking_callback((void (*)())openssl_lock_callback);
71
72         return DA_RESULT_OK;
73 }
74 da_ret_t deinit_openssl_locks(void)
75 {
76         DA_LOGD("");
77         int index;
78         int crypto_num_locks = CRYPTO_num_locks();
79         for (index = 0; index < crypto_num_locks; index++)
80                 pthread_mutex_destroy(&(g_openssl_locks_list[index]));
81
82         CRYPTO_set_id_callback(NULL);
83         CRYPTO_set_locking_callback(NULL);
84         OPENSSL_free(g_openssl_locks_list);
85         g_openssl_locks_list = NULL;
86
87         return DA_RESULT_OK;
88 }
89 #endif
90
91 static void __init_da_info(int id)
92 {
93         da_info_t *da_info = DA_NULL;
94         file_info_t *file_info = DA_NULL;
95         http_info_t *http_info = DA_NULL;
96         req_info_t *req_info = DA_NULL;
97
98         da_info = (da_info_t *)calloc(1, sizeof(da_info_t));
99         if (!da_info) {
100                 DA_LOGE("Fail to calloc. id[%d]", id);
101                 da_info_list[id] = DA_NULL;
102                 return;
103         }
104         file_info = (file_info_t *)calloc(1, sizeof(file_info_t));
105         if (!file_info) {
106                 DA_LOGE("Fail to calloc. id[%d]", id);
107                 free(da_info);
108                 da_info_list[id] = DA_NULL;
109                 return;
110         }
111         http_info = (http_info_t *)calloc(1, sizeof(http_info_t));
112         if (!http_info) {
113                 DA_LOGE("Fail to calloc. id[%d]", id);
114                 free(da_info);
115                 free(file_info);
116                 da_info_list[id] = DA_NULL;
117                 return;
118         }
119         req_info = (req_info_t *)calloc(1, sizeof(req_info_t));
120         if (!req_info) {
121                 DA_LOGE("Fail to calloc. id[%d]", id);
122                 free(da_info);
123                 free(file_info);
124                 free(http_info);
125                 da_info_list[id] = DA_NULL;
126                 return;
127         }
128
129         da_info->da_id = DA_INVALID_ID;
130         da_info->thread_id = 0;
131         memset(&(da_info->cb_info), 0x00, sizeof(da_cb_t));
132         da_info->is_cb_update = DA_FALSE;
133         da_info->http_info = http_info;
134         da_info->file_info = file_info;
135         da_info->req_info = req_info;
136         da_info->update_time = 0;
137         da_info_list[id] = da_info;
138 }
139
140 da_ret_t init_http_msg_t(http_msg_t **http_msg)
141 {
142         da_ret_t ret = DA_RESULT_OK;
143         http_msg_t *temp = DA_NULL;
144         temp = (http_msg_t *)calloc(1, sizeof(http_msg_t));
145         if (!temp) {
146                 DA_LOGE("Fail to calloc. id");
147                 return DA_ERR_FAIL_TO_MEMALLOC;
148         }
149         *http_msg = temp;
150         return ret;
151 }
152
153 void destroy_http_msg_t(http_msg_t *http_msg)
154 {
155         if (http_msg)
156                 free(http_msg);
157         http_msg = DA_NULL;
158         return;
159 }
160
161 da_ret_t get_available_da_id(int *available_id)
162 {
163         da_ret_t ret = DA_ERR_ALREADY_MAX_DOWNLOAD;
164         int i = 0;
165
166         DA_MUTEX_LOCK(&mutex_da_info_list);
167         for (i = 0; i < DA_MAX_ID; i++) {
168                 if (da_info_list[i] == DA_NULL) {
169                         *available_id = i;
170                         DA_LOGV("available download id[%d]", *available_id);
171                         __init_da_info(i);
172                         ret = DA_RESULT_OK;
173                         break;
174                 }
175         }
176         DA_MUTEX_UNLOCK(&mutex_da_info_list);
177
178         return ret;
179 }
180
181 da_ret_t get_da_info_with_da_id(int id, da_info_t **out_info)
182 {
183         da_ret_t ret = DA_ERR_INVALID_ARGUMENT;
184         int i = 0;
185
186         DA_MUTEX_LOCK(&mutex_da_info_list);
187         for (i = 0; i < DA_MAX_ID; i++) {
188                 if (DA_NULL != da_info_list[i] && da_info_list[i]->da_id == id) {
189                         *out_info = da_info_list[i];
190                         ret = DA_RESULT_OK;
191                         break;
192                 }
193         }
194         DA_MUTEX_UNLOCK(&mutex_da_info_list);
195
196         return ret;
197 }
198
199 da_ret_t __is_supporting_protocol(const char *url)
200 {
201         da_ret_t ret = DA_RESULT_OK;
202         int wanted_str_len = 0;
203         char *protocol = NULL;
204         char *wanted_str_start = NULL;
205         char *wanted_str_end = NULL;
206
207         if (DA_NULL == url || strlen(url) < 1)
208                 return DA_ERR_INVALID_URL;
209
210         wanted_str_start = (char*)url;
211         wanted_str_end = strstr(url, "://");
212         if (!wanted_str_end) {
213                 DA_LOGE("No protocol on this url");
214                 return DA_ERR_INVALID_URL;
215         }
216
217         wanted_str_len = wanted_str_end - wanted_str_start;
218         protocol = (char*)calloc(1, wanted_str_len + 1);
219         if (!protocol) {
220                 DA_LOGE("DA_ERR_FAIL_TO_MEMALLOC");
221                 return DA_ERR_FAIL_TO_MEMALLOC;
222         }
223         strncpy(protocol, wanted_str_start, wanted_str_len);
224
225         if (strlen(protocol) < 1)
226                 ret = DA_ERR_UNSUPPORTED_PROTOCAL;
227         else if (strcasecmp(protocol, "http") != 0 &&
228                         strcasecmp(protocol, "https") != 0)
229                 ret = DA_ERR_UNSUPPORTED_PROTOCAL;
230
231         free(protocol);
232         return ret;
233 }
234
235 da_ret_t copy_user_input_data(da_info_t *da_info, const char *url,
236                 req_data_t *ext_data, da_cb_t *da_cb_data)
237 {
238         da_ret_t ret = DA_RESULT_OK;
239
240         if (!url || !da_info) {
241                 DA_LOGE("Invalid Param");
242                 return DA_ERR_INVALID_ARGUMENT;
243         }
244
245         ret = __is_supporting_protocol(url);
246         if (ret != DA_RESULT_OK) {
247                 DA_SECURE_LOGE("url[%s]", url);
248                 return ret;
249         }
250
251         if (ext_data) {
252                 req_info_t *req_info = da_info->req_info;
253
254                 if (ext_data->request_header_count > 0) {
255                         int i = 0;
256                         int count = ext_data->request_header_count;
257                         req_info->req_header = (char **)calloc(count, sizeof(char *));
258                         if (DA_NULL == req_info->req_header) {
259                                 DA_LOGE("Fail to calloc");
260                                 free(req_info);
261                                 da_info->req_info = DA_NULL;
262                                 return DA_ERR_FAIL_TO_MEMALLOC;
263                         }
264                         for (i = 0; i < count; i++) {
265                                 if (ext_data->request_header[i])
266                                         req_info->req_header[i] =
267                                                         strdup(ext_data->request_header[i]);
268                         }
269                         req_info->req_header_count = count;
270                 }
271
272                 if (url)
273                         req_info->url = strdup(url);
274                 if (ext_data->proxy)
275                         req_info->proxy = strdup(ext_data->proxy);
276                 if (ext_data->install_path)
277                         req_info->install_path = strdup(ext_data->install_path);
278                 if (ext_data->file_name)
279                         req_info->file_name = strdup(ext_data->file_name);
280                 if (ext_data->etag)
281                         req_info->etag = strdup(ext_data->etag);
282                 if (ext_data->temp_file_path)
283                         req_info->temp_file_path = strdup(ext_data->temp_file_path);
284                 if (ext_data->pkg_name)
285                         req_info->pkg_name = strdup(ext_data->pkg_name);
286                 if (ext_data->user_req_data)
287                         req_info->user_req_data = ext_data->user_req_data;
288                 if (ext_data->user_client_data)
289                         req_info->user_client_data = ext_data->user_client_data;
290
291                 req_info->network_bonding = ext_data->network_bonding;
292                 req_info->disable_verify_host = ext_data->disable_verify_host;
293
294                 da_info->req_info = req_info;
295         }
296         if (da_cb_data) {
297                 da_info->is_cb_update = DA_TRUE;
298                 memcpy(&(da_info->cb_info), da_cb_data, sizeof(da_cb_t));
299         }
300         return ret;
301 }
302
303 static void __destroy_http_msg(http_msg_t *msg)
304 {
305         msg->curl = DA_NULL;
306         free(msg);
307 }
308
309 static void __destroy_http_msg_request(http_msg_request_t *msg)
310 {
311         if (msg) {
312                 http_msg_request_destroy(&msg);
313                 free(msg);
314         }
315 }
316
317 static void __destroy_http_msg_response(http_msg_response_t *msg)
318 {
319         if (msg) {
320                 http_msg_response_destroy(&msg);
321                 free(msg);
322         }
323 }
324
325 static void __destroy_req_info(req_info_t *req_info)
326 {
327         if (req_info) {
328                 NULL_CHECK_AND_FREE(req_info->url);
329                 if (req_info->req_header && req_info->req_header_count > 0) {
330                         int i = 0;
331                         int count = req_info->req_header_count;
332                         for (i = 0; i < count; i++)     {
333                                 NULL_CHECK_AND_FREE(req_info->req_header[i]);
334                                 req_info->req_header[i] = DA_NULL;
335                         }
336                         NULL_CHECK_AND_FREE(req_info->req_header);
337                         req_info->req_header = DA_NULL;
338                         req_info->req_header_count = 0;
339                 }
340                 NULL_CHECK_AND_FREE(req_info->proxy);
341                 NULL_CHECK_AND_FREE(req_info->install_path);
342                 NULL_CHECK_AND_FREE(req_info->file_name);
343                 NULL_CHECK_AND_FREE(req_info->etag);
344                 NULL_CHECK_AND_FREE(req_info->temp_file_path);
345                 NULL_CHECK_AND_FREE(req_info->pkg_name);
346                 req_info->user_req_data = DA_NULL;
347                 req_info->user_client_data = DA_NULL;
348                 NULL_CHECK_AND_FREE(req_info);
349         }
350 }
351
352 static void __destroy_proxy_info(proxy_info_t *proxy_info)
353 {
354         if (proxy_info) {
355                 NULL_CHECK_AND_FREE(proxy_info->addr);
356                 proxy_info->addr = DA_NULL;
357                 NULL_CHECK_AND_FREE(proxy_info->user_name);
358                 proxy_info->user_name = DA_NULL;
359                 NULL_CHECK_AND_FREE(proxy_info->password);
360                 proxy_info->password = DA_NULL;
361                 NULL_CHECK_AND_FREE(proxy_info);
362         }
363 }
364
365 void destroy_http_info(http_info_t *http_info)
366 {
367         if (http_info) {
368                 NULL_CHECK_AND_FREE(http_info->location_url);
369                 NULL_CHECK_AND_FREE(http_info->content_type_from_header);
370                 NULL_CHECK_AND_FREE(http_info->etag_from_header);
371                 NULL_CHECK_AND_FREE(http_info->file_name_from_header);
372                 if (http_info->proxy_info) {
373                         __destroy_proxy_info(http_info->proxy_info);
374                         http_info->proxy_info = DA_NULL;
375                 }
376                 if (http_info->http_msg_request) {
377                         __destroy_http_msg_request(http_info->http_msg_request);
378                         http_info->http_msg_request = DA_NULL;
379                 }
380                 if (http_info->http_msg_response) {
381                         __destroy_http_msg_response(http_info->http_msg_response);
382                         http_info->http_msg_response = DA_NULL;
383                 }
384                 if (http_info->http_msg) {
385                         __destroy_http_msg(http_info->http_msg);
386                         http_info->http_msg = DA_NULL;
387                 }
388                 DA_MUTEX_DESTROY(&(http_info->mutex_state));
389                 DA_MUTEX_DESTROY(&(http_info->mutex_http));
390                 DA_COND_DESTROY(&(http_info->cond_http));
391                 NULL_CHECK_AND_FREE(http_info);
392         }
393 }
394
395 void destroy_file_info(file_info_t *file_info)
396 {
397         if (file_info) {
398                 file_info->file_handle = DA_NULL;
399                 NULL_CHECK_AND_FREE(file_info->pure_file_name);
400                 NULL_CHECK_AND_FREE(file_info->extension);
401                 NULL_CHECK_AND_FREE(file_info->file_path);
402                 NULL_CHECK_AND_FREE(file_info->mime_type);
403                 NULL_CHECK_AND_FREE(file_info->buffer);
404                 file_info->buffer_len = 0;
405                 file_info->file_size = 0;
406 #ifdef _RAF_SUPPORT
407                 file_info->file_size_of_temp_file = 0;
408 #endif
409                 file_info->bytes_written_to_file = 0;
410                 file_info->is_updated = DA_FALSE;
411                 NULL_CHECK_AND_FREE(file_info);
412         }
413 }
414
415 // For pause and resume case
416 void reset_http_info_for_resume(http_info_t *http_info)
417 {
418         if (http_info) {
419                 DA_LOGI("[TEST] location_url[%p]", http_info->location_url);
420                 NULL_CHECK_AND_FREE(http_info->location_url);
421                 http_info->location_url = DA_NULL;
422                 NULL_CHECK_AND_FREE(http_info->content_type_from_header);
423                 http_info->content_type_from_header = DA_NULL;
424                 if (http_info->proxy_info) {
425                         __destroy_proxy_info(http_info->proxy_info);
426                         http_info->proxy_info = DA_NULL;
427                 }
428                 if (http_info->http_msg_response) {
429                         __destroy_http_msg_response(http_info->http_msg_response);
430                         http_info->http_msg_response = DA_NULL;
431                 }
432                 if (http_info->http_msg) {
433                         __destroy_http_msg(http_info->http_msg);
434                         http_info->http_msg = DA_NULL;
435                 }
436                 http_info->http_method = HTTP_METHOD_GET;
437                 http_info->content_len_from_header = 0;
438                 http_info->total_size = 0;
439         }
440 }
441
442 da_bool_t is_valid_download_id(int download_id)
443 {
444         da_ret_t ret = DA_RESULT_OK;
445
446         DA_LOGV("");
447         DA_MUTEX_LOCK(&mutex_da_info_list);
448         if (DA_NULL == da_info_list[download_id]) {
449                 DA_MUTEX_UNLOCK(&mutex_da_info_list);
450                 return DA_FALSE;
451         }
452         if (is_stopped_state(da_info_list[download_id])) {
453                 DA_MUTEX_UNLOCK(&mutex_da_info_list);
454                 return DA_TRUE;
455         }
456         if (da_info_list[download_id]->da_id != DA_INVALID_ID) {
457                 DA_MUTEX_UNLOCK(&mutex_da_info_list);
458                 return DA_TRUE;
459         } else {
460                 DA_MUTEX_UNLOCK(&mutex_da_info_list);
461                 return DA_FALSE;
462         }
463         DA_MUTEX_UNLOCK(&mutex_da_info_list);
464         return ret;
465 }
466
467 void destroy_da_info_list()
468 {
469         int i = 0;
470         DA_MUTEX_LOCK(&mutex_da_info_list);
471         for (i = 0; i < DA_MAX_ID; i++) {
472                 if (DA_NULL != da_info_list[i]) {
473                         if (da_info_list[i]->thread_id) {
474                                 DA_LOGI("%lu is running. wait for the download thread.",
475                                                 da_info_list[i]->thread_id);
476                                 pthread_join(da_info_list[i]->thread_id, NULL);
477                         }
478
479                         if (da_info_list[i]->req_info) {
480                                 __destroy_req_info(da_info_list[i]->req_info);
481                                 da_info_list[i]->req_info = DA_NULL;
482                         }
483                         if (da_info_list[i]->http_info) {
484                                 destroy_http_info(da_info_list[i]->http_info);
485                                 da_info_list[i]->http_info = DA_NULL;
486                         }
487                         if (da_info_list[i]->file_info) {
488                                 destroy_file_info(da_info_list[i]->file_info);
489                                 da_info_list[i]->file_info = DA_NULL;
490                         }
491                         free(da_info_list[i]);
492                         da_info_list[i] = DA_NULL;
493                 }
494         }
495         DA_MUTEX_UNLOCK(&mutex_da_info_list);
496 }
497
498 void destroy_da_info(int id)
499 {
500         da_info_t *da_info = DA_NULL;
501         DA_MUTEX_LOCK(&mutex_da_info_list);
502         da_info = da_info_list[id];
503         if (da_info) {
504                 if (da_info->req_info) {
505                         __destroy_req_info(da_info->req_info);
506                         da_info->req_info = DA_NULL;
507                 }
508                 if (da_info->http_info) {
509                         destroy_http_info(da_info->http_info);
510                         da_info->http_info = DA_NULL;
511                 }
512                 if (da_info->file_info) {
513                         destroy_file_info(da_info->file_info);
514                         da_info->file_info = DA_NULL;
515                 }
516                 da_info->da_id = DA_INVALID_ID;
517                 da_info->thread_id = 0;
518                 memset(&(da_info->cb_info), 0x00, sizeof(da_cb_t));
519                 free(da_info);
520                 da_info_list[id] = DA_NULL;
521         }
522         DA_MUTEX_UNLOCK(&mutex_da_info_list);
523 }