3 #include <sys/socket.h>
12 #include "download-provider-config.h"
13 #include "download-provider-log.h"
14 #include "download-provider-pthread.h"
15 #include "download-provider-notification.h"
16 #include "download-provider-ipc.h"
17 #include "download-provider-db.h"
18 #include "download-provider-utils.h"
20 #include "download-agent-defs.h"
21 #include "download-agent-interface.h"
23 int _init_agent(void);
24 void _deinit_agent(void);
25 static void __downloading_info_cb(user_downloading_info_t *download_info,
27 static void __download_info_cb(user_download_info_t *download_info,
29 static void __notify_cb(user_notify_info_t *notify_info, void *user_data);
30 static int __change_error(int err);
31 static int __change_state(da_state state);
33 void TerminateDaemon(int signo);
35 pthread_attr_t g_download_provider_thread_attr;
36 fd_set g_download_provider_socket_readset;
37 fd_set g_download_provider_socket_exceptset;
39 int _change_pended_download(download_clientinfo *clientinfo)
43 clientinfo->state = DOWNLOAD_STATE_PENDED;
44 clientinfo->err = DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS;
45 download_provider_db_requestinfo_update_column(clientinfo, DOWNLOAD_DB_STATE);
46 ipc_send_request_stateinfo(clientinfo);
50 void *_start_download(void *args)
55 download_clientinfo_slot *clientinfoslot =
56 (download_clientinfo_slot *) args;
57 if (!clientinfoslot) {
58 TRACE_DEBUG_MSG("[NULL-CHECK] download_clientinfo_slot");
61 download_clientinfo *clientinfo =
62 (download_clientinfo *) clientinfoslot->clientinfo;
64 TRACE_DEBUG_MSG("[NULL-CHECK] download_clientinfo");
68 CLIENT_MUTEX_LOCK(&(clientinfo->client_mutex));
69 clientinfo->state = DOWNLOAD_STATE_READY;
70 clientinfo->err = DOWNLOAD_ERROR_NONE;
71 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
73 // call start_download() of download-agent
74 if (clientinfo->requestinfo->headers.rows > 0) {
77 char **req_header = NULL;
78 len = clientinfo->requestinfo->headers.rows;
79 req_header = calloc(len, sizeof(char *));
81 TRACE_DEBUG_MSG("fail to calloc");
84 for (i = 0; i < len; i++)
86 strdup(clientinfo->requestinfo->headers.str[i].str);
87 if (clientinfo->requestinfo->install_path.length > 1) {
88 if (clientinfo->requestinfo->filename.length > 1)
90 da_start_download_with_extension(clientinfo->requestinfo->
92 DA_FEATURE_REQUEST_HEADER,
94 DA_FEATURE_INSTALL_PATH,
95 clientinfo->requestinfo->install_path.str,
97 clientinfo->requestinfo->filename.str,
99 (void *)clientinfoslot,
103 da_start_download_with_extension(clientinfo->requestinfo->
105 DA_FEATURE_REQUEST_HEADER,
107 DA_FEATURE_INSTALL_PATH,
108 clientinfo->requestinfo->install_path.str,
109 DA_FEATURE_USER_DATA,
110 (void *)clientinfoslot,
113 if (clientinfo->requestinfo->filename.length > 1)
115 da_start_download_with_extension(clientinfo->requestinfo->
117 DA_FEATURE_REQUEST_HEADER,
119 DA_FEATURE_FILE_NAME,
120 clientinfo->requestinfo->filename.str,
121 DA_FEATURE_USER_DATA,
122 (void *)clientinfoslot,
126 da_start_download_with_extension(clientinfo->requestinfo->
128 DA_FEATURE_REQUEST_HEADER,
130 DA_FEATURE_USER_DATA,
131 (void *)clientinfoslot,
134 for (i = 0; i < len; i++) {
139 if (clientinfo->requestinfo->install_path.length > 1) {
140 if (clientinfo->requestinfo->filename.length > 1)
142 da_start_download_with_extension(clientinfo->requestinfo->
144 DA_FEATURE_INSTALL_PATH,
145 clientinfo->requestinfo->install_path.str,
146 DA_FEATURE_FILE_NAME,
147 clientinfo->requestinfo->filename.str,
148 DA_FEATURE_USER_DATA,
149 (void *)clientinfoslot,
153 da_start_download_with_extension(clientinfo->requestinfo->
155 DA_FEATURE_INSTALL_PATH,
156 clientinfo->requestinfo->install_path.str,
157 DA_FEATURE_USER_DATA,
158 (void *)clientinfoslot,
161 if (clientinfo->requestinfo->filename.length > 1)
163 da_start_download_with_extension(clientinfo->requestinfo->
165 DA_FEATURE_FILE_NAME,
166 clientinfo->requestinfo->filename.str,
167 DA_FEATURE_USER_DATA,
168 (void *)clientinfoslot,
172 da_start_download_with_extension(clientinfo->requestinfo->
174 DA_FEATURE_USER_DATA,
175 (void *)clientinfoslot,
180 // if start_download() return error cause of maximun download limitation,
181 // set state to DOWNLOAD_STATE_PENDED.
182 if (da_ret == DA_ERR_ALREADY_MAX_DOWNLOAD) {
183 TRACE_DEBUG_INFO_MSG("change to pended request [%d]", da_ret);
184 CLIENT_MUTEX_LOCK(&(clientinfo->client_mutex));
185 _change_pended_download(clientinfo);
186 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
188 } else if (da_ret != DA_RESULT_OK) {
189 TRACE_DEBUG_INFO_MSG("Fail to request start [%d]", da_ret);
190 /* FIXME : need to seperate in detail according to error return values */
191 CLIENT_MUTEX_LOCK(&(clientinfo->client_mutex));
192 clientinfo->state = DOWNLOAD_STATE_FAILED;
193 clientinfo->err = DOWNLOAD_ERROR_INVALID_PARAMETER;
194 download_provider_db_requestinfo_remove(clientinfo->
195 requestinfo->requestid);
196 ipc_send_request_stateinfo(clientinfo);
197 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
201 CLIENT_MUTEX_LOCK(&(clientinfo->client_mutex));
203 TRACE_DEBUG_INFO_MSG("started download [%d]", da_ret);
205 clientinfo->req_id = req_dl_id;
206 clientinfo->state = DOWNLOAD_STATE_DOWNLOADING;
207 clientinfo->err = DOWNLOAD_ERROR_NONE;
209 download_provider_db_requestinfo_update_column(clientinfo,
212 // sync return // client should be alive till this line at least.
213 ipc_send_request_stateinfo(clientinfo);
215 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
219 int _create_download_thread(download_clientinfo_slot *clientinfo_slot)
221 if (!clientinfo_slot)
224 // create thread for receiving the reqeust info from client.
225 // and if possible, it will create the thread for listening the event.
226 clientinfo_slot->clientinfo->state = DOWNLOAD_STATE_READY;
227 clientinfo_slot->clientinfo->err = DOWNLOAD_ERROR_NONE;
229 (&clientinfo_slot->clientinfo->thread_pid,
230 &g_download_provider_thread_attr, _start_download,
231 clientinfo_slot) != 0) {
232 TRACE_DEBUG_INFO_MSG("failed to call pthread_create for client");
233 TRACE_DEBUG_INFO_MSG("Change to pended job");
234 _change_pended_download(clientinfo_slot->clientinfo);
240 int _handle_new_connection(download_clientinfo_slot *clientinfo_list, download_clientinfo *request_clientinfo)
243 unsigned active_count = 0;
246 if (!clientinfo_list || !request_clientinfo ) {
247 TRACE_DEBUG_MSG("NULL-CHECK");
251 CLIENT_MUTEX_INIT(&(request_clientinfo->client_mutex), NULL);
255 sizeof(request_clientinfo->credentials);
257 (request_clientinfo->clientfd, SOL_SOCKET,
258 SO_PEERCRED, &request_clientinfo->credentials,
261 ("Client Info : pid=%d, uid=%d, gid=%d\n",
262 request_clientinfo->credentials.pid,
263 request_clientinfo->credentials.uid,
264 request_clientinfo->credentials.gid);
268 download_controls type =
269 ipc_receive_header(request_clientinfo->clientfd);
270 TRACE_DEBUG_INFO_MSG("[ACCEPT] HEADER : [%d] ", type);
271 // first of all, receive requestinfo .
272 if (type <= 0 || ipc_receive_request_msg(request_clientinfo) < 0) {
273 TRACE_DEBUG_MSG("Ignore this connection, Invalid command");
274 clear_clientinfo(request_clientinfo);
278 if (type == DOWNLOAD_CONTROL_STOP
279 || type == DOWNLOAD_CONTROL_GET_STATE_INFO
280 || type == DOWNLOAD_CONTROL_RESUME
281 || type == DOWNLOAD_CONTROL_PAUSE) {
282 // get requestid from socket.
283 if (request_clientinfo->requestinfo
284 && request_clientinfo->requestinfo->requestid > 0) {
285 // search requestid in slots.
286 int searchindex = get_same_request_slot_index
288 request_clientinfo->requestinfo->requestid);
289 if (type == DOWNLOAD_CONTROL_STOP) {
290 TRACE_DEBUG_INFO_MSG("Request : DOWNLOAD_CONTROL_STOP");
291 if (searchindex >= 0) {
292 if (da_cancel_download
293 (clientinfo_list[searchindex].clientinfo->req_id)
295 request_clientinfo->state = DOWNLOAD_STATE_STOPPED;
296 request_clientinfo->err = DOWNLOAD_ERROR_NONE;
297 if (clientinfo_list[searchindex].clientinfo->requestinfo
298 && clientinfo_list[searchindex].clientinfo->requestinfo->notification)
299 set_downloadedinfo_appfw_notification(clientinfo_list[searchindex].clientinfo);
300 download_provider_db_requestinfo_remove(request_clientinfo->requestinfo->requestid);
301 download_provider_db_history_new(clientinfo_list[searchindex].clientinfo);
303 request_clientinfo->state = DOWNLOAD_STATE_FAILED;
304 request_clientinfo->err = DOWNLOAD_ERROR_INVALID_PARAMETER;
307 request_clientinfo->state = DOWNLOAD_STATE_NONE;
308 request_clientinfo->err = DOWNLOAD_ERROR_NONE;
310 ipc_send_stateinfo(request_clientinfo);
311 } else if (type == DOWNLOAD_CONTROL_GET_STATE_INFO) {
312 // search slots/downloading db/history db
313 if (searchindex > 0) { // exist in slots (memory)
314 request_clientinfo->state =
315 clientinfo_list[searchindex].clientinfo->state;
316 request_clientinfo->err =
317 clientinfo_list[searchindex].clientinfo->err;
318 } else { //search downloading db or history db
319 download_dbinfo* dbinfo =
320 download_provider_db_get_info(
321 request_clientinfo->requestinfo->requestid);
322 if (dbinfo) { // found in downloading db..it means crashed job
323 request_clientinfo->state = DOWNLOAD_STATE_PENDED;
324 request_clientinfo->err = DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS;
325 } else { // no exist in downloading db
326 dbinfo = download_provider_db_history_get_info(
327 request_clientinfo->requestinfo->requestid);
328 if (!dbinfo) { // no info anywhere
329 request_clientinfo->state = DOWNLOAD_STATE_NONE;
330 request_clientinfo->err = DOWNLOAD_ERROR_NONE;
331 } else { //history info
332 request_clientinfo->state = dbinfo->state;
333 request_clientinfo->err = DOWNLOAD_ERROR_NONE;
336 download_provider_db_info_free(dbinfo);
339 ipc_send_stateinfo(request_clientinfo);
340 // estabilish the spec of return value.
341 } else if (type == DOWNLOAD_CONTROL_PAUSE) {
342 if (searchindex >= 0) {
343 if (da_suspend_download
344 (clientinfo_list[searchindex].clientinfo->req_id)
346 request_clientinfo->state = DOWNLOAD_STATE_PAUSE_REQUESTED;
347 request_clientinfo->err = DOWNLOAD_ERROR_NONE;
349 request_clientinfo->state = DOWNLOAD_STATE_FAILED;
350 request_clientinfo->err = DOWNLOAD_ERROR_INVALID_PARAMETER;
353 request_clientinfo->state = DOWNLOAD_STATE_NONE;
354 request_clientinfo->err = DOWNLOAD_ERROR_NONE;
356 ipc_send_stateinfo(request_clientinfo);
357 } else if (type == DOWNLOAD_CONTROL_RESUME) {
358 if (searchindex >= 0) {
359 if (da_resume_download
360 (clientinfo_list[searchindex].clientinfo->req_id)
362 request_clientinfo->state = DOWNLOAD_STATE_DOWNLOADING;
363 request_clientinfo->err = DOWNLOAD_ERROR_NONE;
365 request_clientinfo->state = DOWNLOAD_STATE_FAILED;
366 request_clientinfo->err = DOWNLOAD_ERROR_INVALID_PARAMETER;
369 request_clientinfo->state = DOWNLOAD_STATE_NONE;
370 request_clientinfo->err = DOWNLOAD_ERROR_NONE;
372 ipc_send_stateinfo(request_clientinfo);
374 ipc_receive_header(request_clientinfo->clientfd);
376 clear_clientinfo(request_clientinfo);
380 if (type != DOWNLOAD_CONTROL_START) {
382 ("Now, DOWNLOAD_CONTROL_START is only supported");
383 clear_clientinfo(request_clientinfo);
387 // check whether requestinfo has requestid or not.
388 if (request_clientinfo->requestinfo
389 && request_clientinfo->requestinfo->requestid > 0) {
390 // search same request id.
391 int searchindex = get_same_request_slot_index(clientinfo_list,
392 request_clientinfo->requestinfo->requestid);
393 if (searchindex < 0) {
394 TRACE_DEBUG_INFO_MSG("Not Found Same Request ID");
395 /* Try to search history db */
396 download_dbinfo *dbinfo = download_provider_db_history_get_info(
397 request_clientinfo->requestinfo->requestid);
398 if (dbinfo == NULL) {
399 /* Try to serach downloading db. The crashed job can not be uploaded to memory */
400 dbinfo = download_provider_db_get_info(
401 request_clientinfo->requestinfo->requestid);
402 if (dbinfo == NULL) {
404 request_clientinfo->state = DOWNLOAD_STATE_FAILED;
405 request_clientinfo->err = DOWNLOAD_ERROR_INVALID_PARAMETER;
406 ipc_send_request_stateinfo(request_clientinfo);
407 clear_clientinfo(request_clientinfo);
411 download_provider_db_info_free(dbinfo);
413 } else { // found request id. // how to deal etag ?
415 TRACE_DEBUG_INFO_MSG("Found Same Request ID slot[%d]", searchindex);
416 CLIENT_MUTEX_LOCK(&(request_clientinfo->client_mutex));
417 // close previous socket.
418 if (clientinfo_list[searchindex].clientinfo->clientfd > 0)
419 close(clientinfo_list[searchindex].clientinfo->clientfd);
420 // change to new socket.
421 clientinfo_list[searchindex].clientinfo->clientfd =
422 request_clientinfo->clientfd;
424 clientinfo_list[searchindex].clientinfo->requestinfo->callbackinfo =
425 request_clientinfo->requestinfo->callbackinfo;
426 clientinfo_list[searchindex].clientinfo->requestinfo->notification =
427 request_clientinfo->requestinfo->notification;
428 request_clientinfo->clientfd = 0; // prevent to not be disconnected.
429 CLIENT_MUTEX_UNLOCK(&(request_clientinfo->client_mutex));
430 clear_clientinfo(request_clientinfo);
432 if (clientinfo_list[searchindex].clientinfo->state
433 == DOWNLOAD_STATE_READY
434 || clientinfo_list[searchindex].clientinfo->state
435 >= DOWNLOAD_STATE_FINISHED) {
436 active_count = get_downloading_count(clientinfo_list);
437 if (active_count >= DA_MAX_DOWNLOAD_REQ_AT_ONCE) {
438 // deal as pended job.
439 _change_pended_download(clientinfo_list[searchindex].clientinfo);
440 TRACE_DEBUG_INFO_MSG ("Pended Request is saved to [%d/%d]",
441 searchslot, MAX_CLIENT);
443 _create_download_thread(&clientinfo_list[searchindex]);
445 ipc_send_request_stateinfo(clientinfo_list[searchindex].clientinfo);
451 searchslot = get_empty_slot_index(clientinfo_list);
452 if (searchslot < 0) {
453 TRACE_DEBUG_MSG("download-provider is busy, try later");
454 clear_clientinfo(request_clientinfo);
455 sleep(5); // provider need the time of refresh.
458 // create new unique id, and insert info to DB.
459 if (request_clientinfo->requestinfo
460 && request_clientinfo->requestinfo->requestid <= 0) {
461 request_clientinfo->requestinfo->requestid =
462 get_download_request_id();
463 if (download_provider_db_requestinfo_new
464 (request_clientinfo) < 0) {
465 clear_clientinfo(request_clientinfo);
466 sleep(5); // provider need the time of refresh.
471 clientinfo_list[searchslot].clientinfo = request_clientinfo;
473 active_count = get_downloading_count(clientinfo_list);
475 TRACE_DEBUG_INFO_MSG("New Connection slot [%d/%d] active [%d/%d]",
479 DA_MAX_DOWNLOAD_REQ_AT_ONCE);
481 if (active_count >= DA_MAX_DOWNLOAD_REQ_AT_ONCE) {
482 // deal as pended job.
483 _change_pended_download(clientinfo_list[searchslot].clientinfo);
484 TRACE_DEBUG_INFO_MSG ("Pended Request is saved to [%d/%d]",
485 searchslot, MAX_CLIENT);
488 unsigned free_slot_count
489 = DA_MAX_DOWNLOAD_REQ_AT_ONCE - active_count;
490 int pendedslot = get_pended_slot_index(clientinfo_list);
491 if(pendedslot >= 0) {
492 TRACE_DEBUG_INFO_MSG ("Free Space [%d]", free_slot_count);
493 for (;free_slot_count > 0 && pendedslot >= 0; free_slot_count--) {
494 TRACE_DEBUG_INFO_MSG ("Start pended job [%d]", pendedslot);
495 _create_download_thread(&clientinfo_list[pendedslot]);
496 pendedslot = get_pended_slot_index(clientinfo_list);
500 if (free_slot_count <= 0) { // change to PENDED
501 // start pended job, deal this job to pended
502 _change_pended_download(clientinfo_list[searchslot].clientinfo);
503 TRACE_DEBUG_INFO_MSG ("Pended Request is saved to [%d/%d]",
504 searchslot, MAX_CLIENT);
506 _create_download_thread(&clientinfo_list[searchslot]);
511 int _handle_client_request(download_clientinfo* clientinfo)
518 TRACE_DEBUG_MSG("NULL-CHECK");
522 switch (msgType = ipc_receive_header(clientinfo->clientfd)) {
523 case DOWNLOAD_CONTROL_STOP:
524 if (clientinfo->state >= DOWNLOAD_STATE_FINISHED) {
525 // clear slot requested by client after finished download
526 TRACE_DEBUG_INFO_MSG("request Free slot to main thread");
527 clear_socket(clientinfo);
530 TRACE_DEBUG_INFO_MSG("DOWNLOAD_CONTROL_STOP");
531 da_ret = da_cancel_download(clientinfo->req_id);
532 CLIENT_MUTEX_LOCK(&(clientinfo->client_mutex));
533 if (da_ret != DA_RESULT_OK) {
534 /* FIXME : need to seperate in detail according to error return values */
535 clientinfo->state = DOWNLOAD_STATE_FAILED;
536 clientinfo->err = DOWNLOAD_ERROR_INVALID_PARAMETER;
537 TRACE_DEBUG_MSG("Fail to request cancel [%d]", da_ret);
539 clientinfo->state = DOWNLOAD_STATE_STOPPED;
540 clientinfo->err = DOWNLOAD_ERROR_NONE;
541 if (clientinfo->requestinfo) {
542 if (clientinfo->requestinfo->notification)
543 set_downloadedinfo_appfw_notification(clientinfo);
544 download_provider_db_requestinfo_remove(clientinfo->
545 requestinfo->requestid);
547 download_provider_db_history_new(clientinfo);
549 ipc_send_stateinfo(clientinfo);
550 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
552 case DOWNLOAD_CONTROL_PAUSE:
553 TRACE_DEBUG_INFO_MSG("DOWNLOAD_CONTROL_PAUSE");
554 da_ret = da_suspend_download(clientinfo->req_id);
555 CLIENT_MUTEX_LOCK(&(clientinfo->client_mutex));
556 if (da_ret != DA_RESULT_OK) {
557 /* FIXME : need to seperate in detail according to error return values */
558 clientinfo->state = DOWNLOAD_STATE_FAILED;
559 clientinfo->err = DOWNLOAD_ERROR_INVALID_PARAMETER;
560 TRACE_DEBUG_MSG("Fail to request suspend [%d]", da_ret);
562 clientinfo->state = DOWNLOAD_STATE_PAUSE_REQUESTED;
563 clientinfo->err = DOWNLOAD_ERROR_NONE;
565 ipc_send_stateinfo(clientinfo);
566 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
568 case DOWNLOAD_CONTROL_RESUME:
569 TRACE_DEBUG_INFO_MSG("DOWNLOAD_CONTROL_RESUME");
570 da_ret = da_resume_download(clientinfo->req_id);
571 CLIENT_MUTEX_LOCK(&(clientinfo->client_mutex));
572 if (da_ret != DA_RESULT_OK) {
573 /* FIXME : need to seperate in detail according to error return values */
574 clientinfo->state = DOWNLOAD_STATE_FAILED;
575 clientinfo->err = DOWNLOAD_ERROR_INVALID_PARAMETER;
576 TRACE_DEBUG_MSG("Fail to request resume [%d]", da_ret);
578 clientinfo->state = DOWNLOAD_STATE_DOWNLOADING;
579 clientinfo->err = DOWNLOAD_ERROR_NONE;
581 ipc_send_stateinfo(clientinfo);
582 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
584 case DOWNLOAD_CONTROL_GET_STATE_INFO: // sync call
585 TRACE_DEBUG_INFO_MSG("DOWNLOAD_CONTROL_GET_STATE_INFO");
586 CLIENT_MUTEX_LOCK(&(clientinfo->client_mutex));
587 ipc_send_stateinfo(clientinfo);
588 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
590 case DOWNLOAD_CONTROL_GET_DOWNLOAD_INFO: // sync call
591 TRACE_DEBUG_INFO_MSG("DOWNLOAD_CONTROL_GET_DOWNLOAD_INFO");
592 CLIENT_MUTEX_LOCK(&(clientinfo->client_mutex));
593 ipc_send_downloadinfo(clientinfo);
594 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
598 TRACE_DEBUG_MSG("(Closed Socket ) terminate event thread (%d)",
600 // bloken socket... it seems the client is dead or closed by agent thread.
601 // close socket, this will break the loop. and terminate this thread.
602 clear_socket(clientinfo);
605 TRACE_DEBUG_MSG("Unknow message [%d]", msgType);
611 void *run_manage_download_server(void *args)
613 int listenfd = 0; // main socket to be albe to listen the new connection
616 fd_set rset, exceptset;
617 struct timeval timeout;
618 long flexible_timeout;
619 download_clientinfo_slot *clientinfo_list;
621 unsigned active_count = 0;
622 download_clientinfo *request_clientinfo;
628 struct sockaddr_un listenaddr, clientaddr;
630 GMainLoop *mainloop = (GMainLoop *) args;
633 if (ret != DOWNLOAD_ERROR_NONE) {
634 TRACE_DEBUG_MSG("failed to init agent");
635 TerminateDaemon(SIGTERM);
638 clear_downloadinginfo_appfw_notification();
640 if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
641 TRACE_DEBUG_MSG("failed to create socket");
642 TerminateDaemon(SIGTERM);
646 bzero(&listenaddr, sizeof(listenaddr));
647 listenaddr.sun_family = AF_UNIX;
648 strcpy(listenaddr.sun_path, DOWNLOAD_PROVIDER_IPC);
650 if (bind(listenfd, (struct sockaddr *)&listenaddr, sizeof listenaddr) !=
652 TRACE_DEBUG_MSG("failed to call bind");
653 TerminateDaemon(SIGTERM);
657 if (chmod(listenaddr.sun_path, 0777) < 0) {
659 ("failed to change the permission of socket file");
660 TerminateDaemon(SIGTERM);
664 if (listen(listenfd, MAX_CLIENT) != 0) {
665 TRACE_DEBUG_MSG("failed to call listen");
666 TerminateDaemon(SIGTERM);
671 TRACE_DEBUG_INFO_MSG("Ready to listen IPC [%d][%s]", listenfd,
672 DOWNLOAD_PROVIDER_IPC);
674 // allocation the array structure for managing the clients.
676 (download_clientinfo_slot *) calloc(MAX_CLIENT,
677 sizeof(download_clientinfo_slot));
678 if (clientinfo_list == NULL) {
679 TRACE_DEBUG_MSG("failed to allocate the memory for client list");
680 TerminateDaemon(SIGTERM);
684 if (pthread_attr_init(&g_download_provider_thread_attr) != 0) {
685 TRACE_DEBUG_MSG("failed to call pthread_attr_init for client");
686 TerminateDaemon(SIGTERM);
689 if (pthread_attr_setdetachstate(&g_download_provider_thread_attr,
690 PTHREAD_CREATE_DETACHED) != 0) {
691 TRACE_DEBUG_MSG("failed to set detach option");
692 TerminateDaemon(SIGTERM);
696 flexible_timeout = DOWNLOAD_PROVIDER_CARE_CLIENT_MIN_INTERVAL;
698 FD_ZERO(&g_download_provider_socket_readset);
699 FD_ZERO(&g_download_provider_socket_exceptset);
700 FD_SET(listenfd, &g_download_provider_socket_readset);
701 FD_SET(listenfd, &g_download_provider_socket_exceptset);
703 while (g_main_loop_is_running(mainloop)) {
706 for (i = 0; i < MAX_CLIENT; i++) {
707 if (!clientinfo_list[i].clientinfo)
710 if (clientinfo_list[i].clientinfo->state >= DOWNLOAD_STATE_FINISHED) {
711 if (clientinfo_list[i].clientinfo->clientfd <= 0)
712 clear_clientinfoslot(&clientinfo_list[i]);
718 rset = g_download_provider_socket_readset;
719 exceptset = g_download_provider_socket_exceptset;
721 memset(&timeout, 0x00, sizeof(struct timeval));
722 timeout.tv_sec = flexible_timeout;
724 if (select((maxfd + 1), &rset, 0, &exceptset, &timeout) < 0) {
726 ("select error, provider can't receive any request from client.");
727 TerminateDaemon(SIGTERM);
731 for (i = 0; i < MAX_CLIENT; i++) { // find the socket received the packet.
732 if (!clientinfo_list[i].clientinfo)
734 //Even if no socket, downloading should be progressed.
735 if (clientinfo_list[i].clientinfo->clientfd <= 0)
737 if (FD_ISSET(clientinfo_list[i].clientinfo->clientfd, &rset) > 0) {
738 // ignore it is not started yet.
739 if (clientinfo_list[i].clientinfo->state <= DOWNLOAD_STATE_READY)
741 TRACE_DEBUG_INFO_MSG("FD_ISSET [%d] readset slot[%d]",
742 clientinfo_list[i].clientinfo->clientfd, i);
743 _handle_client_request(clientinfo_list[i].clientinfo);
746 } else if (FD_ISSET(clientinfo_list[i].clientinfo->clientfd, &exceptset) > 0) {
747 TRACE_DEBUG_MSG("FD_ISSET [%d] exceptset slot[%d]", clientinfo_list[i].clientinfo->clientfd, i);
748 clear_clientinfoslot(&clientinfo_list[i]);
752 if (FD_ISSET(listenfd, &exceptset) > 0) {
753 TRACE_DEBUG_MSG("meet listenfd Exception of socket");
754 TerminateDaemon(SIGTERM);
756 } else if (FD_ISSET(listenfd, &rset) > 0) { // new connection
757 TRACE_DEBUG_INFO_MSG("FD_ISSET listenfd rset");
762 DOWNLOAD_PROVIDER_CARE_CLIENT_MIN_INTERVAL;
765 (download_clientinfo *) calloc(1,
766 sizeof(download_clientinfo));
767 if (!request_clientinfo) {
769 ("download-provider can't allocate the memory, try later");
770 clientlen = sizeof(clientaddr);
771 int clientfd = accept(listenfd,
772 (struct sockaddr *)&clientaddr, &clientlen);
773 close(clientfd); // disconnect.
774 sleep(5); // provider need the time of refresh.
778 clientlen = sizeof(clientaddr);
779 request_clientinfo->clientfd = accept(listenfd,
780 (struct sockaddr*)&clientaddr,
782 if (request_clientinfo->clientfd < 0) {
783 clear_clientinfo(request_clientinfo);
784 sleep(5); // provider need the time of refresh.
787 if (_handle_new_connection(clientinfo_list, request_clientinfo) < 0) {
791 // after starting the download by DA, event thread will start to get the event from client.
792 if (request_clientinfo && request_clientinfo->clientfd > 0) {
793 FD_SET(request_clientinfo->clientfd, &g_download_provider_socket_readset); // add new descriptor to set
794 FD_SET(request_clientinfo->clientfd, &g_download_provider_socket_exceptset);
795 if (request_clientinfo->clientfd > maxfd )
796 maxfd = request_clientinfo->clientfd; /* for select */
800 if (is_timeout) { // timeout
801 // If there is better solution to be able to know
802 // the number of downloading threads, replace below rough codes.
803 active_count = get_downloading_count(clientinfo_list);
804 // check whether the number of downloading is already maximum.
805 if (active_count >= DA_MAX_DOWNLOAD_REQ_AT_ONCE)
808 unsigned free_slot_count
809 = DA_MAX_DOWNLOAD_REQ_AT_ONCE - active_count;
810 int pendedslot = get_pended_slot_index(clientinfo_list);
811 if(pendedslot >= 0) {
812 TRACE_DEBUG_INFO_MSG ("Free Space [%d]", free_slot_count);
813 for (;free_slot_count > 0 && pendedslot >= 0; free_slot_count--) {
814 TRACE_DEBUG_INFO_MSG ("start pended job [%d]", pendedslot);
815 if (_create_download_thread(&clientinfo_list[pendedslot]) > 0)
817 pendedslot = get_pended_slot_index(clientinfo_list);
821 if (check_retry && free_slot_count > 0) {
822 // Auto re-download feature.
823 // ethernet may be connected with other downloading items.
824 if (get_network_status() < 0)
827 // check auto-retrying list regardless state. pended state is also included to checking list.
829 download_dbinfo_list *db_list =
830 download_provider_db_get_list(DOWNLOAD_STATE_NONE);
831 if (!db_list || db_list->count <= 0) {
833 ("provider does not need to check DB anymore. in this life.");
834 // provider does not need to check DB anymore. in this life.
837 download_provider_db_list_free(db_list);
842 DA_MAX_DOWNLOAD_REQ_AT_ONCE
843 && i < db_list->count; i++) {
844 if (db_list->item[i].requestid <= 0)
846 if (get_same_request_slot_index
847 (clientinfo_list,db_list->item[i].requestid) < 0) {
848 // not found requestid in memory
850 ("Retry download [%d]",
851 db_list->item[i].requestid);
852 //search empty slot. copy db info to slot.
854 get_empty_slot_index(clientinfo_list);
855 if (searchslot < 0) {
857 ("download-provider is busy, try later");
859 flexible_timeout * 2;
862 // allocte requestinfo to empty slot.
864 (download_clientinfo *)
865 calloc(1, sizeof(download_clientinfo));
866 if (!request_clientinfo)
868 request_clientinfo->requestinfo
870 download_provider_db_get_requestinfo
872 if (!request_clientinfo->requestinfo) {
873 free(request_clientinfo);
874 request_clientinfo = NULL;
878 CLIENT_MUTEX_INIT(&(request_clientinfo->client_mutex), NULL);
879 request_clientinfo->state = DOWNLOAD_STATE_READY;
880 clientinfo_list[searchslot].clientinfo =
884 ("Retry download [%d/%d][%d/%d]",
885 searchslot, MAX_CLIENT,
887 DA_MAX_DOWNLOAD_REQ_AT_ONCE);
888 if (_create_download_thread(&clientinfo_list[searchslot]) > 0)
892 if (i >= db_list->count) // do not search anymore.
894 download_provider_db_list_free(db_list);
897 // save system resource (CPU)
898 if (check_retry == 0 && active_count == 0
899 && flexible_timeout <
900 DOWNLOAD_PROVIDER_CARE_CLIENT_MAX_INTERVAL)
901 flexible_timeout = flexible_timeout * 2;
902 if (flexible_timeout >
903 DOWNLOAD_PROVIDER_CARE_CLIENT_MAX_INTERVAL)
905 DOWNLOAD_PROVIDER_CARE_CLIENT_MAX_INTERVAL;
906 TRACE_DEBUG_INFO_MSG("Next Timeout after [%ld] sec",
909 } // if (i >= MAX_CLIENT) { // timeout
912 FD_CLR(listenfd, &rset);
913 FD_CLR(listenfd, &exceptset);
914 FD_CLR(listenfd, &g_download_provider_socket_readset);
915 FD_CLR(listenfd, &g_download_provider_socket_exceptset);
917 // close accept socket.
923 // close all sockets for client. ..
924 // client thread will terminate by itself through catching this closing.
925 for (searchslot = 0; searchslot < MAX_CLIENT; searchslot++)
926 if (clientinfo_list[searchslot].clientinfo)
927 clear_clientinfoslot(&clientinfo_list[searchslot]);
930 free(clientinfo_list);
936 void __download_info_cb(user_download_info_t *download_info, void *user_data)
940 TRACE_DEBUG_MSG("[CRITICAL] clientinfoslot is NULL");
943 download_clientinfo_slot *clientinfoslot =
944 (download_clientinfo_slot *) user_data;
945 download_clientinfo *clientinfo =
946 (download_clientinfo *) clientinfoslot->clientinfo;
948 TRACE_DEBUG_MSG("[CRITICAL] clientinfo is NULL");
951 TRACE_DEBUG_INFO_MSG("id[%d],size[%lu]",
952 download_info->da_dl_req_id, download_info->file_size);
954 if (clientinfo->req_id != download_info->da_dl_req_id) {
955 TRACE_DEBUG_MSG("[CRITICAL] req_id[%d] da_dl_req_id[%d}",
957 download_info->da_dl_req_id);
960 CLIENT_MUTEX_LOCK(&(clientinfo->client_mutex));
961 if (!clientinfo->downloadinfo)
962 clientinfo->downloadinfo =
963 (download_content_info *) calloc(1, sizeof(download_content_info));
964 if (clientinfo->downloadinfo)
965 clientinfo->downloadinfo->file_size = download_info->file_size;
966 if (download_info->file_type) {
967 TRACE_DEBUG_INFO_MSG("mime[%s]", download_info->file_type);
969 len = strlen(download_info->file_type);
970 if (len > (DP_MAX_STR_LEN - 1))
971 len = DP_MAX_STR_LEN - 1;
972 if (clientinfo->downloadinfo) {
973 strncpy(clientinfo->downloadinfo->mime_type,
974 download_info->file_type, len);
975 download_provider_db_requestinfo_update_column
976 (clientinfo, DOWNLOAD_DB_MIMETYPE);
979 if (download_info->tmp_saved_path) {
981 TRACE_DEBUG_INFO_MSG("tmp path[%s]", download_info->tmp_saved_path);
982 clientinfo->tmp_saved_path =
983 strdup(download_info->tmp_saved_path);
984 download_provider_db_requestinfo_update_column(clientinfo,
985 DOWNLOAD_DB_SAVEDPATH);
986 str = strrchr(download_info->tmp_saved_path, '/');
990 if (len > (DP_MAX_STR_LEN - 1))
991 len = DP_MAX_STR_LEN - 1;
992 if (clientinfo->downloadinfo) {
993 strncpy(clientinfo->downloadinfo->content_name,
995 download_provider_db_requestinfo_update_column
996 (clientinfo, DOWNLOAD_DB_FILENAME);
997 TRACE_DEBUG_INFO_MSG("content_name[%s]",
998 clientinfo->downloadinfo->
1004 if (clientinfo->requestinfo->callbackinfo.started)
1005 ipc_send_downloadinfo(clientinfo);
1007 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
1010 void __downloading_info_cb(user_downloading_info_t *download_info,
1015 TRACE_DEBUG_MSG("[CRITICAL] clientinfoslot is NULL");
1018 download_clientinfo_slot *clientinfoslot =
1019 (download_clientinfo_slot *) user_data;
1020 download_clientinfo *clientinfo =
1021 (download_clientinfo *) clientinfoslot->clientinfo;
1023 TRACE_DEBUG_MSG("[CRITICAL] clientinfo is NULL");
1026 CLIENT_MUTEX_LOCK(&(clientinfo->client_mutex));
1027 if (clientinfo->req_id != download_info->da_dl_req_id) {
1028 TRACE_DEBUG_MSG("[CRITICAL] req_id[%d] da_dl_req_id[%d}",
1030 download_info->da_dl_req_id);
1031 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
1034 if (!clientinfo->downloadinginfo)
1035 clientinfo->downloadinginfo = (downloading_state_info *) calloc(1,
1036 sizeof(downloading_state_info));
1037 if (clientinfo->downloadinginfo)
1038 clientinfo->downloadinginfo->received_size =
1039 download_info->total_received_size;
1040 if (download_info->saved_path) {
1041 TRACE_DEBUG_INFO_MSG("tmp path[%s]", download_info->saved_path);
1042 len = strlen(download_info->saved_path);
1043 if (len > (DP_MAX_PATH_LEN - 1))
1044 len = DP_MAX_PATH_LEN - 1;
1045 if (clientinfo->downloadinginfo)
1046 strncpy(clientinfo->downloadinginfo->saved_path,
1047 download_info->saved_path, len);
1048 /* FIXME : This should be reviewd again after smack rules is applied */
1049 if (chown(clientinfo->downloadinginfo->saved_path,
1050 clientinfo->credentials.uid,
1051 clientinfo->credentials.gid) < 0)
1052 TRACE_DEBUG_INFO_MSG("Fail to chown [%s]", strerror(errno));
1055 static size_t updated_second;
1056 time_t tt = time(NULL);
1057 struct tm *localTime = localtime(&tt);
1059 if (updated_second != localTime->tm_sec || download_info->saved_path) { // every 1 second.
1060 if (clientinfo->requestinfo
1061 && clientinfo->requestinfo->notification)
1062 set_downloadinginfo_appfw_notification(clientinfo);
1063 if (clientinfo->requestinfo->callbackinfo.progress)
1064 ipc_send_downloadinginfo(clientinfo);
1065 updated_second = localTime->tm_sec;
1067 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
1070 void __notify_cb(user_notify_info_t *notify_info, void *user_data)
1073 TRACE_DEBUG_MSG("[CRITICAL] clientinfoslot is NULL");
1076 download_clientinfo_slot *clientinfoslot =
1077 (download_clientinfo_slot *) user_data;
1078 download_clientinfo *clientinfo =
1079 (download_clientinfo *) clientinfoslot->clientinfo;
1081 TRACE_DEBUG_MSG("[CRITICAL] clientinfo is NULL");
1085 TRACE_DEBUG_INFO_MSG("id[%d],state[%d],err[%d]",
1086 notify_info->da_dl_req_id,
1087 notify_info->state, notify_info->err);
1088 if (clientinfo->req_id != notify_info->da_dl_req_id) {
1089 TRACE_DEBUG_MSG("[CRITICAL] req_id[%d] da_dl_req_id[%d}",
1090 clientinfo->req_id, notify_info->da_dl_req_id);
1094 CLIENT_MUTEX_LOCK(&(clientinfo->client_mutex));
1096 clientinfo->state = __change_state(notify_info->state);
1097 clientinfo->err = __change_error(notify_info->err);
1098 if (clientinfo->state == DOWNLOAD_STATE_FINISHED ||
1099 clientinfo->state == DOWNLOAD_STATE_FAILED) {
1100 if (clientinfo->requestinfo) {
1101 if (clientinfo->requestinfo->notification)
1102 set_downloadedinfo_appfw_notification(clientinfo);
1103 download_provider_db_requestinfo_remove(clientinfo->
1104 requestinfo->requestid);
1106 download_provider_db_history_new(clientinfo);
1107 TRACE_DEBUG_INFO_MSG("[TEST]Finish clientinfo[%p], fd[%d]",
1108 clientinfo, clientinfo->clientfd);
1111 TRACE_DEBUG_INFO_MSG("state[%d]", clientinfo->state);
1112 ipc_send_stateinfo(clientinfo);
1114 CLIENT_MUTEX_UNLOCK(&(clientinfo->client_mutex));
1117 int __change_state(da_state state)
1119 int ret = DOWNLOAD_STATE_NONE;
1121 case DA_STATE_WAITING:
1122 case DA_STATE_DOWNLOAD_STARTED:
1123 TRACE_DEBUG_INFO_MSG("DA_STATE_DOWNLOAD_STARTED");
1124 ret = DOWNLOAD_STATE_READY;
1126 case DA_STATE_DOWNLOADING:
1127 TRACE_DEBUG_INFO_MSG("DA_STATE_DOWNLOADING");
1128 ret = DOWNLOAD_STATE_DOWNLOADING;
1130 case DA_STATE_DOWNLOAD_COMPLETE:
1131 TRACE_DEBUG_INFO_MSG("DA_STATE_COMPLETE");
1132 ret = DOWNLOAD_STATE_INSTALLING;
1134 case DA_STATE_CANCELED:
1135 TRACE_DEBUG_INFO_MSG("DA_STATE_CANCELED");
1136 ret = DOWNLOAD_STATE_STOPPED;
1138 case DA_STATE_CANCELED_ALL:
1139 TRACE_DEBUG_INFO_MSG("DA_STATE_CANCELED_ALL");
1141 case DA_STATE_SUSPENDED:
1142 TRACE_DEBUG_INFO_MSG("DA_STATE_SUSPENDED");
1143 ret = DOWNLOAD_STATE_PAUSED;
1145 case DA_STATE_SUSPENDED_ALL:
1146 TRACE_DEBUG_INFO_MSG("DA_STATE_SUSPENDED_ALL");
1148 case DA_STATE_RESUMED:
1149 TRACE_DEBUG_INFO_MSG("DA_STATE_RESUMED");
1150 ret = DOWNLOAD_STATE_DOWNLOADING;
1152 case DA_STATE_RESUMED_ALL:
1153 TRACE_DEBUG_INFO_MSG("DA_STATE_RESUMED_ALL");
1155 case DA_STATE_FINISHED:
1156 TRACE_DEBUG_INFO_MSG("DA_STATE_FINISHED");
1157 ret = DOWNLOAD_STATE_FINISHED;
1159 case DA_STATE_FAILED:
1160 TRACE_DEBUG_INFO_MSG("DA_STATE_FAILED");
1161 ret = DOWNLOAD_STATE_FAILED;
1169 int __change_error(int err)
1171 int ret = DOWNLOAD_ERROR_UNKOWN;
1174 ret = DOWNLOAD_ERROR_NONE;
1176 case DA_ERR_INVALID_ARGUMENT:
1177 ret = DOWNLOAD_ERROR_INVALID_PARAMETER;
1179 case DA_ERR_FAIL_TO_MEMALLOC:
1180 ret = DOWNLOAD_ERROR_OUT_OF_MEMORY;
1182 case DA_ERR_UNREACHABLE_SERVER:
1183 ret = DOWNLOAD_ERROR_NETWORK_UNREACHABLE;
1185 case DA_ERR_HTTP_TIMEOUT:
1186 ret = DOWNLOAD_ERROR_CONNECTION_TIMED_OUT;
1188 case DA_ERR_DISK_FULL:
1189 ret = DOWNLOAD_ERROR_NO_SPACE;
1191 case DA_ERR_INVALID_STATE:
1192 ret = DOWNLOAD_ERROR_INVALID_STATE;
1194 case DA_ERR_NETWORK_FAIL:
1195 ret = DOWNLOAD_ERROR_CONNECTION_FAILED;
1197 case DA_ERR_INVALID_URL:
1198 ret = DOWNLOAD_ERROR_INVALID_URL;
1200 case DA_ERR_INVALID_INSTALL_PATH:
1201 ret = DOWNLOAD_ERROR_INVALID_DESTINATION;
1203 case DA_ERR_ALREADY_MAX_DOWNLOAD:
1204 ret = DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS;
1206 case DA_ERR_FAIL_TO_INSTALL_FILE:
1207 ret = DOWNLOAD_ERROR_INSTALL_FAIL;
1209 case DA_ERR_FAIL_TO_CREATE_THREAD:
1210 case DA_ERR_FAIL_TO_OBTAIN_MUTEX:
1211 case DA_ERR_FAIL_TO_ACCESS_FILE:
1212 case DA_ERR_FAIL_TO_GET_CONF_VALUE:
1213 case DA_ERR_FAIL_TO_ACCESS_STORAGE:
1214 case DA_ERR_DLOPEN_FAIL:
1215 ret = DOWNLOAD_ERROR_IO_ERROR;
1224 da_client_cb_t da_cb = {
1227 __downloading_info_cb
1229 da_ret = da_init(&da_cb, DA_DOWNLOAD_MANAGING_METHOD_AUTO);
1230 if (da_ret != DA_RESULT_OK) {
1231 return DOWNLOAD_ERROR_FAIL_INIT_AGENT;
1233 return DOWNLOAD_ERROR_NONE;
1236 void _deinit_agent()