merge with master
[platform/framework/web/download-provider.git] / agent / download-agent-client-mgr.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 <unistd.h>
18
19 #include "download-agent-client-mgr.h"
20 #include "download-agent-debug.h"
21 #include "download-agent-utils.h"
22 #include "download-agent-file.h"
23
24 #define IS_CLIENT_Q_HAVING_DATA(QUEUE)  (QUEUE->having_data)
25
26 static client_app_mgr_t client_app_mgr;
27
28 static da_result_t __launch_client_thread(void);
29 static void *__thread_for_client_noti(void *data);
30 void __thread_clean_up_handler_for_client_thread(void *arg);
31 static void __pop_client_noti(client_noti_t **out_client_noti);
32
33 void __client_q_goto_sleep_without_lock(void);
34 void __client_q_wake_up_without_lock(void);
35 void destroy_client_noti(client_noti_t *client_noti);
36
37 da_result_t init_client_app_mgr()
38 {
39         DA_LOG_FUNC_START(ClientNoti);
40
41         if(client_app_mgr.is_init)
42                 return DA_RESULT_OK;
43
44         client_app_mgr.is_init = DA_TRUE;
45         client_app_mgr.client_app_info.client_user_agent = DA_NULL;
46         client_app_mgr.is_thread_init = DA_FALSE;
47
48         return DA_RESULT_OK;
49 }
50
51 da_bool_t is_client_app_mgr_init(void)
52 {
53         return client_app_mgr.is_init;
54 }
55
56 da_result_t reg_client_app(
57                 da_client_cb_t *da_client_callback)
58 {
59         da_result_t ret = DA_RESULT_OK;
60         client_queue_t *queue = DA_NULL;
61         client_noti_t *client_noti = DA_NULL;
62
63         DA_LOG_FUNC_START(ClientNoti);
64
65         memset(&(client_app_mgr.client_app_info.client_callback),
66                         0, sizeof(da_client_cb_t));
67         memcpy(&(client_app_mgr.client_app_info.client_callback),
68                         da_client_callback, sizeof(da_client_cb_t));
69
70         _da_thread_mutex_init(&(client_app_mgr.mutex_client_mgr), DA_NULL);
71
72         /* If some noti is existed at queue, delete all */
73         do {
74                 __pop_client_noti(&client_noti);
75                 destroy_client_noti(client_noti);
76         } while(client_noti != DA_NULL);
77
78         queue = &(client_app_mgr.client_queue);
79         DA_LOG_VERBOSE(ClientNoti, "client queue = %p", queue);
80         _da_thread_mutex_init(&(queue->mutex_client_queue), DA_NULL);
81         _da_thread_cond_init(&(queue->cond_client_queue), DA_NULL);
82
83         ret = __launch_client_thread();
84
85         return ret;
86 }
87
88 da_result_t dereg_client_app(void)
89 {
90         client_noti_t *client_noti = DA_NULL;
91
92         DA_LOG_FUNC_START(ClientNoti);
93
94         client_noti = (client_noti_t *)calloc(1, sizeof(client_noti_t));
95         if (!client_noti) {
96                 DA_LOG_ERR(ClientNoti, "calloc fail");
97                 return DA_ERR_FAIL_TO_MEMALLOC;
98         }
99
100         client_noti->slot_id = DA_INVALID_ID;
101         client_noti->noti_type = Q_CLIENT_NOTI_TYPE_TERMINATE;
102         client_noti->next = DA_NULL;
103
104         _da_thread_mutex_lock(&(client_app_mgr.mutex_client_mgr));
105         if (client_app_mgr.is_thread_init != DA_TRUE) {
106                 DA_LOG_CRITICAL(ClientNoti, "try to cancel client mgr thread id[%lu]", client_app_mgr.thread_id);
107                 if (pthread_cancel(client_app_mgr.thread_id) < 0) {
108                         DA_LOG_ERR(ClientNoti, "cancel thread is failed!!!");
109                 }
110                 free(client_noti);
111         } else {
112                 void *t_return = NULL;
113                 DA_LOG_VERBOSE(ClientNoti, "pushing Q_CLIENT_NOTI_TYPE_TERMINATE");
114                 push_client_noti(client_noti);
115                 DA_LOG_CRITICAL(Thread, "===try to join client mgr thread id[%lu]===", client_app_mgr.thread_id);
116                 if (pthread_join(client_app_mgr.thread_id, &t_return) < 0) {
117                         DA_LOG_ERR(Thread, "join client thread is failed!!!");
118                 }
119                 DA_LOG_CRITICAL(Thread, "===thread join return[%d]===", (char*)t_return);
120         }
121         _da_thread_mutex_unlock(&(client_app_mgr.mutex_client_mgr));
122
123         /* ToDo: This clean up should be done at the end of client_thread. */
124         if(client_app_mgr.client_app_info.client_user_agent) {
125                 free(client_app_mgr.client_app_info.client_user_agent);
126                 client_app_mgr.client_app_info.client_user_agent = DA_NULL;
127         }
128         _da_thread_mutex_lock(&(client_app_mgr.mutex_client_mgr));
129         client_app_mgr.is_thread_init = DA_FALSE;
130         _da_thread_mutex_unlock(&(client_app_mgr.mutex_client_mgr));
131         _da_thread_mutex_destroy(&(client_app_mgr.mutex_client_mgr));
132         return DA_RESULT_OK;
133 }
134
135 da_result_t send_client_paused_info(int slot_id)
136 {
137         client_noti_t *client_noti = DA_NULL;
138         user_paused_info_t *paused_info = DA_NULL;
139         download_state_t state = GET_DL_STATE_ON_ID(slot_id);
140
141         DA_LOG_FUNC_START(ClientNoti);
142
143         if (!GET_DL_ENABLE_PAUSE_UPDATE(slot_id)) {
144                 DA_LOG(ClientNoti, "Do not call pause cb");
145                 return DA_RESULT_OK;
146         }
147         if (!is_valid_slot_id(slot_id)) {
148                 DA_LOG_ERR(ClientNoti, "Download ID is not valid");
149                 return DA_RESULT_OK;
150         }
151
152         DA_LOG_VERBOSE(ClientNoti, "slot_id[%d]", slot_id);
153         if ((DOWNLOAD_STATE_PAUSED != state)) {
154                 DA_LOG(ClientNoti, "The state is not paused. state:%d", state);
155                 return DA_ERR_INVALID_STATE;
156         }
157
158         client_noti = (client_noti_t *)calloc(1, sizeof(client_noti_t));
159         if (!client_noti) {
160                 DA_LOG_ERR(ClientNoti, "calloc fail");
161                 return DA_ERR_FAIL_TO_MEMALLOC;
162         }
163
164         client_noti->slot_id = slot_id;
165         client_noti->user_data = GET_DL_USER_DATA(slot_id);
166         client_noti->noti_type = Q_CLIENT_NOTI_TYPE_PAUSED_INFO;
167         client_noti->next = DA_NULL;
168
169         paused_info = (user_paused_info_t *)&(client_noti->type.paused_info);
170         paused_info->download_id= GET_DL_ID(slot_id);
171         DA_LOG(ClientNoti, "pushing paused info. slot_id=%d, dl_id=%d",
172                         slot_id, GET_DL_ID(slot_id));
173
174         push_client_noti(client_noti);
175
176         return DA_RESULT_OK;
177 }
178
179 da_result_t  send_client_update_progress_info (
180                 int slot_id,
181                 int dl_id,
182                 unsigned long int received_size
183                 )
184 {
185         client_noti_t *client_noti = DA_NULL;
186         user_progress_info_t *progress_info = DA_NULL;
187
188         //DA_LOG_FUNC_START(ClientNoti);
189
190         if (!is_valid_slot_id(slot_id)) {
191                 DA_LOG_ERR(ClientNoti, "Download ID is not valid");
192                 return DA_ERR_INVALID_DL_REQ_ID;
193         }
194
195         client_noti = (client_noti_t *)calloc(1, sizeof(client_noti_t));
196         if (!client_noti) {
197                 DA_LOG_ERR(ClientNoti, "calloc fail");
198                 return DA_ERR_FAIL_TO_MEMALLOC;
199         }
200
201         client_noti->slot_id = slot_id;
202         client_noti->user_data = GET_DL_USER_DATA(slot_id);
203         client_noti->noti_type = Q_CLIENT_NOTI_TYPE_PROGRESS_INFO;
204         client_noti->next = DA_NULL;
205
206         progress_info = (user_progress_info_t *)&(client_noti->type.update_progress_info);
207         progress_info->download_id= dl_id;
208         progress_info->received_size = received_size;
209
210         DA_LOG_VERBOSE(ClientNoti, "pushing received_size=%lu, slot_id=%d, dl_id=%d",
211                         received_size, slot_id, dl_id);
212
213         push_client_noti(client_noti);
214
215         return DA_RESULT_OK;
216 }
217
218 da_result_t  send_client_update_dl_info (
219                 int slot_id,
220                 int dl_id,
221                 char *file_type,
222                 unsigned long int file_size,
223                 char *tmp_saved_path,
224                 char *pure_file_name,
225                 char *etag,
226                 char *extension)
227 {
228         client_noti_t *client_noti = DA_NULL;
229         user_download_info_t *update_dl_info = DA_NULL;
230         int len = 0;
231
232         DA_LOG_FUNC_START(ClientNoti);
233
234         if (!is_valid_slot_id(slot_id)) {
235                 DA_LOG_ERR(ClientNoti, "Download ID is not valid");
236                 return DA_ERR_INVALID_DL_REQ_ID;
237         }
238
239         client_noti = (client_noti_t *)calloc(1, sizeof(client_noti_t));
240         if (!client_noti) {
241                 DA_LOG_ERR(ClientNoti, "calloc fail");
242                 return DA_ERR_FAIL_TO_MEMALLOC;
243         }
244
245         client_noti->slot_id = slot_id;
246         client_noti->user_data = GET_DL_USER_DATA(slot_id);
247         client_noti->noti_type = Q_CLIENT_NOTI_TYPE_STARTED_INFO;
248         client_noti->next = DA_NULL;
249
250         update_dl_info = (user_download_info_t *)&(client_noti->type.update_dl_info);
251         update_dl_info->download_id = dl_id;
252         update_dl_info->file_size = file_size;
253         if (pure_file_name && extension) {
254                 len = strlen(pure_file_name) + strlen(extension) + 1;
255                 update_dl_info->content_name = (char *)calloc(len + 1, sizeof(char));
256                 if (!update_dl_info->content_name) {
257                         free(client_noti);
258                         return DA_ERR_FAIL_TO_MEMALLOC;
259                 }
260                 snprintf(update_dl_info->content_name, len + 1, "%s.%s",
261                                 pure_file_name, extension);
262         }
263
264         /* These strings MUST be copied to detach __thread_for_client_noti from download_info */
265         if (file_type)
266                 update_dl_info->file_type = strdup(file_type);
267
268         if (tmp_saved_path)
269                 update_dl_info->tmp_saved_path = strdup(tmp_saved_path);
270
271         if (etag)
272                 update_dl_info->etag = strdup(etag);
273         DA_LOG(ClientNoti, "pushing file_size=%lu, slot_id=%d, dl_id=%d",
274                         file_size, slot_id, dl_id);
275
276         push_client_noti(client_noti);
277
278         return DA_RESULT_OK;
279 }
280
281 da_result_t  send_client_finished_info (
282                 int slot_id,
283                 int dl_id,
284                 char *saved_path,
285                 char *etag,
286                 int error,
287                 int http_status
288                 )
289 {
290         client_noti_t *client_noti = DA_NULL;
291         user_finished_info_t *finished_info = DA_NULL;
292
293         DA_LOG_FUNC_START(ClientNoti);
294
295         if (!is_valid_slot_id(slot_id)) {
296                 DA_LOG_ERR(ClientNoti, "Download ID is not valid");
297                 return DA_ERR_INVALID_DL_REQ_ID;
298         }
299
300         client_noti = (client_noti_t *)calloc(1, sizeof(client_noti_t));
301         if (!client_noti) {
302                 DA_LOG_ERR(ClientNoti, "calloc fail");
303                 return DA_ERR_FAIL_TO_MEMALLOC;
304         }
305
306         client_noti->slot_id = slot_id;
307         client_noti->user_data = GET_DL_USER_DATA(slot_id);
308         client_noti->noti_type = Q_CLIENT_NOTI_TYPE_FINISHED_INFO;
309         client_noti->next = DA_NULL;
310
311         finished_info = (user_finished_info_t *)&(client_noti->type.finished_info);
312         finished_info->download_id = dl_id;
313         finished_info->err = error;
314         finished_info->http_status = http_status;
315
316         if (saved_path) {
317                 finished_info->saved_path = strdup(saved_path);
318                 DA_LOG(ClientNoti, "saved path=%s", saved_path);
319         }
320         if (etag) {
321                 finished_info->etag = strdup(etag);
322                 DA_LOG(ClientNoti, "pushing finished info. etag[%s]", etag);
323         }
324         DA_LOG(ClientNoti, "user_data=%p", client_noti->user_data);
325         DA_LOG(ClientNoti, "http_status=%d", http_status);
326         DA_LOG(ClientNoti, "pushing slot_id=%d, dl_id=%d err=%d", slot_id, dl_id, error);
327
328         push_client_noti(client_noti);
329
330         return DA_RESULT_OK;
331 }
332
333 da_result_t  __launch_client_thread(void)
334 {
335         pthread_t thread_id = DA_NULL;
336
337         DA_LOG_FUNC_START(Thread);
338
339         if (pthread_create(&thread_id,DA_NULL,__thread_for_client_noti,DA_NULL) < 0) {
340                 DA_LOG_ERR(Thread, "making thread failed..");
341                 return DA_ERR_FAIL_TO_CREATE_THREAD;
342         }
343         DA_LOG(Thread, "client mgr thread id[%d]", thread_id);
344         client_app_mgr.thread_id = thread_id;
345         return DA_RESULT_OK;
346 }
347
348 void destroy_client_noti(client_noti_t *client_noti)
349 {
350         if (client_noti) {
351                 if (client_noti->noti_type == Q_CLIENT_NOTI_TYPE_STARTED_INFO) {
352                         user_download_info_t *update_dl_info = DA_NULL;
353                         update_dl_info = (user_download_info_t*)&(client_noti->type.update_dl_info);
354                         if (update_dl_info->file_type) {
355                                 free(update_dl_info->file_type);
356                                 update_dl_info->file_type = DA_NULL;
357                         }
358                         if (update_dl_info->tmp_saved_path) {
359                                 free(update_dl_info->tmp_saved_path);
360                                 update_dl_info->tmp_saved_path = DA_NULL;
361                         }
362                         if (update_dl_info->etag) {
363                                 free(update_dl_info->etag);
364                                 update_dl_info->etag = DA_NULL;
365                         }
366                 } else if (client_noti->noti_type ==
367                                 Q_CLIENT_NOTI_TYPE_FINISHED_INFO) {
368                         user_finished_info_t *finished_info = DA_NULL;
369                         finished_info = (user_finished_info_t*)
370                                 &(client_noti->type.finished_info);
371                         if (finished_info->saved_path) {
372                                 free(finished_info->saved_path);
373                                 finished_info->saved_path = DA_NULL;
374                         }
375                         if (finished_info->etag) {
376                                 free(finished_info->etag);
377                                 finished_info->etag = DA_NULL;
378                         }
379                 }
380                 free(client_noti);
381         }
382 }
383
384
385 void push_client_noti(client_noti_t *client_noti)
386 {
387         client_queue_t *queue = DA_NULL;
388         client_noti_t *head = DA_NULL;
389         client_noti_t *pre = DA_NULL;
390         client_noti_t *cur = DA_NULL;
391
392         /* DA_LOG_FUNC_START(ClientNoti); */
393
394         queue = &(client_app_mgr.client_queue);
395         _da_thread_mutex_lock (&(queue->mutex_client_queue));
396
397         head = queue->client_q_head;
398         if (!head) {
399                 queue->client_q_head = client_noti;
400         } else {
401                 cur = head;
402                 while (cur->next) {
403                         pre = cur;
404                         cur = pre->next;
405                 }
406 #if 0
407                 if (cur->noti_type == Q_CLIENT_NOTI_TYPE_PROGRESS_INFO) {
408                         /* For UI performance. If the update noti info is existed at queue,
409                            replace it with new update noti info */
410                         if (cur->slot_id == client_noti->slot_id) {
411                                 /* DA_LOG(ClientNoti, "exchange queue's tail and pushing item"); */
412                                 if (pre == DA_NULL)
413                                         queue->client_q_head = client_noti;
414                                 else
415                                         pre->next = client_noti;
416                                 destroy_client_noti(cur);
417                         } else {
418                                 cur->next = client_noti;
419                         }
420                 } else {
421                         cur->next = client_noti;
422                 }
423 #else
424         cur->next = client_noti;
425 #endif
426         }
427
428         queue->having_data = DA_TRUE;
429
430         __client_q_wake_up_without_lock();
431         if (queue->client_q_head->next) {
432                 DA_LOG_VERBOSE(ClientNoti, "client noti[%p] next noti[%p]",
433                                 queue->client_q_head, queue->client_q_head->next);
434         } else {
435                 DA_LOG_VERBOSE(ClientNoti, "client noti[%p] next noti is NULL",
436                                 queue->client_q_head);
437         }
438
439         _da_thread_mutex_unlock (&(queue->mutex_client_queue));
440 }
441
442 void __pop_client_noti(client_noti_t **out_client_noti)
443 {
444         client_queue_t *queue = DA_NULL;
445
446         /* DA_LOG_FUNC_START(ClientNoti); */
447
448         queue = &(client_app_mgr.client_queue);
449
450         _da_thread_mutex_lock (&(queue->mutex_client_queue));
451
452         if (queue->client_q_head) {
453                 *out_client_noti = queue->client_q_head;
454                 queue->client_q_head = queue->client_q_head->next;
455                 if (queue->client_q_head) {
456                         DA_LOG_VERBOSE(ClientNoti, "client noti[%p] next noti[%p]",
457                                         *out_client_noti, queue->client_q_head);
458                 } else {
459                         DA_LOG_VERBOSE(ClientNoti, "client noti[%p] next noti is NULL",
460                                         *out_client_noti);
461                 }
462         } else {
463                 *out_client_noti = DA_NULL;
464         }
465
466         if (queue->client_q_head == DA_NULL) {
467                 queue->having_data = DA_FALSE;
468         }
469
470         _da_thread_mutex_unlock (&(queue->mutex_client_queue));
471 }
472
473 void __client_q_goto_sleep_without_lock(void)
474 {
475         client_queue_t *queue = DA_NULL;
476
477         /* DA_LOG_FUNC_START(ClientNoti); */
478
479         queue = &(client_app_mgr.client_queue);
480         _da_thread_cond_wait(&(queue->cond_client_queue), &(queue->mutex_client_queue));
481 }
482
483 void __client_q_wake_up_without_lock(void)
484 {
485         client_queue_t *queue = DA_NULL;
486
487         /* DA_LOG_FUNC_START(ClientNoti); */
488
489         queue = &(client_app_mgr.client_queue);
490         _da_thread_cond_signal(&(queue->cond_client_queue));
491 }
492
493 void __thread_clean_up_handler_for_client_thread(void *arg)
494 {
495         DA_LOG_CRITICAL(Thread, "cleanup for thread id = %d", pthread_self());
496 }
497
498 static void *__thread_for_client_noti(void *data)
499 {
500         da_result_t  ret = DA_RESULT_OK;
501         da_bool_t need_wait = DA_TRUE;
502         client_queue_t *queue = DA_NULL;
503         client_noti_t *client_noti = DA_NULL;
504
505         //DA_LOG_FUNC_START(Thread);
506
507         _da_thread_mutex_lock(&(client_app_mgr.mutex_client_mgr));
508         client_app_mgr.is_thread_init = DA_TRUE;
509         _da_thread_mutex_unlock(&(client_app_mgr.mutex_client_mgr));
510
511         queue = &(client_app_mgr.client_queue);
512         DA_LOG_VERBOSE(ClientNoti, "client queue = %p", queue);
513
514         pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, DA_NULL);
515         pthread_cleanup_push(__thread_clean_up_handler_for_client_thread, (void *)DA_NULL);
516
517         do {
518                 _da_thread_mutex_lock(&(queue->mutex_client_queue));
519                 if (DA_FALSE == IS_CLIENT_Q_HAVING_DATA(queue)) {
520                         DA_LOG_VERBOSE(Thread, "Sleep @ thread_for_client_noti!");
521                         __client_q_goto_sleep_without_lock();
522                         DA_LOG_VERBOSE(Thread, "Woke up @ thread_for_client_noti");
523                 }
524                 _da_thread_mutex_unlock(&(queue->mutex_client_queue));
525
526                 do {
527                         __pop_client_noti(&client_noti);
528                         if (client_noti == DA_NULL) {
529                                 DA_LOG_ERR(ClientNoti, "There is no data on client queue!");
530                                 ret = DA_ERR_INVALID_STATE;
531                                 need_wait = DA_FALSE;
532                         } else {
533                                 DA_LOG_VERBOSE(ClientNoti, "noti type[%d]",
534                                                 client_noti->noti_type);
535                                 switch (client_noti->noti_type) {
536                                 case Q_CLIENT_NOTI_TYPE_STARTED_INFO:
537                                 {
538                                         user_download_info_t *update_dl_info = DA_NULL;;
539                                         update_dl_info = (user_download_info_t*)(&(client_noti->type.update_dl_info));
540                                         if (client_app_mgr.client_app_info.client_callback.update_dl_info_cb) {
541                                                 client_app_mgr.client_app_info.client_callback.update_dl_info_cb(update_dl_info, client_noti->user_data);
542                                                 if (update_dl_info->etag)
543                                                         DA_LOG(ClientNoti, "Etag:[%s]", update_dl_info->etag);
544                                                 DA_LOG(ClientNoti, "Update download info for slot_id=%d, dl_id=%d, received size=%lu- DONE",
545                                                                 client_noti->slot_id,
546                                                                 update_dl_info->download_id,
547                                                                 update_dl_info->file_size
548                                                                 );
549                                         }
550                                 }
551                                 break;
552                                 case Q_CLIENT_NOTI_TYPE_PROGRESS_INFO:
553                                 {
554                                         user_progress_info_t *progress_info = DA_NULL;;
555                                         progress_info = (user_progress_info_t*)(&(client_noti->type.update_progress_info));
556                                         if (client_app_mgr.client_app_info.client_callback.update_progress_info_cb) {
557                                                 client_app_mgr.client_app_info.client_callback.update_progress_info_cb(progress_info, client_noti->user_data);
558                                                 DA_LOG_VERBOSE(ClientNoti, "Update downloading info for slot_id=%d, dl_id=%d, received size=%lu - DONE",
559                                                                 client_noti->slot_id,
560                                                                 progress_info->download_id,
561                                                                 progress_info->received_size);
562                                         }
563                                 }
564                                 break;
565                                 case Q_CLIENT_NOTI_TYPE_FINISHED_INFO:
566                                 {
567                                         user_finished_info_t *finished_info = DA_NULL;;
568                                         finished_info = (user_finished_info_t*)(&(client_noti->type.finished_info));
569                                         if (client_app_mgr.client_app_info.client_callback.finished_info_cb) {
570                                                 client_app_mgr.client_app_info.client_callback.finished_info_cb(
571                                                         finished_info, client_noti->user_data);
572                                                 DA_LOG(ClientNoti, "Completed info for slot_id=%d, dl_id=%d, saved_path=%s etag=%s err=%d http_state=%d user_data=%p- DONE",
573                                                                 client_noti->slot_id,
574                                                                 finished_info->download_id,
575                                                                 finished_info->saved_path,
576                                                                 finished_info->etag,
577                                                                 finished_info->err,
578                                                                 finished_info->http_status,
579                                                                 client_noti->user_data);
580                                         }
581                                 }
582                                 break;
583                                 case Q_CLIENT_NOTI_TYPE_PAUSED_INFO:
584                                 {
585                                         user_paused_info_t *da_paused_info = DA_NULL;
586                                         da_paused_info = (user_paused_info_t *)(&(client_noti->type.paused_info));
587
588                                         if (client_app_mgr.client_app_info.client_callback.paused_info_cb) {
589                                                 DA_LOG(ClientNoti, "User Paused info for slot_id=%d, dl_id=%d - Done",
590                                                                 client_noti->slot_id,
591                                                                 da_paused_info->download_id);
592                                                 client_app_mgr.client_app_info.client_callback.paused_info_cb(
593                                                         da_paused_info, client_noti->user_data);
594                                         }
595                                 }
596                                 break;
597                                 case Q_CLIENT_NOTI_TYPE_TERMINATE:
598                                         DA_LOG_CRITICAL(ClientNoti, "Q_CLIENT_NOTI_TYPE_TERMINATE");
599                                         need_wait = DA_FALSE;
600                                         break;
601                                 }
602                                 destroy_client_noti(client_noti);
603                         }
604
605                         if(DA_TRUE == need_wait) {
606                                 _da_thread_mutex_lock(&(queue->mutex_client_queue));
607                                 if (DA_FALSE == IS_CLIENT_Q_HAVING_DATA(queue)) {
608                                         _da_thread_mutex_unlock (&(queue->mutex_client_queue));
609                                         break;
610                                 } else {
611                                         _da_thread_mutex_unlock (&(queue->mutex_client_queue));
612                                 }
613                         } else {
614                                 break;
615                         }
616                 } while (1);
617         } while (DA_TRUE == need_wait);
618
619         _da_thread_mutex_destroy(&(queue->mutex_client_queue));
620         _da_thread_cond_destroy(&(queue->cond_client_queue));
621
622         pthread_cleanup_pop(0);
623         DA_LOG_CRITICAL(Thread, "=====thread_for_client_noti- EXIT=====");
624         pthread_exit((void *)NULL);
625         return DA_NULL;
626 }
627
628 char *get_client_user_agent_string(void)
629 {
630         if (!client_app_mgr.is_init)
631                 return DA_NULL;
632
633         return client_app_mgr.client_app_info.client_user_agent;
634 }