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