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 <curl/curl.h>
22 #ifdef USE_SSL_THREAD_LOCKING
23 #include <openssl/crypto.h>
26 #include "download-agent-dl-info.h"
27 #include "download-agent-http-mgr.h"
28 #include "download-agent-http-msg-handler.h"
30 static pthread_mutex_t mutex_da_info_list = PTHREAD_MUTEX_INITIALIZER;
31 da_info_t *da_info_list[DA_MAX_ID];
33 #ifdef USE_SSL_THREAD_LOCKING
34 static pthread_mutex_t *g_openssl_locks_list;
36 /* locking mechnism for safe use of openssl context */
37 static void openssl_lock_callback(int mode, int type, char *file, int line)
39 DA_LOGV("type [%d], mode [%d]", type, mode);
43 if (mode & CRYPTO_LOCK)
44 pthread_mutex_lock(&(g_openssl_locks_list[type]));
46 pthread_mutex_unlock(&(g_openssl_locks_list[type]));
49 static unsigned long thread_id(void)
51 unsigned long ret = (unsigned long)pthread_self();
55 da_ret_t init_openssl_locks(void)
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;
66 for (index = 0; index < crypto_num_locks; index++)
67 pthread_mutex_init(&(g_openssl_locks_list[index]), NULL);
69 CRYPTO_set_id_callback((unsigned long (*)())thread_id);
70 CRYPTO_set_locking_callback((void (*)())openssl_lock_callback);
74 da_ret_t deinit_openssl_locks(void)
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]));
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;
91 static void __init_da_info(int id)
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;
98 da_info = (da_info_t *)calloc(1, sizeof(da_info_t));
100 DA_LOGE("Fail to calloc. id[%d]", id);
101 da_info_list[id] = DA_NULL;
104 file_info = (file_info_t *)calloc(1, sizeof(file_info_t));
106 DA_LOGE("Fail to calloc. id[%d]", id);
108 da_info_list[id] = DA_NULL;
111 http_info = (http_info_t *)calloc(1, sizeof(http_info_t));
113 DA_LOGE("Fail to calloc. id[%d]", id);
116 da_info_list[id] = DA_NULL;
119 req_info = (req_info_t *)calloc(1, sizeof(req_info_t));
121 DA_LOGE("Fail to calloc. id[%d]", id);
125 da_info_list[id] = DA_NULL;
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;
140 da_ret_t init_http_msg_t(http_msg_t **http_msg)
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));
146 DA_LOGE("Fail to calloc. id");
147 return DA_ERR_FAIL_TO_MEMALLOC;
153 void destroy_http_msg_t(http_msg_t *http_msg)
161 da_ret_t get_available_da_id(int *available_id)
163 da_ret_t ret = DA_ERR_ALREADY_MAX_DOWNLOAD;
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) {
170 DA_LOGV("available download id[%d]", *available_id);
176 DA_MUTEX_UNLOCK(&mutex_da_info_list);
181 da_ret_t get_da_info_with_da_id(int id, da_info_t **out_info)
183 da_ret_t ret = DA_ERR_INVALID_ARGUMENT;
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];
194 DA_MUTEX_UNLOCK(&mutex_da_info_list);
199 da_ret_t __is_supporting_protocol(const char *url)
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;
207 if (DA_NULL == url || strlen(url) < 1)
208 return DA_ERR_INVALID_URL;
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;
217 wanted_str_len = wanted_str_end - wanted_str_start;
218 protocol = (char*)calloc(1, wanted_str_len + 1);
220 DA_LOGE("DA_ERR_FAIL_TO_MEMALLOC");
221 return DA_ERR_FAIL_TO_MEMALLOC;
223 strncpy(protocol, wanted_str_start, wanted_str_len);
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;
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)
238 da_ret_t ret = DA_RESULT_OK;
240 if (!url || !da_info) {
241 DA_LOGE("Invalid Param");
242 return DA_ERR_INVALID_ARGUMENT;
245 ret = __is_supporting_protocol(url);
246 if (ret != DA_RESULT_OK) {
247 DA_SECURE_LOGE("url[%s]", url);
252 req_info_t *req_info = da_info->req_info;
254 if (ext_data->request_header_count > 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");
261 da_info->req_info = DA_NULL;
262 return DA_ERR_FAIL_TO_MEMALLOC;
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]);
269 req_info->req_header_count = count;
273 req_info->url = strdup(url);
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);
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;
291 req_info->network_bonding = ext_data->network_bonding;
292 req_info->disable_verify_host = ext_data->disable_verify_host;
294 da_info->req_info = req_info;
297 da_info->is_cb_update = DA_TRUE;
298 memcpy(&(da_info->cb_info), da_cb_data, sizeof(da_cb_t));
303 static void __destroy_http_msg(http_msg_t *msg)
309 static void __destroy_http_msg_request(http_msg_request_t *msg)
312 http_msg_request_destroy(&msg);
317 static void __destroy_http_msg_response(http_msg_response_t *msg)
320 http_msg_response_destroy(&msg);
325 static void __destroy_req_info(req_info_t *req_info)
328 NULL_CHECK_AND_FREE(req_info->url);
329 if (req_info->req_header && req_info->req_header_count > 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;
336 NULL_CHECK_AND_FREE(req_info->req_header);
337 req_info->req_header = DA_NULL;
338 req_info->req_header_count = 0;
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);
352 static void __destroy_proxy_info(proxy_info_t *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);
365 void destroy_http_info(http_info_t *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;
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;
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;
384 if (http_info->http_msg) {
385 __destroy_http_msg(http_info->http_msg);
386 http_info->http_msg = DA_NULL;
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);
395 void destroy_file_info(file_info_t *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;
407 file_info->file_size_of_temp_file = 0;
409 file_info->bytes_written_to_file = 0;
410 file_info->is_updated = DA_FALSE;
411 NULL_CHECK_AND_FREE(file_info);
415 // For pause and resume case
416 void reset_http_info_for_resume(http_info_t *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;
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;
432 if (http_info->http_msg) {
433 __destroy_http_msg(http_info->http_msg);
434 http_info->http_msg = DA_NULL;
436 http_info->http_method = HTTP_METHOD_GET;
437 http_info->content_len_from_header = 0;
438 http_info->total_size = 0;
442 da_bool_t is_valid_download_id(int download_id)
444 da_ret_t ret = DA_RESULT_OK;
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);
452 if (is_stopped_state(da_info_list[download_id])) {
453 DA_MUTEX_UNLOCK(&mutex_da_info_list);
456 if (da_info_list[download_id]->da_id != DA_INVALID_ID) {
457 DA_MUTEX_UNLOCK(&mutex_da_info_list);
460 DA_MUTEX_UNLOCK(&mutex_da_info_list);
463 DA_MUTEX_UNLOCK(&mutex_da_info_list);
467 void destroy_da_info_list()
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);
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;
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;
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;
491 free(da_info_list[i]);
492 da_info_list[i] = DA_NULL;
495 DA_MUTEX_UNLOCK(&mutex_da_info_list);
498 void destroy_da_info(int id)
500 da_info_t *da_info = DA_NULL;
501 DA_MUTEX_LOCK(&mutex_da_info_list);
502 da_info = da_info_list[id];
504 if (da_info->req_info) {
505 __destroy_req_info(da_info->req_info);
506 da_info->req_info = DA_NULL;
508 if (da_info->http_info) {
509 destroy_http_info(da_info->http_info);
510 da_info->http_info = DA_NULL;
512 if (da_info->file_info) {
513 destroy_file_info(da_info->file_info);
514 da_info->file_info = DA_NULL;
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));
520 da_info_list[id] = DA_NULL;
522 DA_MUTEX_UNLOCK(&mutex_da_info_list);