2 * Copyright (c) 2013 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.
17 #include <sys/types.h>
24 #include <download-provider-log.h>
25 #include <download-provider-config.h>
26 #include <download-provider-ipc.h>
27 #include <download-provider-network.h>
28 #include <download-provider-client.h>
29 #include <download-provider-pthread.h>
30 #include <download-provider-notify.h>
31 #include <download-provider-notification-manager.h>
32 #include <download-provider-queue-manager.h>
33 #include <download-provider-client-manager.h>
34 #include <download-provider-db-defs.h>
35 #include <download-provider-db.h>
36 #include <download-provider-plugin-download-agent.h>
37 #include <download-provider-security.h>
40 #define SIZE_MAX ((size_t) - 1)
43 static const char *dp_db_column[] = {
44 [DP_PROP_NONE] = NULL,
45 [DP_PROP_URL] = DP_DB_COL_URL,
46 [DP_PROP_PROXY] = DP_DB_COL_PROXY,
47 [DP_PROP_DESTINATION] = DP_DB_COL_DESTINATION,
48 [DP_PROP_FILENAME] = DP_DB_COL_FILENAME,
49 [DP_PROP_STATE_CALLBACK] = DP_DB_COL_STATE_EVENT,
50 [DP_PROP_PROGRESS_CALLBACK] = DP_DB_COL_PROGRESS_EVENT,
51 [DP_PROP_AUTO_DOWNLOAD] = DP_DB_COL_AUTO_DOWNLOAD,
52 [DP_PROP_NETWORK_TYPE] = DP_DB_COL_NETWORK_TYPE,
53 [DP_PROP_NETWORK_BONDING] = DP_DB_COL_NETWORK_BONDING,
54 [DP_PROP_SAVED_PATH] = DP_DB_COL_SAVED_PATH,
55 [DP_PROP_TEMP_SAVED_PATH] = DP_DB_COL_TMP_SAVED_PATH,
56 [DP_PROP_MIME_TYPE] = DP_DB_COL_MIMETYPE,
57 [DP_PROP_RECEIVED_SIZE] = NULL,
58 [DP_PROP_TOTAL_FILE_SIZE] = DP_DB_COL_CONTENT_SIZE,
59 [DP_PROP_CONTENT_NAME] = DP_DB_COL_CONTENT_NAME,
60 [DP_PROP_HTTP_STATUS] = DP_DB_COL_HTTP_STATUS,
61 [DP_PROP_ETAG] = DP_DB_COL_ETAG,
62 [DP_PROP_STATE] = DP_DB_COL_STATE,
63 [DP_PROP_ERROR] = DP_DB_COL_ERRORCODE,
64 [DP_PROP_HTTP_HEADERS] = NULL,
65 [DP_PROP_HTTP_HEADER] = NULL,
66 [DP_PROP_NOTIFICATION_RAW] = NULL,
67 [DP_PROP_NOTIFICATION_SUBJECT] = DP_DB_COL_NOTI_SUBJECT,
68 [DP_PROP_NOTIFICATION_DESCRIPTION] = DP_DB_COL_NOTI_DESCRIPTION,
69 [DP_PROP_NOTIFICATION_TYPE] = DP_DB_COL_NOTI_TYPE,
70 [DP_PROP_CREATE] = NULL,
71 [DP_PROP_START] = NULL,
72 [DP_PROP_PAUSE] = NULL,
73 [DP_PROP_CANCEL] = NULL,
74 [DP_PROP_DESTROY] = NULL,
77 char *dp_print_state(int state)
86 case DP_STATE_CONNECTING:
88 case DP_STATE_DOWNLOADING:
92 case DP_STATE_COMPLETED:
94 case DP_STATE_CANCELED:
104 char *dp_print_errorcode(int errorcode)
109 case DP_ERROR_INVALID_PARAMETER:
110 return "INVALID_PARAMETER";
111 case DP_ERROR_OUT_OF_MEMORY:
112 return "OUT_OF_MEMORY";
113 case DP_ERROR_IO_ERROR:
115 case DP_ERROR_NETWORK_UNREACHABLE:
116 return "NETWORK_UNREACHABLE";
117 case DP_ERROR_CONNECTION_TIMED_OUT:
118 return "CONNECTION_TIMED_OUT";
119 case DP_ERROR_NO_SPACE:
121 case DP_ERROR_FIELD_NOT_FOUND:
122 return "FIELD_NOT_FOUND";
123 case DP_ERROR_INVALID_STATE:
124 return "INVALID_STATE";
125 case DP_ERROR_CONNECTION_FAILED:
126 return "CONNECTION_FAILED";
127 case DP_ERROR_INVALID_URL:
128 return "INVALID_URL";
129 case DP_ERROR_INVALID_DESTINATION:
130 return "INVALID_DESTINATION";
131 case DP_ERROR_QUEUE_FULL:
133 case DP_ERROR_ALREADY_COMPLETED:
134 return "ALREADY_COMPLETED";
135 case DP_ERROR_FILE_ALREADY_EXISTS:
136 return "FILE_ALREADY_EXISTS";
137 case DP_ERROR_TOO_MANY_DOWNLOADS:
138 return "TOO_MANY_DOWNLOADS";
139 case DP_ERROR_NO_DATA:
141 case DP_ERROR_UNHANDLED_HTTP_CODE:
142 return "UNHANDLED_HTTP_CODE";
143 case DP_ERROR_CANNOT_RESUME:
144 return "CANNOT_RESUME";
145 case DP_ERROR_PERMISSION_DENIED:
146 return "PERMISSION_DENIED";
147 case DP_ERROR_RESPONSE_TIMEOUT:
148 return "RESPONSE_TIMEOUT";
149 case DP_ERROR_REQUEST_TIMEOUT:
150 return "REQUEST_TIMEOUT";
151 case DP_ERROR_SYSTEM_DOWN:
152 return "SYSTEM_DOWN";
153 case DP_ERROR_CLIENT_DOWN:
154 return "CLIENT_DOWN";
155 case DP_ERROR_DISK_BUSY:
157 case DP_ERROR_ID_NOT_FOUND:
158 return "ID_NOT_FOUND";
165 char *dp_print_section(short section)
188 char *dp_print_property(unsigned property)
201 case DP_PROP_DESTROY:
207 case DP_PROP_DESTINATION:
208 return "DESTINATION";
209 case DP_PROP_FILENAME:
211 case DP_PROP_STATE_CALLBACK:
213 case DP_PROP_PROGRESS_CALLBACK:
214 return "PROGRESS_CB";
215 case DP_PROP_AUTO_DOWNLOAD:
216 return "AUTO_DOWNLOAD";
217 case DP_PROP_NETWORK_TYPE:
218 return "NETWORK_TYPE";
219 case DP_PROP_NETWORK_BONDING:
220 return "NETWORK_BONDING";
221 case DP_PROP_SAVED_PATH:
223 case DP_PROP_TEMP_SAVED_PATH:
224 return "TEMP_SAVED_PATH";
225 case DP_PROP_MIME_TYPE:
227 case DP_PROP_RECEIVED_SIZE:
228 return "RECEIVED_SIZE";
229 case DP_PROP_TOTAL_FILE_SIZE:
230 return "TOTAL_FILE_SIZE";
231 case DP_PROP_CONTENT_NAME:
232 return "CONTENT_NAME";
233 case DP_PROP_HTTP_STATUS:
234 return "HTTP_STATUS";
241 case DP_PROP_NOTIFICATION_RAW:
242 return "NOTIFICATION_RAW";
243 case DP_PROP_NOTIFICATION_SUBJECT:
244 return "NOTIFICATION_SUBJECT";
245 case DP_PROP_NOTIFICATION_DESCRIPTION:
246 return "NOTIFICATION_DESCRIPTION";
247 case DP_PROP_NOTIFICATION_TYPE:
248 return "NOTIFICATION_TYPE";
249 case DP_PROP_HTTP_HEADERS:
250 return "HTTP_HEADERS";
251 case DP_PROP_HTTP_HEADER:
252 return "HTTP_HEADER";
253 case DP_PROP_VERIFY_HOST:
254 return "VERIFY_HOST";
261 static const char *__dp_get_db_table_name(unsigned property)
266 case DP_PROP_DESTINATION:
267 case DP_PROP_FILENAME:
268 case DP_PROP_STATE_CALLBACK:
269 case DP_PROP_PROGRESS_CALLBACK:
270 case DP_PROP_NETWORK_TYPE:
271 case DP_PROP_NETWORK_BONDING:
272 return DP_TABLE_REQUEST;
273 case DP_PROP_AUTO_DOWNLOAD:
276 return DP_TABLE_LOGGING;
277 case DP_PROP_SAVED_PATH:
278 case DP_PROP_TEMP_SAVED_PATH:
279 case DP_PROP_MIME_TYPE:
280 case DP_PROP_CONTENT_NAME:
282 case DP_PROP_TOTAL_FILE_SIZE:
283 case DP_PROP_HTTP_STATUS:
284 return DP_TABLE_DOWNLOAD;
285 case DP_PROP_NOTIFICATION_RAW:
286 case DP_PROP_NOTIFICATION_SUBJECT:
287 case DP_PROP_NOTIFICATION_DESCRIPTION:
288 case DP_PROP_NOTIFICATION_TYPE:
289 return DP_TABLE_NOTIFICATION;
290 case DP_PROP_HTTP_HEADERS:
291 case DP_PROP_HTTP_HEADER:
292 return DP_TABLE_HEADERS;
293 case DP_PROP_RECEIVED_SIZE:
299 case DP_PROP_DESTROY:
306 static int __dp_get_download_id(dp_client_fmt *client)
308 int download_id = -1;
309 int check_duplicate = 1;
311 int errorcode = DP_ERROR_NONE;
314 if (dp_db_get_max_download_id(client->dbhandle,
315 DP_TABLE_LOGGING, &download_id, &errorcode) < 0) {
316 TRACE_ERROR("ERROR [%d]", errorcode);
317 // database is empty start with id : 1
318 download_id = DP_FIRST_DOWNLOAD_ID;
320 if (download_id < INT_MAX)
327 if (download_id < INT_MAX) {
328 TRACE_INFO("download_id [%d]", download_id);
329 check_duplicate = dp_db_check_duplicated_int(client->dbhandle,
330 DP_TABLE_LOGGING, DP_DB_COL_ID, download_id, &errorcode);
331 if (errorcode == DP_ERROR_NONE) {
332 if (check_duplicate == 0)
335 TRACE_ERROR("ERROR [%d]", errorcode);
337 if (retry_count < 3) {
339 } else if (retry_count < 10) {
340 gettimeofday(&tval, NULL);
341 tval.tv_usec = (tval.tv_usec & 0x0fff);
342 download_id += 1171 * retry_count + tval.tv_usec;
343 } else if (retry_count < 20) {
344 gettimeofday(&tval, NULL);
345 tval.tv_usec = (tval.tv_usec & 0xff33ff) + retry_count;
346 download_id += tval.tv_usec;
348 TRACE_ERROR("failed to generate unique download_id [%d]", download_id);
352 TRACE_ERROR("reached INT_MAX limit");
353 download_id = DP_FIRST_DOWNLOAD_ID;
355 } while (check_duplicate != 0);
359 void dp_request_create(dp_client_fmt *client, dp_request_fmt *request)
362 // find the tail of linked list & check limitation
364 dp_request_fmt *tailp = client->requests;
365 dp_request_fmt *prevp = NULL;
366 for (; i < MAX_DOWNLOAD_HANDLE; i++) {
369 TRACE_DEBUG("link %d info: id:%d access-time:%d", i, tailp->id, tailp->access_time);
373 request->next = NULL;
374 if (prevp == NULL) // it's first link
375 client->requests = request;
377 prevp->next = request; // attach at the tail
379 TRACE_INFO("sock:%d download-id:%d", client->channel, request->id);
382 static int __dp_request_create(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
384 int errorcode = DP_ERROR_NONE;
386 int download_id = __dp_get_download_id(client);
388 // allocation new request.
389 dp_request_fmt *request = (dp_request_fmt *) calloc(1, sizeof(dp_request_fmt));
390 if (request == NULL) {
391 TRACE_ERROR("check memory sock:%d download-id:%d", client->channel, download_id);
392 return DP_ERROR_OUT_OF_MEMORY;
395 if (dp_db_new_logging(client->dbhandle, download_id, DP_STATE_READY, DP_ERROR_NONE, &errorcode) < 0) {
396 TRACE_ERROR("new log sock:%d download-id:%d errorcode:%s", client->channel, download_id, dp_print_errorcode(errorcode));
401 request->id = download_id;
402 request->agent_id = -1;
403 request->state = DP_STATE_READY;
404 request->error = DP_ERROR_NONE;
405 request->network_type = DP_NETWORK_ALL;
406 request->access_time = (int)time(NULL);
407 request->state_cb = 0;
408 request->progress_cb = 0;
409 request->startcount = 0;
410 request->noti_type = DP_NOTIFICATION_TYPE_NONE;
411 request->progress_lasttime = 0;
412 request->received_size = 0;
413 request->content_type = DP_CONTENT_UNKNOWN;
414 request->file_size = 0;
415 request->noti_priv_id = -1;
417 dp_request_create(client, request);
418 ipc_info->id = download_id;
422 void dp_request_free(dp_request_fmt *request)
424 // free notification handle here
425 TRACE_DEBUG("destory id:%d", request->id);
429 static int _dp_client_can_remove_request(dp_request_fmt *request)
431 if (request->id <= 0 || request->state == DP_STATE_NONE) {
432 TRACE_ERROR("id:%d unexpected request.", request->id);
436 int now_time = (int)time(NULL);
437 if (request->access_time > 0 &&
438 (now_time - request->access_time) > DP_CARE_CLIENT_CLEAR_INTERVAL) {
439 // check accesstime. if difference is bigger than DP_CARE_CLIENT_CLEAR_INTERVAL, clear.
440 if (request->state == DP_STATE_READY || request->state == DP_STATE_COMPLETED ||
441 request->state == DP_STATE_CANCELED || request->state == DP_STATE_FAILED)
445 if (request->state == DP_STATE_PAUSED &&
446 dp_is_alive_download(request->agent_id) == 0) {
447 // paused & agent_id not exist.... unload from memory.
448 TRACE_ERROR("id:%d hanged as paused (%d/%d)",request->id, request->access_time, now_time);
455 static int _dp_client_check_zombie_request(dp_request_fmt *request)
457 int now_time = (int)time(NULL);
460 if (request->access_time > 0)
461 time_diff = now_time - request->access_time;
463 if (time_diff > DP_CARE_CLIENT_CLEAR_INTERVAL && request->state == DP_STATE_CONNECTING) {
464 TRACE_ERROR("id:%d connection timeout (%d/%d)",
465 request->id, request->access_time, now_time);
472 void dp_client_clear_requests(void *slotp)
474 dp_client_slots_fmt *slot = (dp_client_slots_fmt *)slotp;
476 TRACE_ERROR("check slot memory");
480 dp_client_fmt *client = &slot->client;
481 dp_request_fmt *tailp = client->requests;
482 dp_request_fmt *prevp = NULL;
484 unsigned queued_count = 0;
485 unsigned ongoing_count = 0;
487 for (int i = 0; tailp != NULL; i++) {
488 int can_remove = _dp_client_can_remove_request(tailp);
489 int is_zombie = _dp_client_check_zombie_request(tailp);
492 TRACE_ERROR("id:%d is zombie request.", tailp->id);
493 if (dp_cancel_agent_download_without_update(tailp->agent_id) < 0)
494 TRACE_ERROR("failed to cancel download(%d) id:%d", tailp->agent_id, tailp->id);
495 tailp->state = DP_STATE_FAILED;
496 tailp->error = DP_ERROR_CONNECTION_TIMED_OUT;
497 if (tailp->noti_type == DP_NOTIFICATION_TYPE_COMPLETE_ONLY ||
498 tailp->noti_type == DP_NOTIFICATION_TYPE_ALL) {
499 if (dp_notification_manager_push_notification(slot, tailp, DP_NOTIFICATION) < 0)
500 TRACE_ERROR("failed to register notification for id:%d", tailp->id);
505 dp_request_fmt *removep = tailp;
506 if (prevp == NULL) // first request.
507 client->requests = tailp->next;
509 prevp->next = tailp->next;
511 TRACE_DEBUG("request %d clear: id:%d state:%s", i, removep->id, dp_print_state(removep->state));
512 dp_request_free(removep);
518 if (tailp->state == DP_STATE_QUEUED)
524 TRACE_DEBUG("info requests:%d queued:%d", ongoing_count, queued_count);
525 if (queued_count > 0)
526 dp_queue_manager_wake_up();
529 int dp_request_destroy(dp_client_fmt *client, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
531 int errorcode = DP_ERROR_NONE;
533 if (requestp != NULL && client->requests != NULL) {
534 if (requestp == client->requests) {
535 // cancel downloading ... after checking status
536 client->requests = requestp->next;
537 dp_request_free(requestp);
540 dp_request_fmt *prevp = client->requests;
541 dp_request_fmt *removep = client->requests->next;
542 for (; i < MAX_DOWNLOAD_HANDLE; i++) {
543 if (removep == NULL) {
544 errorcode = DP_ERROR_ID_NOT_FOUND;
547 if (removep == requestp) {
548 // cancel downloading ... after checking status
549 prevp->next = removep->next;
550 dp_request_free(removep);
554 removep = removep->next;
559 TRACE_DEBUG("sock:%d id:%d errorcode:%s", client->channel,
560 (ipc_info) ? ipc_info->id : -1, dp_print_errorcode(errorcode));
565 static int __dp_request_read_int(int sock, dp_ipc_fmt *ipc_info, int *value)
567 int errorcode = DP_ERROR_NONE;
568 if (ipc_info->size == sizeof(int)) {
569 if (dp_ipc_read(sock, value, ipc_info->size, __FUNCTION__) < 0) {
570 TRACE_ERROR("sock:%d check ipc length:%zd", sock, ipc_info->size);
571 errorcode = DP_ERROR_IO_ERROR;
574 errorcode = DP_ERROR_IO_ERROR;
579 static int __dp_request_feedback_string(int sock, dp_ipc_fmt *ipc_info, void *string, size_t length, int errorvalue)
581 int errorcode = DP_ERROR_NONE;
583 if (length == 0 && errorvalue == DP_ERROR_NONE)
584 errorvalue = DP_ERROR_NO_DATA;
586 if (dp_ipc_query(sock, ipc_info->id, ipc_info->section, ipc_info->property, errorvalue, length * sizeof(char)) < 0) {
587 errorcode = DP_ERROR_IO_ERROR;
588 TRACE_ERROR("sock:%d check ipc length:%zd", sock, length);
590 if (errorvalue == DP_ERROR_NONE && errorcode == DP_ERROR_NONE) {
591 if (dp_ipc_write(sock, string, sizeof(char) * length) < 0) {
592 errorcode = DP_ERROR_IO_ERROR;
593 TRACE_ERROR("sock:%d check ipc length:%zd", sock, length);
599 static int __dp_request_read_string(int sock, dp_ipc_fmt *ipc_info, char **string)
601 int errorcode = DP_ERROR_NONE;
602 if (ipc_info->size > 0) {
603 char *recv_str = (char *)calloc((ipc_info->size + (size_t)1), sizeof(char));
604 if (recv_str == NULL) {
605 TRACE_ERROR("sock:%d check memory length:%zd", sock, ipc_info->size);
606 errorcode = DP_ERROR_OUT_OF_MEMORY;
608 if (dp_ipc_read(sock, recv_str, ipc_info->size, __FUNCTION__) <= 0) {
609 TRACE_ERROR("sock:%d check ipc length:%zd", sock, ipc_info->size);
610 errorcode = DP_ERROR_IO_ERROR;
613 recv_str[ipc_info->size] = '\0';
614 TRACE_DEBUG("sock:%d length:%zd string:%s", sock, ipc_info->size, recv_str);
619 errorcode = DP_ERROR_IO_ERROR;
624 static int __dp_request_feedback_int(int sock, dp_ipc_fmt *ipc_info, void *value, int errorvalue, size_t extra_size)
626 int errorcode = DP_ERROR_NONE;
627 if (errorvalue != DP_ERROR_NONE)
629 if (dp_ipc_query(sock, ipc_info->id, ipc_info->section, ipc_info->property, errorvalue, extra_size) < 0) {
630 errorcode = DP_ERROR_IO_ERROR;
631 TRACE_ERROR("sock:%d check ipc length:%zd", sock, extra_size);
633 if (errorvalue == DP_ERROR_NONE && errorcode == DP_ERROR_NONE) {
634 if (dp_ipc_write(sock, value, extra_size) < 0) {
635 errorcode = DP_ERROR_IO_ERROR;
636 TRACE_ERROR("sock:%d check ipc length:%zd", sock, extra_size);
642 static int __dp_request_get_info_string(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
644 int errorcode = DP_ERROR_NONE;
645 int bundle_type = -1; // DP_PROP_NOTIFICATION_RAW
648 const char *table = __dp_get_db_table_name(ipc_info->property);
649 const char *column = dp_db_column[ipc_info->property];
651 if (ipc_info->property == DP_PROP_NOTIFICATION_RAW) {
652 errorcode = __dp_request_read_int(client->channel, ipc_info, &bundle_type);
653 TRACE_DEBUG("read %s type:%d", dp_print_property(ipc_info->property), bundle_type);
655 if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_ONGOING)
656 column = DP_DB_COL_NOTI_RAW_ONGOING;
657 else if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_COMPLETE)
658 column = DP_DB_COL_NOTI_RAW_COMPLETE;
659 else if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_FAILED)
660 column = DP_DB_COL_NOTI_RAW_FAIL;
662 if (column == NULL) {
663 errorcode = DP_ERROR_INVALID_PARAMETER;
664 TRACE_ERROR("invalid type %s type:%d",
665 dp_print_property(ipc_info->property), bundle_type);
666 if (dp_ipc_query(client->channel, ipc_info->id,
667 ipc_info->section, ipc_info->property, errorcode, 0) < 0) {
668 errorcode = DP_ERROR_IO_ERROR;
669 TRACE_ERROR("check ipc sock:%d", client->channel);
675 if (dp_db_get_property_string(client->dbhandle, ipc_info->id,
676 table, column, (unsigned char **)&string, &length, &errorcode) < 0)
677 errorcode = DP_ERROR_NO_DATA;
679 if (__dp_request_feedback_string(client->channel, ipc_info,
680 string, length, errorcode) == DP_ERROR_IO_ERROR) {
681 errorcode = DP_ERROR_IO_ERROR;
682 TRACE_ERROR("check ipc sock:%d", client->channel);
690 static int __dp_request_get_info_int_from_db(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
692 int errorcode = DP_ERROR_NONE;
693 int is_file_size = 0;
695 unsigned long long lval = 0;
696 const char *table = __dp_get_db_table_name(ipc_info->property);
697 size_t size = sizeof(int);
699 if (ipc_info->property == DP_PROP_RECEIVED_SIZE
700 || ipc_info->property == DP_PROP_TOTAL_FILE_SIZE) {
702 size = sizeof(unsigned long long);
705 if (dp_db_get_property_int(client->dbhandle, ipc_info->id,
706 table, dp_db_column[ipc_info->property],
707 (is_file_size ? (void *)&lval : (void *)&ival), &errorcode) < 0) {
708 TRACE_ERROR("failed to get %s", dp_print_property(ipc_info->property));
709 errorcode = DP_ERROR_NO_DATA;
712 if (__dp_request_feedback_int(client->channel, ipc_info,
713 (is_file_size ? (void *)&lval : (void *)&ival),
714 errorcode, size) == DP_ERROR_IO_ERROR) {
715 errorcode = DP_ERROR_IO_ERROR;
716 TRACE_ERROR("check ipc sock:%d", client->channel);
722 static int __dp_request_get_info_int_from_request(dp_client_fmt *client,
723 dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
726 int errorcode = DP_ERROR_NONE;
727 size_t size = sizeof(int);
730 switch (ipc_info->property) {
731 case DP_PROP_RECEIVED_SIZE:
732 val = &requestp->received_size;
733 size = sizeof(unsigned long long);
735 case DP_PROP_STATE_CALLBACK:
736 val = &requestp->state_cb;
738 case DP_PROP_PROGRESS_CALLBACK:
739 val = &requestp->progress_cb;
741 case DP_PROP_NETWORK_TYPE:
742 val = &requestp->network_type;
745 val = &requestp->state;
748 val = &requestp->error;
750 case DP_PROP_TOTAL_FILE_SIZE:
751 val = &requestp->file_size;
752 size = sizeof(unsigned long long);
754 case DP_PROP_NOTIFICATION_TYPE:
755 val = &requestp->noti_type;
761 if (ipc_info->property == DP_PROP_RECEIVED_SIZE) {
762 errorcode = DP_ERROR_INVALID_STATE;
765 return __dp_request_get_info_int_from_db(client, ipc_info);
769 if (__dp_request_feedback_int(client->channel, ipc_info,
770 val, errorcode, size) == DP_ERROR_IO_ERROR) {
771 errorcode = DP_ERROR_IO_ERROR;
772 TRACE_ERROR("check ipc sock:%d", client->channel);
777 static int __dp_request_get_http_headers_info(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
779 int errorcode = DP_ERROR_NONE;
780 int field_count = dp_db_check_duplicated_int(client->dbhandle,
781 DP_TABLE_HEADERS, DP_DB_COL_ID, ipc_info->id, &errorcode);
783 if (field_count < 0) {
784 TRACE_ERROR("failed to get %s", dp_print_property(ipc_info->property));
785 errorcode = DP_ERROR_DISK_BUSY;
789 int result = __dp_request_feedback_int(client->channel,
790 ipc_info, (void *)&field_count, errorcode, sizeof(int));
791 if (result == DP_ERROR_IO_ERROR) {
792 errorcode = DP_ERROR_IO_ERROR;
793 TRACE_ERROR("check ipc sock:%d", client->channel);
794 } else if (field_count > 0) {
795 // get fields from database.
796 int *ids = (int *)calloc(field_count, sizeof(int));
798 TRACE_ERROR("failed to allocate the clients");
799 errorcode = DP_ERROR_OUT_OF_MEMORY;
801 // getting ids of clients
803 int rows_count = dp_db_get_cond_ids(client->dbhandle,
804 DP_TABLE_HEADERS, DP_DB_COL_ROW_ID, DP_DB_COL_ID,
805 ipc_info->id, ids, field_count, &errorcode);
806 for (; i < rows_count; i++) {
809 if (dp_db_get_cond_string(client->dbhandle,
810 DP_TABLE_HEADERS, DP_DB_COL_ROW_ID,
811 ids[i], DP_DB_COL_HEADER_FIELD,
812 (unsigned char **)&string, &length, &errorcode) < 0) {
813 TRACE_ERROR("failed to get %s", dp_print_property(ipc_info->property));
814 errorcode = DP_ERROR_NO_DATA;
816 result = __dp_request_feedback_string(client->channel,
817 ipc_info, string, length, errorcode);
819 if (result == DP_ERROR_IO_ERROR) {
820 errorcode = DP_ERROR_IO_ERROR;
821 TRACE_ERROR("check ipc sock:%d", client->channel);
832 /* 1. read field string
833 * 2. response with extra size
836 static int __dp_request_get_http_header_info(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
838 char *header_field = NULL;
841 int errorcode = __dp_request_read_string(client->channel, ipc_info, &header_field);
842 if (errorcode == DP_ERROR_NONE && header_field != NULL) {
843 if (dp_db_get_header_value(client->dbhandle, ipc_info->id,
844 header_field, (unsigned char **)&string, &length, &errorcode) < 0)
845 errorcode = DP_ERROR_NO_DATA;
846 } else if (header_field == NULL) {
847 errorcode = DP_ERROR_INVALID_PARAMETER;
850 if (__dp_request_feedback_string(client->channel,
851 ipc_info, string, length, errorcode) == DP_ERROR_IO_ERROR) {
852 errorcode = DP_ERROR_IO_ERROR;
853 TRACE_ERROR("check ipc sock:%d", client->channel);
862 static int __dp_request_get_info(dp_client_fmt *client, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
864 int errorcode = DP_ERROR_NONE;
866 switch (ipc_info->property) {
869 case DP_PROP_DESTINATION:
870 case DP_PROP_FILENAME:
871 case DP_PROP_SAVED_PATH:
872 case DP_PROP_TEMP_SAVED_PATH:
873 case DP_PROP_MIME_TYPE:
874 case DP_PROP_CONTENT_NAME:
876 case DP_PROP_NOTIFICATION_SUBJECT:
877 case DP_PROP_NOTIFICATION_DESCRIPTION:
878 case DP_PROP_NOTIFICATION_RAW:
879 errorcode = __dp_request_get_info_string(client, ipc_info);
881 case DP_PROP_RECEIVED_SIZE:
882 case DP_PROP_STATE_CALLBACK:
883 case DP_PROP_PROGRESS_CALLBACK:
884 case DP_PROP_NETWORK_TYPE:
887 case DP_PROP_TOTAL_FILE_SIZE:
888 case DP_PROP_NOTIFICATION_TYPE:
889 errorcode = __dp_request_get_info_int_from_request(client, ipc_info, requestp);
891 case DP_PROP_NETWORK_BONDING:
892 case DP_PROP_AUTO_DOWNLOAD:
893 case DP_PROP_HTTP_STATUS:
894 errorcode = __dp_request_get_info_int_from_db(client, ipc_info);
896 case DP_PROP_HTTP_HEADERS:
897 errorcode = __dp_request_get_http_headers_info(client, ipc_info);
899 case DP_PROP_HTTP_HEADER:
900 errorcode = __dp_request_get_http_header_info(client, ipc_info);
903 errorcode = DP_ERROR_INVALID_PARAMETER;
907 if (errorcode != DP_ERROR_NONE)
908 TRACE_ERROR("failed to get %s, error:%s",
909 dp_print_property(ipc_info->property), dp_print_errorcode(errorcode));
914 static int __dp_request_set_info(dp_client_slots_fmt *slot, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
917 TRACE_ERROR("check slot memory");
918 return DP_ERROR_INVALID_PARAMETER;
920 dp_client_fmt *client = &slot->client;
921 if (client == NULL || ipc_info == NULL) {
922 TRACE_ERROR("check client or ipc info.");
923 return DP_ERROR_INVALID_PARAMETER;
926 int errorcode = DP_ERROR_NONE;
928 // if completed or downloading, invalid state.
929 int download_state = DP_STATE_NONE;
930 if (requestp != NULL) {
931 download_state = requestp->state;
933 if (dp_db_get_property_int(client->dbhandle, ipc_info->id, DP_TABLE_LOGGING, DP_DB_COL_STATE, &download_state, &errorcode) < 0) {
934 TRACE_ERROR("failed to get %s", dp_print_property(ipc_info->property));
935 errorcode = DP_ERROR_ID_NOT_FOUND;
937 if (dp_ipc_query(client->channel, ipc_info->id, DP_SEC_SET,
938 ipc_info->property, errorcode, 0) < 0) {
939 TRACE_ERROR("check ipc sock:%d", client->channel);
944 // should the state be checked ?
945 TRACE_DEBUG("state:%s set property:%s", dp_print_state(download_state), dp_print_property(ipc_info->property));
947 switch (ipc_info->property) {
950 char *recv_str = NULL;
951 errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
952 if (errorcode == DP_ERROR_NONE) {
953 if (recv_str == NULL) {
954 errorcode = DP_ERROR_INVALID_PARAMETER;
956 // write to database here
957 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_URL, (void *)recv_str, ipc_info->size, 2, &errorcode) < 0) {
958 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
959 errorcode = DP_ERROR_DISK_BUSY;
968 char *recv_str = NULL;
969 errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
970 if (errorcode == DP_ERROR_NONE) {
971 if (recv_str == NULL) {
972 errorcode = DP_ERROR_INVALID_PARAMETER;
974 // write to database here
975 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_PROXY, (void *)recv_str, ipc_info->size, 2, &errorcode) < 0)
976 TRACE_ERROR("failed to set %s errorcode:%s", dp_print_property(ipc_info->property), dp_print_errorcode(errorcode));
982 case DP_PROP_DESTINATION:
984 char *recv_str = NULL;
985 errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
986 if (errorcode == DP_ERROR_NONE) {
987 if (recv_str == NULL) {
988 errorcode = DP_ERROR_INVALID_PARAMETER;
990 // check here destination is available
991 errorcode = dp_is_valid_dir(slot->credential, recv_str);
992 if (errorcode == DP_ERROR_NONE &&
993 dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_DESTINATION, (void *)recv_str, ipc_info->size, 2, &errorcode) < 0) {
994 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
995 errorcode = DP_ERROR_DISK_BUSY;
1002 case DP_PROP_TEMP_SAVED_PATH:
1004 char *recv_str = NULL;
1005 errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
1006 if (errorcode == DP_ERROR_NONE) {
1007 if (recv_str == NULL) {
1008 errorcode = DP_ERROR_INVALID_PARAMETER;
1010 errorcode = dp_is_valid_dir(slot->credential, recv_str);
1011 if (errorcode == DP_ERROR_NONE &&
1012 dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_TEMP_FILE_PATH, (void *)recv_str, ipc_info->size, 2, &errorcode) < 0) {
1013 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1014 errorcode = DP_ERROR_DISK_BUSY;
1021 case DP_PROP_FILENAME:
1023 char *recv_str = NULL;
1024 errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
1025 if (errorcode == DP_ERROR_NONE) {
1026 if (recv_str == NULL) {
1027 errorcode = DP_ERROR_INVALID_PARAMETER;
1029 // write to database here
1030 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_FILENAME, (void *)recv_str, ipc_info->size, 2, &errorcode) < 0) {
1031 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1032 errorcode = DP_ERROR_DISK_BUSY;
1039 case DP_PROP_STATE_CALLBACK:
1042 // DP_ERROR_INVALID_STATE if downloading or finished
1043 // update database here
1044 if (requestp != NULL)
1045 requestp->state_cb = 1;
1048 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_STATE_EVENT, (void *)&enable_cb, ipc_info->size, 0, &errorcode) < 0) {
1049 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1050 errorcode = DP_ERROR_DISK_BUSY;
1054 case DP_PROP_PROGRESS_CALLBACK:
1057 // DP_ERROR_INVALID_STATE if downloading or finished
1058 // update database here
1059 if (requestp != NULL)
1060 requestp->progress_cb = 1;
1063 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_PROGRESS_EVENT, (void *)&enable_cb, ipc_info->size, 0, &errorcode) < 0) {
1064 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1065 errorcode = DP_ERROR_DISK_BUSY;
1069 case DP_PROP_AUTO_DOWNLOAD:
1071 // update autodownload property as 1 in database
1073 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_LOGGING, DP_DB_COL_AUTO_DOWNLOAD, (void *)&enable_cb, ipc_info->size, 0, &errorcode) < 0) {
1074 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1075 errorcode = DP_ERROR_DISK_BUSY;
1079 case DP_PROP_NETWORK_TYPE:
1082 errorcode = __dp_request_read_int(client->channel, ipc_info, &recv_int);
1083 if (recv_int <= DP_NETWORK_OFF ||
1084 recv_int > DP_NETWORK_ALL) {
1085 errorcode = DP_ERROR_INVALID_PARAMETER;
1087 // update in database
1088 if (requestp != NULL) {
1089 if (requestp->state == DP_STATE_QUEUED) {
1090 dp_queue_manager_clear_queue(requestp);
1092 requestp->network_type = recv_int;
1093 if (requestp->state == DP_STATE_CONNECTING ||
1094 requestp->state == DP_STATE_DOWNLOADING) {
1095 // pause & push queue
1096 if (dp_pause_agent_download_without_update(requestp->agent_id) < 0) {
1097 TRACE_ERROR("failed to pause download(%d) id:%d", requestp->agent_id, ipc_info->id);
1099 requestp->state = DP_STATE_PAUSED;
1100 requestp->error = DP_ERROR_NONE;
1101 if (dp_queue_manager_push_queue(slot, requestp) < 0) {
1102 if (dp_db_update_logging(client->dbhandle, ipc_info->id, DP_STATE_FAILED, DP_ERROR_QUEUE_FULL, &errorcode) < 0)
1103 TRACE_ERROR("update log sock:%d download-id:%d", client->channel, ipc_info->id);
1104 requestp->state = DP_STATE_FAILED;
1105 requestp->error = DP_ERROR_QUEUE_FULL;
1106 errorcode = DP_ERROR_QUEUE_FULL;
1112 int enable_cb = recv_int;
1113 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_NETWORK_TYPE, (void *)&enable_cb, ipc_info->size, 0, &errorcode) < 0) {
1114 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1115 errorcode = DP_ERROR_DISK_BUSY;
1120 case DP_PROP_NETWORK_BONDING:
1123 errorcode = __dp_request_read_int(client->channel, ipc_info, &recv_int);
1124 if (errorcode == DP_ERROR_NONE) {
1125 if (requestp != NULL && requestp->network_type != DP_NETWORK_ALL) {
1126 errorcode = DP_ERROR_INVALID_NETWORK_TYPE;
1127 TRACE_ERROR("[ERROR] wrong network type");
1128 } else if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_NETWORK_BONDING, (void *)&recv_int, ipc_info->size, 0, &errorcode) < 0) {
1129 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1130 errorcode = DP_ERROR_DISK_BUSY;
1135 case DP_PROP_NOTIFICATION_TYPE:
1138 errorcode = __dp_request_read_int(client->channel, ipc_info, &recv_int);
1139 if (recv_int == DP_NOTIFICATION_TYPE_NONE ||
1140 recv_int == DP_NOTIFICATION_TYPE_COMPLETE_ONLY ||
1141 recv_int == DP_NOTIFICATION_TYPE_ALL) {
1142 // check state request->state == DP_STATE_COMPLETED
1143 // DP_ERROR_INVALID_STATE
1144 // update notificatio type in database
1145 int noti_type = recv_int;
1146 if (requestp != NULL) {
1147 if (recv_int < requestp->noti_type) {
1148 // if already notification, unregister from notification bar.
1149 if (recv_int == DP_NOTIFICATION_TYPE_NONE) {
1150 if (dp_notification_manager_clear_notification(slot, requestp, DP_NOTIFICATION) < 0)
1151 TRACE_ERROR("failed to clear notification %s", dp_print_property(ipc_info->property));
1153 if (dp_notification_manager_clear_notification(slot, requestp, DP_NOTIFICATION_ONGOING) < 0)
1154 TRACE_ERROR("failed to clear ongoing %s", dp_print_property(ipc_info->property));
1156 requestp->noti_type = recv_int;
1158 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, DP_DB_COL_NOTI_TYPE, (void *)¬i_type, ipc_info->size, 0, &errorcode) < 0) {
1159 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1160 errorcode = DP_ERROR_DISK_BUSY;
1163 errorcode = DP_ERROR_INVALID_PARAMETER;
1167 case DP_PROP_NOTIFICATION_SUBJECT:
1169 char *recv_str = NULL;
1170 errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
1171 if (errorcode == DP_ERROR_NONE) {
1172 if (recv_str == NULL) {
1173 errorcode = DP_ERROR_INVALID_PARAMETER;
1175 // write to database here
1176 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, DP_DB_COL_NOTI_SUBJECT, (void *)recv_str, ipc_info->size, 2, &errorcode) < 0) {
1177 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1178 errorcode = DP_ERROR_DISK_BUSY;
1185 case DP_PROP_NOTIFICATION_DESCRIPTION:
1187 char *recv_str = NULL;
1188 errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
1189 if (errorcode == DP_ERROR_NONE) {
1190 if (recv_str == NULL) {
1191 errorcode = DP_ERROR_INVALID_PARAMETER;
1193 // write to database here
1194 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, DP_DB_COL_NOTI_DESCRIPTION, (void *)recv_str, ipc_info->size, 2, &errorcode) < 0) {
1195 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1196 errorcode = DP_ERROR_DISK_BUSY;
1203 case DP_PROP_NOTIFICATION_RAW: // bundle_type(db column) + bundle_binary
1205 int bundle_type = -1;
1206 errorcode = __dp_request_read_int(client->channel, ipc_info, &bundle_type);
1207 TRACE_DEBUG("read %s type:%d", dp_print_property(ipc_info->property), bundle_type);
1208 char *raw_column = NULL;
1209 if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_ONGOING)
1210 raw_column = DP_DB_COL_NOTI_RAW_ONGOING;
1211 else if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_COMPLETE)
1212 raw_column = DP_DB_COL_NOTI_RAW_COMPLETE;
1213 else if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_FAILED)
1214 raw_column = DP_DB_COL_NOTI_RAW_FAIL;
1216 errorcode = DP_ERROR_INVALID_PARAMETER;
1218 if (dp_ipc_query(client->channel, ipc_info->id, DP_SEC_SET,
1219 ipc_info->property, errorcode, 0) < 0) {
1220 TRACE_ERROR("check ipc sock:%d", client->channel);
1221 errorcode = DP_ERROR_IO_ERROR;
1223 if (errorcode == DP_ERROR_NONE) {
1224 dp_ipc_fmt *raw_info = dp_ipc_get_fmt(client->channel);
1225 if (raw_info == NULL || raw_info->section != ipc_info->section ||
1226 raw_info->property != ipc_info->property ||
1227 (raw_info->id != ipc_info->id)) {
1228 TRACE_ERROR("there is a confusion waiting raw binary in %s section", dp_print_property(ipc_info->property));
1229 errorcode = DP_ERROR_IO_ERROR;
1231 if (raw_info != NULL && raw_info->size > 0 && raw_info->size < SIZE_MAX) {
1232 unsigned char *recv_raws = (unsigned char *)calloc(raw_info->size, sizeof(unsigned char));
1233 if (recv_raws == NULL) {
1234 TRACE_ERROR("sock:%d check memory length:%zd", client->channel, raw_info->size);
1235 errorcode = DP_ERROR_OUT_OF_MEMORY;
1237 if (dp_ipc_read(client->channel, recv_raws, raw_info->size, __FUNCTION__) <= 0) {
1238 TRACE_ERROR("sock:%d check ipc length:%zd", client->channel, raw_info->size);
1239 errorcode = DP_ERROR_IO_ERROR;
1241 TRACE_DEBUG("sock:%d length:%zd raws", client->channel, raw_info->size);
1243 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, raw_column, (void *)recv_raws, raw_info->size, 3, &errorcode) < 0) {
1244 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1245 errorcode = DP_ERROR_DISK_BUSY;
1251 errorcode = DP_ERROR_IO_ERROR;
1257 case DP_PROP_HTTP_HEADER: // a request can have one or more fields, a fields can have only one value.
1259 char *header_field = NULL;
1260 char *header_value = NULL;
1261 // 1. read field string
1262 // 2. response after checking sql status
1263 // 3. read query IPC for checking IPC
1264 // 4. read value string
1266 errorcode = __dp_request_read_string(client->channel, ipc_info, &header_field);
1267 if (errorcode == DP_ERROR_NONE && header_field != NULL) {
1269 int check_field = dp_db_check_duplicated_string(client->dbhandle, ipc_info->id, DP_TABLE_HEADERS, DP_DB_COL_HEADER_FIELD, 0, header_field, &errorcode);
1270 if (check_field < 0) {
1271 errorcode = DP_ERROR_DISK_BUSY;
1273 errorcode = DP_ERROR_NONE;
1275 if (dp_ipc_query(client->channel, ipc_info->id, ipc_info->section,
1276 ipc_info->property, errorcode, 0) < 0) {
1277 TRACE_ERROR("check ipc sock:%d", client->channel);
1278 errorcode = DP_ERROR_IO_ERROR;
1280 dp_ipc_fmt *header_ipc = dp_ipc_get_fmt(client->channel);
1281 if (header_ipc == NULL || header_ipc->section != ipc_info->section ||
1282 header_ipc->property != ipc_info->property ||
1283 (header_ipc->id != ipc_info->id)) {
1284 TRACE_ERROR("there is a confusion during waiting http string in %s section", dp_print_property(ipc_info->property));
1285 errorcode = DP_ERROR_IO_ERROR;
1287 errorcode = __dp_request_read_string(client->channel, header_ipc, &header_value);
1288 if (errorcode == DP_ERROR_NONE && header_value != NULL) {
1289 if (check_field == 0) { // insert
1290 if (dp_db_new_header(client->dbhandle, ipc_info->id, header_field, header_value, &errorcode) < 0) {
1291 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1292 errorcode = DP_ERROR_DISK_BUSY;
1295 if (dp_db_update_header(client->dbhandle, ipc_info->id, header_field, header_value, &errorcode) < 0) {
1296 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1297 errorcode = DP_ERROR_DISK_BUSY;
1301 if (errorcode != DP_ERROR_NONE)
1302 TRACE_ERROR("failed to set %s, error:%s", dp_print_property(ipc_info->property), dp_print_errorcode(errorcode));
1303 if (header_value == NULL) {
1304 TRACE_ERROR("failed to set %s, do you want to run as unset?", dp_print_property(ipc_info->property));
1305 errorcode = DP_ERROR_INVALID_PARAMETER;
1313 if (errorcode != DP_ERROR_NONE)
1314 TRACE_ERROR("failed to set %s, error:%s", dp_print_property(ipc_info->property), dp_print_errorcode(errorcode));
1315 if (header_field == NULL) {
1316 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1317 errorcode = DP_ERROR_INVALID_PARAMETER;
1324 case DP_PROP_VERIFY_HOST:
1327 errorcode = __dp_request_read_int(client->channel, ipc_info, &recv_int);
1328 if (errorcode == DP_ERROR_NONE) {
1329 if (requestp != NULL)
1330 requestp->disable_verify_host = recv_int ? 0 : 1;
1335 errorcode = DP_ERROR_INVALID_PARAMETER;
1339 if (dp_ipc_query(client->channel, ipc_info->id, DP_SEC_SET,
1340 ipc_info->property, errorcode, 0) < 0)
1341 TRACE_ERROR("check ipc sock:%d", client->channel);
1345 static int __dp_request_unset_info(dp_client_fmt *client, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
1347 if (client == NULL || ipc_info == NULL) {
1348 TRACE_ERROR("check client or ipc info.");
1349 return DP_ERROR_INVALID_PARAMETER;
1352 int errorcode = DP_ERROR_NONE;
1354 switch (ipc_info->property) {
1356 // it would be run like cancel operation
1357 if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_URL, &errorcode) < 0)
1358 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1361 if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_PROXY, &errorcode) < 0)
1362 TRACE_ERROR("failed to unset %s errorcode:%s", dp_print_property(ipc_info->property), dp_print_errorcode(errorcode));
1364 case DP_PROP_DESTINATION:
1365 // if downloading, change destination to da_agent
1366 if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_DESTINATION, &errorcode) < 0)
1367 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1369 case DP_PROP_FILENAME:
1370 if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_FILENAME, &errorcode) < 0)
1371 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1373 case DP_PROP_STATE_CALLBACK:
1375 if (requestp != NULL)
1376 requestp->state_cb = 0;
1379 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_STATE_EVENT, (void *)&enable_cb, 0, 0, &errorcode) < 0) {
1380 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1381 errorcode = DP_ERROR_DISK_BUSY;
1385 case DP_PROP_PROGRESS_CALLBACK:
1387 if (requestp != NULL)
1388 requestp->progress_cb = 0;
1391 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_PROGRESS_EVENT, (void *)&enable_cb, 0, 0, &errorcode) < 0) {
1392 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1393 errorcode = DP_ERROR_DISK_BUSY;
1397 case DP_PROP_AUTO_DOWNLOAD:
1399 // update autodownload property as 0 in database
1401 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_LOGGING, DP_DB_COL_AUTO_DOWNLOAD, (void *)&enable_cb, 0, 0, &errorcode) < 0) {
1402 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1403 errorcode = DP_ERROR_DISK_BUSY;
1407 case DP_PROP_NETWORK_TYPE:
1410 // update database here
1411 if (requestp != NULL)
1412 requestp->network_type = DP_NETWORK_OFF;
1414 int enable_cb = DP_NETWORK_OFF;
1415 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_NETWORK_TYPE, (void *)&enable_cb, ipc_info->size, 0, &errorcode) < 0) {
1416 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1417 errorcode = DP_ERROR_DISK_BUSY;
1421 case DP_PROP_NOTIFICATION_TYPE:
1423 int noti_type = DP_NOTIFICATION_TYPE_NONE;
1424 if (requestp != NULL)
1425 requestp->noti_type = noti_type;
1427 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, DP_DB_COL_NOTI_TYPE, (void *)¬i_type, ipc_info->size, 0, &errorcode) < 0) {
1428 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1429 errorcode = DP_ERROR_DISK_BUSY;
1433 case DP_PROP_NOTIFICATION_SUBJECT:
1435 if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, DP_DB_COL_NOTI_SUBJECT, &errorcode) < 0)
1436 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1439 case DP_PROP_NOTIFICATION_DESCRIPTION:
1441 if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, DP_DB_COL_NOTI_DESCRIPTION, &errorcode) < 0)
1442 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1445 case DP_PROP_NOTIFICATION_RAW:
1447 int bundle_type = -1;
1448 errorcode = __dp_request_read_int(client->channel, ipc_info, &bundle_type);
1449 TRACE_DEBUG("read %s type:%d", dp_print_property(ipc_info->property), bundle_type);
1450 char *raw_column = NULL;
1451 if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_ONGOING)
1452 raw_column = DP_DB_COL_NOTI_RAW_ONGOING;
1453 else if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_COMPLETE)
1454 raw_column = DP_DB_COL_NOTI_RAW_COMPLETE;
1455 else if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_FAILED)
1456 raw_column = DP_DB_COL_NOTI_RAW_FAIL;
1457 if (raw_column != NULL) {
1458 if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, raw_column, &errorcode) < 0)
1459 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1461 TRACE_ERROR("invalid param set: %s type:%d", dp_print_property(ipc_info->property), bundle_type);
1462 errorcode = DP_ERROR_INVALID_PARAMETER;
1466 case DP_PROP_HTTP_HEADER: // unset value by field
1468 char *header_field = NULL;
1469 errorcode = __dp_request_read_string(client->channel, ipc_info, &header_field);
1470 if (errorcode == DP_ERROR_NONE && header_field != NULL) {
1471 int is_present = dp_db_check_duplicated_string(client->dbhandle, ipc_info->id, DP_TABLE_HEADERS, DP_DB_COL_HEADER_FIELD, 0, header_field, &errorcode);
1473 errorcode = DP_ERROR_DISK_BUSY;
1474 else if (is_present == 0)
1475 errorcode = DP_ERROR_FIELD_NOT_FOUND;
1476 else if (dp_db_cond_delete(client->dbhandle, ipc_info->id, DP_TABLE_HEADERS, DP_DB_COL_HEADER_FIELD, header_field, 2, &errorcode) < 0) {
1477 TRACE_ERROR("failed to unset %s for %s", dp_print_property(ipc_info->property), header_field);
1478 errorcode = DP_ERROR_DISK_BUSY;
1481 if (errorcode != DP_ERROR_NONE)
1482 TRACE_ERROR("failed to set %s, error:%s", dp_print_property(ipc_info->property), dp_print_errorcode(errorcode));
1483 if (header_field == NULL) {
1484 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1485 errorcode = DP_ERROR_INVALID_PARAMETER;
1492 errorcode = DP_ERROR_INVALID_PARAMETER;
1496 if (dp_ipc_query(client->channel, ipc_info->id, DP_SEC_UNSET,
1497 ipc_info->property, errorcode, 0) < 0) {
1498 TRACE_ERROR("check ipc sock:%d", client->channel);
1503 static int __dp_call_cancel_agent(dp_request_fmt *request)
1506 if (request != NULL) {
1507 if (request->agent_id >= 0) {
1508 TRACE_INFO("cancel download(%d) id: %d state:%s", request->agent_id,
1509 request->id, dp_print_state(request->state));
1510 if (dp_cancel_agent_download_without_update(request->agent_id) == 0)
1513 TRACE_ERROR("invalid agent-id:%d id:%d", request->agent_id, request->id);
1519 static int __dp_request_controls(dp_client_slots_fmt *slot, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
1522 TRACE_ERROR("check slot memory");
1523 return DP_ERROR_INVALID_PARAMETER;
1525 dp_client_fmt *client = &slot->client;
1526 if (client == NULL || ipc_info == NULL) {
1527 TRACE_ERROR("check client or ipc info.");
1528 return DP_ERROR_INVALID_PARAMETER;
1531 int errorcode = DP_ERROR_NONE;
1533 if (ipc_info->property == DP_PROP_CREATE) {
1534 // check packets again
1535 if (ipc_info->size != 0 || ipc_info->id != -1)
1536 errorcode = DP_ERROR_IO_ERROR;
1538 errorcode = __dp_request_create(client, ipc_info);
1542 int download_state = DP_STATE_NONE;
1543 if (requestp != NULL) {
1544 download_state = requestp->state;
1546 if (dp_db_get_property_int(client->dbhandle, ipc_info->id, DP_TABLE_LOGGING, DP_DB_COL_STATE, &download_state, &errorcode) < 0) {
1547 TRACE_ERROR("failed to get %s", dp_print_property(ipc_info->property));
1548 errorcode = DP_ERROR_ID_NOT_FOUND;
1550 if (dp_ipc_query(client->channel, ipc_info->id, DP_SEC_SET,
1551 ipc_info->property, errorcode, 0) < 0) {
1552 TRACE_ERROR("check ipc sock:%d", client->channel);
1557 TRACE_DEBUG("id:%d state:%s set property:%s", ipc_info->id, dp_print_state(download_state), dp_print_property(ipc_info->property));
1559 if (ipc_info->property == DP_PROP_START) {
1561 if (download_state == DP_STATE_COMPLETED ||
1562 download_state == DP_STATE_DOWNLOADING) {
1563 errorcode = DP_ERROR_INVALID_STATE;
1566 if (requestp == NULL) { // load from databse
1568 // load and add new request to client->requests.
1570 if (requestp == NULL) {
1571 TRACE_ERROR("failed to load id:%d from database sock:%d", ipc_info->id, client->channel);
1572 errorcode = DP_ERROR_DISK_BUSY;
1574 if (errorcode == DP_ERROR_NONE) {
1576 if (dp_db_update_logging(client->dbhandle, ipc_info->id, DP_STATE_QUEUED, DP_ERROR_NONE, &errorcode) < 0) {
1577 TRACE_ERROR("update log sock:%d download-id:%d", client->channel, ipc_info->id);
1578 errorcode = DP_ERROR_DISK_BUSY;
1580 requestp->state = DP_STATE_QUEUED;
1581 requestp->error = DP_ERROR_NONE;
1582 // if it's the first request for this client-> push a request at the head of queue.
1583 // check count queued, connecting.downloading in requets of client
1584 // else push at the tail of queue.
1586 if (dp_queue_manager_push_queue(slot, requestp) < 0) {
1587 if (dp_db_update_logging(client->dbhandle, ipc_info->id, DP_STATE_FAILED, DP_ERROR_QUEUE_FULL, &errorcode) < 0)
1588 TRACE_ERROR("update log sock:%d download-id:%d", client->channel, ipc_info->id);
1589 requestp->state = DP_STATE_FAILED;
1590 requestp->error = DP_ERROR_QUEUE_FULL;
1591 errorcode = DP_ERROR_QUEUE_FULL;
1593 dp_queue_manager_wake_up();
1595 if (requestp->noti_type == DP_NOTIFICATION_TYPE_ALL) {
1596 if (dp_notification_manager_push_notification(slot, requestp, DP_NOTIFICATION_ONGOING) < 0)
1597 TRACE_ERROR("failed to register notification for id:%d", ipc_info->id);
1602 TRACE_DEBUG("id:%d check start error:%s", ipc_info->id, dp_print_errorcode(errorcode));
1605 } else if (ipc_info->property == DP_PROP_PAUSE) {
1607 if (download_state > DP_STATE_DOWNLOADING) {
1608 errorcode = DP_ERROR_INVALID_STATE;
1609 } else { // change state regardless it's on memory or not.
1610 if (dp_db_update_logging(client->dbhandle, ipc_info->id, DP_STATE_PAUSED, DP_ERROR_NONE, &errorcode) < 0) {
1611 TRACE_ERROR("update log sock:%d download-id:%d", client->channel, ipc_info->id);
1612 errorcode = DP_ERROR_DISK_BUSY;
1614 // call da_pause API
1615 if (requestp != NULL) {
1616 // pop from queue. if state is queued.
1617 if (requestp->state == DP_STATE_QUEUED) {
1618 dp_queue_manager_clear_queue(requestp);
1619 } else if (requestp->state == DP_STATE_CONNECTING ||
1620 requestp->state == DP_STATE_DOWNLOADING) {
1621 if (dp_pause_agent_download_without_update(requestp->agent_id) < 0)
1622 TRACE_ERROR("failed to pause download(%d) id:%d", requestp->agent_id, ipc_info->id);
1624 requestp->state = DP_STATE_PAUSED;
1625 requestp->error = DP_ERROR_NONE;
1630 } else if (ipc_info->property == DP_PROP_CANCEL) {
1632 if (download_state > DP_STATE_COMPLETED) {
1633 errorcode = DP_ERROR_INVALID_STATE;
1634 } else { // change state regardless it's on memory or not.
1635 if (dp_db_update_logging(client->dbhandle, ipc_info->id, DP_STATE_CANCELED, DP_ERROR_NONE, &errorcode) < 0) {
1636 TRACE_ERROR("update log sock:%d download-id:%d", client->channel, ipc_info->id);
1637 errorcode = DP_ERROR_DISK_BUSY;
1639 // call da_cancel API
1640 if (requestp != NULL) {
1641 // pop from queue. if state is queued.
1642 if (requestp->state == DP_STATE_QUEUED) {
1643 dp_queue_manager_clear_queue(requestp);
1644 } else if (requestp->state == DP_STATE_CONNECTING ||
1645 requestp->state == DP_STATE_DOWNLOADING ||
1646 requestp->state == DP_STATE_PAUSED) {
1647 if (__dp_call_cancel_agent(requestp) < 0)
1648 TRACE_ERROR("failed to cancel download(%d) id:%d", requestp->agent_id, ipc_info->id);
1650 requestp->agent_id = -1;
1651 requestp->state = DP_STATE_CANCELED;
1652 requestp->error = DP_ERROR_NONE;
1653 if (requestp->noti_type == DP_NOTIFICATION_TYPE_COMPLETE_ONLY ||
1654 requestp->noti_type == DP_NOTIFICATION_TYPE_ALL) {
1655 if (dp_notification_manager_push_notification(slot, requestp, DP_NOTIFICATION) < 0)
1656 TRACE_ERROR("failed to register notification for id:%d", ipc_info->id);
1662 } else if (ipc_info->property == DP_PROP_DESTROY) {
1665 // pop from queue. if state is queued.
1666 if (requestp != NULL) {
1667 if (requestp->state == DP_STATE_QUEUED)
1668 dp_queue_manager_clear_queue(requestp);
1669 if (requestp->state == DP_STATE_CONNECTING ||
1670 requestp->state == DP_STATE_DOWNLOADING) {
1671 // update state property database;
1672 if (dp_db_update_logging(client->dbhandle, ipc_info->id, DP_STATE_CANCELED, DP_ERROR_NONE, &errorcode) < 0) {
1673 TRACE_ERROR("update log sock:%d download-id:%d", client->channel, ipc_info->id);
1675 // call da_cancel API
1676 if (__dp_call_cancel_agent(requestp) < 0)
1677 TRACE_ERROR("failed to cancel download(%d) id:%d", requestp->agent_id, ipc_info->id);
1679 requestp->state = DP_STATE_CANCELED;
1681 if (requestp->state == DP_STATE_QUEUED || requestp->state == DP_STATE_CANCELED) {
1683 if (requestp->noti_type == DP_NOTIFICATION_TYPE_COMPLETE_ONLY ||
1684 requestp->noti_type == DP_NOTIFICATION_TYPE_ALL) {
1685 if (dp_notification_manager_push_notification(slot, requestp, DP_NOTIFICATION) < 0)
1686 TRACE_ERROR("failed to register notification for id:%d", ipc_info->id);
1689 requestp->agent_id = -1;
1691 errorcode = dp_request_destroy(client, ipc_info, requestp);
1694 errorcode = DP_ERROR_INVALID_PARAMETER;
1695 TRACE_ERROR("invalid param - id:%d set property:%s", ipc_info->id, dp_print_property(ipc_info->property));
1700 if (dp_ipc_query(client->channel, ipc_info->id, DP_SEC_CONTROL,
1701 ipc_info->property, errorcode, 0) < 0) {
1702 TRACE_ERROR("check ipc sock:%d", client->channel);
1705 // workaround. client still request the feedback by cancelation
1706 if (ipc_info->property == DP_PROP_CANCEL ||
1707 ipc_info->property == DP_PROP_PAUSE) {
1708 if (requestp != NULL && requestp->state_cb == 1) {
1709 if (slot->client.notify < 0 ||
1710 dp_notify_feedback(slot->client.notify, slot, ipc_info->id, requestp->state, errorcode, 0) < 0) {
1711 TRACE_ERROR("id:%d disable state callback by IO_ERROR", ipc_info->id);
1712 requestp->state_cb = 0;
1720 static int __dp_client_requests(dp_client_slots_fmt *slot, dp_ipc_fmt *ipc_info)
1723 TRACE_ERROR("check slot memory");
1724 return DP_ERROR_INVALID_PARAMETER;
1726 dp_client_fmt *client = &slot->client;
1727 if (client == NULL || ipc_info == NULL) {
1728 TRACE_ERROR("check client or ipc info.");
1729 return DP_ERROR_INVALID_PARAMETER;
1732 int errorcode = DP_ERROR_NONE;
1734 // check id except create command /////////// DP_ERROR_ID_NOT_FOUND
1735 dp_request_fmt *requestp = NULL;
1736 if (ipc_info->section != DP_SEC_CONTROL ||
1737 ipc_info->property != DP_PROP_CREATE) {
1738 // check on requests
1740 requestp = client->requests;
1741 errorcode = DP_ERROR_ID_NOT_FOUND;
1742 for (; i < MAX_DOWNLOAD_HANDLE; i++) {
1743 if (requestp == NULL)
1745 //TRACE_DEBUG("link %d info: id:%d access-time:%d", i, requestp->id, requestp->access_time);
1746 if (requestp->id == ipc_info->id) {
1747 errorcode = DP_ERROR_NONE;
1750 requestp = requestp->next;
1752 if (errorcode == DP_ERROR_ID_NOT_FOUND) {
1753 // check in database
1754 if (dp_db_check_duplicated_int(client->dbhandle, DP_TABLE_LOGGING, DP_DB_COL_ID, ipc_info->id, &errorcode) > 0) {
1755 //TRACE_DEBUG("found %d from database", ipc_info->id);
1756 errorcode = DP_ERROR_NONE;
1761 if (errorcode != DP_ERROR_NONE) { // prechecking
1762 TRACE_ERROR("precheck errorcode:%s sock:%d id:%d section:%s property:%s",
1763 dp_print_errorcode(errorcode),
1764 client->channel, ipc_info->id,
1765 dp_print_section(ipc_info->section),
1766 dp_print_property(ipc_info->property));
1768 // clear followed packets.
1769 if (ipc_info->size > 0) {
1770 char garbage[ipc_info->size];
1771 if (read(client->channel, &garbage, ipc_info->size) == 0) {
1772 TRACE_ERROR("sock:%d closed peer", client->channel);
1773 errorcode = DP_ERROR_IO_ERROR;
1777 if (dp_ipc_query(client->channel, ipc_info->id,
1778 ipc_info->section, ipc_info->property, errorcode, 0) < 0) {
1779 TRACE_ERROR("check ipc sock:%d", client->channel);
1780 errorcode = DP_ERROR_IO_ERROR;
1785 switch (ipc_info->section) {
1786 case DP_SEC_CONTROL:
1787 errorcode = __dp_request_controls(slot, ipc_info, requestp);
1790 errorcode = __dp_request_get_info(client, ipc_info, requestp);
1793 errorcode = __dp_request_set_info(slot, ipc_info, requestp);
1796 errorcode = __dp_request_unset_info(client, ipc_info, requestp);
1799 errorcode = DP_ERROR_INVALID_PARAMETER;
1805 static void __dp_client_stop_all_requests(dp_client_slots_fmt *slot)
1807 unsigned push_count = 0;
1808 int errorcode = DP_ERROR_NONE;
1810 dp_request_fmt *tailp = slot->client.requests;
1811 for (; tailp != NULL; i++) {
1812 TRACE_DEBUG("request %d stop id:%d state:%s", i, tailp->id, dp_print_state(tailp->state));
1813 int state = tailp->state;
1814 if (state == DP_STATE_CONNECTING) {
1815 if (dp_cancel_agent_download_without_update(tailp->agent_id) < 0)
1816 TRACE_ERROR("failed to cancel download(%d) id:%d", tailp->agent_id, tailp->id);
1817 } else if (state == DP_STATE_DOWNLOADING) {
1818 if (dp_pause_agent_download(tailp->agent_id) < 0)
1819 TRACE_ERROR("failed to pause download(%d) id:%d", tailp->agent_id, tailp->id);
1821 if (state == DP_STATE_DOWNLOADING || state == DP_STATE_CONNECTING) {
1822 tailp->state = DP_STATE_QUEUED;
1823 // This is error code for checking the reason when changing ip configuration process
1824 tailp->error = DP_ERROR_IO_EAGAIN;
1825 // push to queue now
1826 // in da callback, check DP_ERROR_IO_EAGAIN, then ignore.
1827 if (dp_db_update_logging(slot->client.dbhandle, tailp->id, tailp->state, DP_ERROR_NONE, &errorcode) < 0)
1828 TRACE_ERROR("update log sock:%d download-id:%d", slot->client.channel, tailp->id);
1829 if (dp_queue_manager_push_queue(slot, tailp) < 0) {
1830 TRACE_ERROR("Fail to push queueg sock:%d download-id:%d", slot->client.channel, tailp->id);
1831 // FIXME later : error case. How can handle this item?
1836 tailp = tailp->next;
1839 dp_queue_manager_wake_up();
1842 void dp_client_sig_handler(int signo)
1844 TRACE_INFO("thread:%lu signal:%d", pthread_self(), signo);
1847 void *dp_client_request_thread(void *arg)
1849 dp_client_slots_fmt *slot = (dp_client_slots_fmt *)arg;
1851 TRACE_ERROR("slot null, can not launch the thread for client");
1855 // wait detaching thread
1856 CLIENT_MUTEX_LOCK(&slot->mutex);
1858 TRACE_INFO("slot %p thread:%lu", slot, slot->thread);
1860 struct sigaction act = {{0},};
1862 sigemptyset(&newmask);
1863 sigaddset(&newmask, SIGUSR1);
1864 act.sa_handler = dp_client_sig_handler;
1865 sigaction(SIGUSR1, &act, NULL);
1867 fd_set imask, emask;
1868 int errorcode = DP_ERROR_NONE;
1869 dp_client_fmt *client = &slot->client;
1870 int client_sock = client->channel;
1871 struct timeval timeout; // for timeout of select
1873 CLIENT_MUTEX_UNLOCK(&slot->mutex);
1875 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
1877 while (slot != NULL && client_sock >= 0 &&
1878 client_sock == slot->client.channel) {
1879 memset(&timeout, 0x00, sizeof(struct timeval));
1880 timeout.tv_sec = DP_CARE_CLIENT_REQUEST_INTERVAL;
1883 FD_SET(client_sock, &imask);
1884 FD_SET(client_sock, &emask);
1885 if (select(client_sock + 1, &imask, 0, &emask, &timeout) < 0) {
1886 if (slot != NULL && slot->client.channel >= 0) {
1887 TRACE_INFO("broadcast by client-manager");
1888 CLIENT_MUTEX_LOCK(&slot->mutex);
1889 // check all requests
1890 __dp_client_stop_all_requests(slot);
1891 CLIENT_MUTEX_UNLOCK(&slot->mutex);
1894 TRACE_ERROR("interrupted by client-manager sock:%d", client_sock);
1898 if (FD_ISSET(client_sock, &imask) > 0) {
1900 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
1901 CLIENT_MUTEX_LOCK(&slot->mutex);
1903 client->access_time = (int)time(NULL);
1905 errorcode = DP_ERROR_NONE;
1907 // read ipc_fmt first. below func will deal followed packets
1908 dp_ipc_fmt *ipc_info = dp_ipc_get_fmt(client_sock);
1909 if (ipc_info == NULL) {
1910 TRACE_ERROR("sock:%d maybe closed", client_sock);
1911 errorcode = DP_ERROR_IO_ERROR;
1913 TRACE_INFO("sock:%d id:%d section:%s property:%s errorcode:%s size:%zd",
1914 client_sock, ipc_info->id,
1915 dp_print_section(ipc_info->section),
1916 dp_print_property(ipc_info->property),
1917 dp_print_errorcode(ipc_info->errorcode),
1920 if (client->dbhandle == 0 || dp_db_check_connection(client->dbhandle) < 0) {
1921 if (dp_db_open_client(&client->dbhandle, slot->pkgname, &errorcode) < 0) {
1922 TRACE_ERROR("failed to open database for sock:%d errorcode:%s", client_sock, dp_print_errorcode(errorcode));
1923 if (dp_ipc_query(client->channel, ipc_info->id,
1924 ipc_info->section, ipc_info->property, errorcode, 0) < 0) {
1925 TRACE_ERROR("check ipc sock:%d", client->channel);
1930 if (errorcode == DP_ERROR_NONE) {
1932 errorcode = __dp_client_requests(slot, ipc_info);
1938 CLIENT_MUTEX_UNLOCK(&slot->mutex);
1939 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
1941 if (errorcode == DP_ERROR_IO_ERROR ||
1942 errorcode == DP_ERROR_OUT_OF_MEMORY ||
1943 errorcode == DP_ERROR_INVALID_PARAMETER) {
1944 TRACE_ERROR("disconnect client errorcode:%s sock:%d",
1945 dp_print_errorcode(errorcode), client_sock);
1949 } else if (FD_ISSET(client_sock, &emask) > 0) {
1950 TRACE_ERROR("[EXCEPTION]");
1955 if (CLIENT_MUTEX_TRYLOCK(&slot->mutex) == 0) {
1956 // 1. clear zombie requests. clean requests finished. paused or ready for long time
1957 dp_client_clear_requests(slot);
1959 if (client->dbhandle != 0) {
1960 int sql_errorcode = DP_ERROR_NONE;
1961 // 2. maintain only 1000 rows for each client
1962 if (dp_db_limit_rows(client->dbhandle, DP_TABLE_LOGGING, DP_LOG_DB_LIMIT_ROWS, &sql_errorcode) < 0)
1963 TRACE_INFO("limit rows error:%s", dp_print_errorcode(sql_errorcode));
1964 // 3. maintain for 48 hours
1965 if (dp_db_limit_time(client->dbhandle, DP_TABLE_LOGGING, DP_CARE_CLIENT_INFO_PERIOD, &sql_errorcode) < 0)
1966 TRACE_INFO("limit rows error:%s", dp_print_errorcode(sql_errorcode));
1968 // 4. if no requests, exit by itself.
1969 if (slot->client.requests == NULL) {
1970 TRACE_DEBUG("no requests");
1971 CLIENT_MUTEX_UNLOCK(&slot->mutex);
1974 CLIENT_MUTEX_UNLOCK(&slot->mutex);
1977 } // while (slot != NULL && client_sock >= 0 && ....)
1979 if (client_sock >= 0 && client_sock < FD_SETSIZE) {
1980 FD_CLR(client_sock, &imask);
1981 FD_CLR(client_sock, &emask);
1984 // if no requests, clear slot after disconnect with client.
1985 CLIENT_MUTEX_LOCK(&slot->mutex);
1987 TRACE_INFO("thread done slot %p thread:%lu", slot, slot->thread);
1989 slot->thread = 0;// to prevent kill thread twice
1992 dp_request_fmt *tailp = slot->client.requests;
1993 dp_request_fmt *prevp = NULL;
1994 for (; tailp != NULL; i++) {
1995 if (tailp->state != DP_STATE_QUEUED &&
1996 tailp->state != DP_STATE_CONNECTING &&
1997 tailp->state != DP_STATE_DOWNLOADING) {
1998 dp_request_fmt *removep = tailp;
1999 if (prevp == NULL) // first request.
2000 client->requests = tailp->next;
2002 prevp->next = tailp->next;
2003 tailp = tailp->next;
2004 TRACE_DEBUG("request %d remove: id:%d state:%s", i, removep->id, dp_print_state(removep->state));
2005 dp_request_free(removep);
2008 TRACE_DEBUG("request %d remain: id:%d state:%s", i, tailp->id, dp_print_state(tailp->state));
2010 tailp = tailp->next;
2013 // if no requests after clear finished requests.
2014 if (slot->client.requests == NULL) {
2015 dp_client_slot_free(slot);
2017 if (slot->client.notify >= 0)
2018 close(slot->client.notify);
2019 dp_notify_deinit(slot->credential.pid);
2020 slot->client.notify = -1;
2021 if (slot->client.channel > 0)
2022 close(slot->client.channel);
2023 slot->client.channel = -1;
2025 TRACE_INFO("thread done slot %p thread:%lu sock:%d", slot, slot->thread, client_sock);
2026 CLIENT_MUTEX_UNLOCK(&slot->mutex);