Change the type of some log messages from DEBUG to INFO
[platform/framework/web/download-provider.git] / provider / download-provider-client.c
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <sys/time.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include <sys/stat.h>
21 #include <signal.h>
22 #include <limits.h>
23
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>
38
39 #ifndef SIZE_MAX
40 #define SIZE_MAX ((size_t) - 1)
41 #endif
42
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,
75 };
76
77 char *dp_print_state(int state)
78 {
79         switch (state) {
80         case DP_STATE_NONE:
81                 return "NONE";
82         case DP_STATE_READY:
83                 return "READY";
84         case DP_STATE_QUEUED:
85                 return "QUEUED";
86         case DP_STATE_CONNECTING:
87                 return "CONNECTING";
88         case DP_STATE_DOWNLOADING:
89                 return "DOWNLOADING";
90         case DP_STATE_PAUSED:
91                 return "PAUSED";
92         case DP_STATE_COMPLETED:
93                 return "COMPLETED";
94         case DP_STATE_CANCELED:
95                 return "CANCELED";
96         case DP_STATE_FAILED:
97                 return "FAILED";
98         default:
99                 break;
100         }
101         return "UNKNOWN";
102 }
103
104 char *dp_print_errorcode(int errorcode)
105 {
106         switch (errorcode) {
107         case DP_ERROR_NONE:
108                 return "NONE";
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:
114                 return "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:
120                 return "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:
132                 return "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:
140                 return "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:
156                 return "DISK_BUSY";
157         case DP_ERROR_ID_NOT_FOUND:
158                 return "ID_NOT_FOUND";
159         default:
160                         break;
161         }
162         return "UNKNOWN";
163 }
164
165 char *dp_print_section(short section)
166 {
167         switch (section) {
168         case DP_SEC_NONE:
169                 return "NONE";
170         case DP_SEC_INIT:
171                 return "INIT";
172         case DP_SEC_DEINIT:
173                 return "DEINIT";
174         case DP_SEC_CONTROL:
175                 return "CONTROL";
176         case DP_SEC_GET:
177                 return "GET";
178         case DP_SEC_SET:
179                 return "SET";
180         case DP_SEC_UNSET:
181                 return "UNSET";
182         default:
183                 break;
184         }
185         return "UNKNOWN";
186 }
187
188 char *dp_print_property(unsigned property)
189 {
190         switch (property) {
191         case DP_PROP_NONE:
192                 return "NONE";
193         case DP_PROP_CREATE:
194                 return "CREATE";
195         case DP_PROP_START:
196                 return "START";
197         case DP_PROP_PAUSE:
198                 return "PAUSE";
199         case DP_PROP_CANCEL:
200                 return "CANCEL";
201         case DP_PROP_DESTROY:
202                 return "DESTROY";
203         case DP_PROP_URL:
204                 return "URL";
205         case DP_PROP_PROXY:
206                 return "PROXY";
207         case DP_PROP_DESTINATION:
208                 return "DESTINATION";
209         case DP_PROP_FILENAME:
210                 return "FILENAME";
211         case DP_PROP_STATE_CALLBACK:
212                 return "STATE_CB";
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:
222                 return "SAVED_PATH";
223         case DP_PROP_TEMP_SAVED_PATH:
224                 return "TEMP_SAVED_PATH";
225         case DP_PROP_MIME_TYPE:
226                 return "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";
235         case DP_PROP_ETAG:
236                 return "ETAG";
237         case DP_PROP_STATE:
238                 return "STATE";
239         case DP_PROP_ERROR:
240                 return "ERROR";
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";
255         default:
256                 break;
257         }
258         return "UNKNOWN";
259 }
260
261 static const char *__dp_get_db_table_name(unsigned property)
262 {
263         switch (property) {
264         case DP_PROP_URL:
265         case DP_PROP_PROXY:
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:
274         case DP_PROP_STATE:
275         case DP_PROP_ERROR:
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:
281         case DP_PROP_ETAG:
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:
294         case DP_PROP_NONE:
295         case DP_PROP_CREATE:
296         case DP_PROP_START:
297         case DP_PROP_PAUSE:
298         case DP_PROP_CANCEL:
299         case DP_PROP_DESTROY:
300         default:
301                 break;
302         }
303         return NULL;
304 }
305
306 static int __dp_get_download_id(dp_client_fmt *client)
307 {
308         int download_id = -1;
309         int check_duplicate = 1;
310         int retry_count = 0;
311         int errorcode = DP_ERROR_NONE;
312         struct timeval tval;
313
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;
319         } else {
320                 if (download_id < INT_MAX)
321                         download_id++;
322         }
323
324         retry_count = 0;
325         do {
326                 retry_count++;
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)
333                                         break;
334                         } else {
335                                 TRACE_ERROR("ERROR [%d]", errorcode);
336                         }
337                         if (retry_count < 3) {
338                                 download_id++;
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;
347                         } else {
348                                 TRACE_ERROR("failed to generate unique download_id [%d]", download_id);
349                                 return -1;
350                         }
351                 } else {
352                         TRACE_ERROR("reached INT_MAX limit");
353                         download_id = DP_FIRST_DOWNLOAD_ID;
354                 }
355         } while (check_duplicate != 0);
356         return download_id;
357 }
358
359 void dp_request_create(dp_client_fmt *client, dp_request_fmt *request)
360 {
361         // new request
362         // find the tail of linked list & check limitation
363         int i = 0;
364         dp_request_fmt *tailp = client->requests;
365         dp_request_fmt *prevp = NULL;
366         for (; i < MAX_DOWNLOAD_HANDLE; i++) {
367                 if (tailp == NULL)
368                         break;
369                 TRACE_DEBUG("link %d info: id:%d access-time:%d", i, tailp->id, tailp->access_time);
370                 prevp = tailp;
371                 tailp = tailp->next;
372         }
373         request->next = NULL;
374         if (prevp == NULL) // it's first link
375                 client->requests = request;
376         else
377                 prevp->next = request; // attach at the tail
378
379         TRACE_INFO("sock:%d download-id:%d", client->channel, request->id);
380 }
381
382 static int __dp_request_create(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
383 {
384         int errorcode = DP_ERROR_NONE;
385
386         int download_id = __dp_get_download_id(client);
387
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;
393         }
394
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));
397                 free(request);
398                 return errorcode;
399         }
400
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;
416
417         dp_request_create(client, request);
418         ipc_info->id = download_id;
419         return errorcode;
420 }
421
422 void dp_request_free(dp_request_fmt *request)
423 {
424         // free notification handle here
425         TRACE_DEBUG("destory id:%d", request->id);
426         free(request);
427 }
428
429 static int _dp_client_can_remove_request(dp_request_fmt *request)
430 {
431         if (request->id <= 0 || request->state == DP_STATE_NONE) {
432                 TRACE_ERROR("id:%d unexpected request.", request->id);
433                 return 1;
434         }
435
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)
442                         return 1;
443         }
444
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);
449                 return 1;
450         }
451
452         return 0;
453 }
454
455 static int _dp_client_check_zombie_request(dp_request_fmt *request)
456 {
457         int now_time = (int)time(NULL);
458         int time_diff = 0;
459
460         if (request->access_time > 0)
461                 time_diff = now_time - request->access_time;
462
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);
466                 return 1;
467         }
468
469         return 0;
470 }
471
472 void dp_client_clear_requests(void *slotp)
473 {
474         dp_client_slots_fmt *slot = (dp_client_slots_fmt *)slotp;
475         if (slot == NULL) {
476                 TRACE_ERROR("check slot memory");
477                 return ;
478         }
479
480         dp_client_fmt *client = &slot->client;
481         dp_request_fmt *tailp = client->requests;
482         dp_request_fmt *prevp = NULL;
483
484         unsigned queued_count = 0;
485         unsigned ongoing_count = 0;
486
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);
490
491                 if (is_zombie) {
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);
501                         }
502                 }
503
504                 if (can_remove) {
505                         dp_request_fmt *removep = tailp;
506                         if (prevp == NULL) // first request.
507                                 client->requests = tailp->next;
508                         else
509                                 prevp->next = tailp->next;
510                         tailp = 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);
513                         continue;
514                 } else {
515                         ongoing_count++;
516                 }
517
518                 if (tailp->state == DP_STATE_QUEUED)
519                         queued_count++;
520
521                 prevp = tailp;
522                 tailp = tailp->next;
523         }
524         TRACE_DEBUG("info requests:%d queued:%d", ongoing_count, queued_count);
525         if (queued_count > 0)
526                 dp_queue_manager_wake_up();
527 }
528
529 int dp_request_destroy(dp_client_fmt *client, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
530 {
531         int errorcode = DP_ERROR_NONE;
532
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);
538                 } else {
539                         int i = 1;
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;
545                                         break;
546                                 }
547                                 if (removep == requestp) {
548                                         // cancel downloading ... after checking status
549                                         prevp->next = removep->next;
550                                         dp_request_free(removep);
551                                         break;
552                                 }
553                                 prevp = removep;
554                                 removep = removep->next;
555                         }
556                 }
557         }
558
559         TRACE_DEBUG("sock:%d id:%d errorcode:%s", client->channel,
560                         (ipc_info) ? ipc_info->id : -1, dp_print_errorcode(errorcode));
561
562         return errorcode;
563 }
564
565 static int __dp_request_read_int(int sock, dp_ipc_fmt *ipc_info, int *value)
566 {
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;
572                 }
573         } else {
574                 errorcode = DP_ERROR_IO_ERROR;
575         }
576         return errorcode;
577 }
578
579 static int __dp_request_feedback_string(int sock, dp_ipc_fmt *ipc_info, void *string, size_t length, int errorvalue)
580 {
581         int errorcode = DP_ERROR_NONE;
582
583         if (length == 0 && errorvalue == DP_ERROR_NONE)
584                 errorvalue = DP_ERROR_NO_DATA;
585
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);
589         }
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);
594                 }
595         }
596         return errorcode;
597 }
598
599 static int __dp_request_read_string(int sock, dp_ipc_fmt *ipc_info, char **string)
600 {
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;
607                 } else {
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;
611                                 free(recv_str);
612                         } else {
613                                 recv_str[ipc_info->size] = '\0';
614                                 TRACE_DEBUG("sock:%d length:%zd string:%s", sock, ipc_info->size, recv_str);
615                                 *string = recv_str;
616                         }
617                 }
618         } else {
619                 errorcode = DP_ERROR_IO_ERROR;
620         }
621         return errorcode;
622 }
623
624 static int __dp_request_feedback_int(int sock, dp_ipc_fmt *ipc_info, void *value, int errorvalue, size_t extra_size)
625 {
626         int errorcode = DP_ERROR_NONE;
627         if (errorvalue != DP_ERROR_NONE)
628                 extra_size = 0;
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);
632         }
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);
637                 }
638         }
639         return errorcode;
640 }
641
642 static int __dp_request_get_info_string(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
643 {
644         int errorcode = DP_ERROR_NONE;
645         int bundle_type = -1; // DP_PROP_NOTIFICATION_RAW
646         unsigned length = 0;
647         char *string = NULL;
648         const char *table = __dp_get_db_table_name(ipc_info->property);
649         const char *column = dp_db_column[ipc_info->property];
650
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);
654
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;
661
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);
670                         }
671                         return errorcode;
672                 }
673         }
674
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;
678
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);
683         }
684
685         free(string);
686
687         return errorcode;
688 }
689
690 static int __dp_request_get_info_int_from_db(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
691 {
692         int errorcode = DP_ERROR_NONE;
693         int is_file_size = 0;
694         int ival = 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);
698
699         if (ipc_info->property == DP_PROP_RECEIVED_SIZE
700                         || ipc_info->property == DP_PROP_TOTAL_FILE_SIZE) {
701                 is_file_size = 1;
702                 size = sizeof(unsigned long long);
703         }
704
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;
710         }
711
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);
717         }
718         return errorcode;
719 }
720
721
722 static int __dp_request_get_info_int_from_request(dp_client_fmt *client,
723                 dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
724 {
725         void *val = NULL;
726         int errorcode = DP_ERROR_NONE;
727         size_t size = sizeof(int);
728
729         if (requestp) {
730                 switch (ipc_info->property) {
731                 case DP_PROP_RECEIVED_SIZE:
732                         val = &requestp->received_size;
733                         size = sizeof(unsigned long long);
734                         break;
735                 case DP_PROP_STATE_CALLBACK:
736                         val = &requestp->state_cb;
737                         break;
738                 case DP_PROP_PROGRESS_CALLBACK:
739                         val = &requestp->progress_cb;
740                         break;
741                 case DP_PROP_NETWORK_TYPE:
742                         val = &requestp->network_type;
743                         break;
744                 case DP_PROP_STATE:
745                         val = &requestp->state;
746                         break;
747                 case DP_PROP_ERROR:
748                         val = &requestp->error;
749                         break;
750                 case DP_PROP_TOTAL_FILE_SIZE:
751                         val = &requestp->file_size;
752                         size = sizeof(unsigned long long);
753                         break;
754                 case DP_PROP_NOTIFICATION_TYPE:
755                         val = &requestp->noti_type;
756                         break;
757                 default:
758                         break;
759                 }
760         } else {
761                 if (ipc_info->property == DP_PROP_RECEIVED_SIZE) {
762                         errorcode = DP_ERROR_INVALID_STATE;
763                         goto DONE;
764                 }
765                 return __dp_request_get_info_int_from_db(client, ipc_info);
766         }
767
768 DONE:
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);
773         }
774         return errorcode;
775 }
776
777 static int __dp_request_get_http_headers_info(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
778 {
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);
782
783         if (field_count < 0) {
784                 TRACE_ERROR("failed to get %s", dp_print_property(ipc_info->property));
785                 errorcode = DP_ERROR_DISK_BUSY;
786                 field_count = 0;
787         }
788
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));
797                 if (ids == NULL) {
798                         TRACE_ERROR("failed to allocate the clients");
799                         errorcode = DP_ERROR_OUT_OF_MEMORY;
800                 } else {
801                         // getting ids of clients
802                         int i = 0;
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++) {
807                                 char *string = NULL;
808                                 unsigned length = 0;
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;
815                                 }
816                                 result = __dp_request_feedback_string(client->channel,
817                                                 ipc_info, string, length, errorcode);
818                                 free(string);
819                                 if (result == DP_ERROR_IO_ERROR) {
820                                         errorcode = DP_ERROR_IO_ERROR;
821                                         TRACE_ERROR("check ipc sock:%d", client->channel);
822                                 }
823                         }
824                 }
825                 if (ids)
826                         free(ids);
827         }
828         return errorcode;
829 }
830
831
832 /* 1. read field string
833  * 2. response with extra size
834  * 3. send string.
835  */
836 static int __dp_request_get_http_header_info(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
837 {
838         char *header_field = NULL;
839         char *string = NULL;
840         unsigned length = 0;
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;
848         }
849
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);
854         }
855
856         free(header_field);
857         free(string);
858
859         return errorcode;
860 }
861
862 static int __dp_request_get_info(dp_client_fmt *client, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
863 {
864         int errorcode = DP_ERROR_NONE;
865
866         switch (ipc_info->property) {
867         case DP_PROP_URL:
868         case DP_PROP_PROXY:
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:
875         case DP_PROP_ETAG:
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);
880                 break;
881         case DP_PROP_RECEIVED_SIZE:
882         case DP_PROP_STATE_CALLBACK:
883         case DP_PROP_PROGRESS_CALLBACK:
884         case DP_PROP_NETWORK_TYPE:
885         case DP_PROP_STATE:
886         case DP_PROP_ERROR:
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);
890                 break;
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);
895                 break;
896         case DP_PROP_HTTP_HEADERS:
897                 errorcode = __dp_request_get_http_headers_info(client, ipc_info);
898                 break;
899         case DP_PROP_HTTP_HEADER:
900                 errorcode = __dp_request_get_http_header_info(client, ipc_info);
901                 break;
902         default:
903                 errorcode = DP_ERROR_INVALID_PARAMETER;
904                 break;
905         }
906
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));
910
911         return errorcode;
912 }
913
914 static int __dp_request_set_info(dp_client_slots_fmt *slot, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
915 {
916         if (slot == NULL) {
917                 TRACE_ERROR("check slot memory");
918                 return DP_ERROR_INVALID_PARAMETER;
919         }
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;
924         }
925
926         int errorcode = DP_ERROR_NONE;
927
928         // if completed or downloading, invalid state.
929         int download_state = DP_STATE_NONE;
930         if (requestp != NULL) {
931                 download_state = requestp->state;
932         } else {
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;
936                         // feedback
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);
940                         }
941                         return errorcode;
942                 }
943         }
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));
946
947         switch (ipc_info->property) {
948         case DP_PROP_URL:
949                 {
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;
955                                 } else {
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;
960                                         }
961                                         free(recv_str);
962                                 }
963                         }
964                         break;
965                 }
966         case DP_PROP_PROXY:
967                 {
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;
973                                 } else {
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));
977                                         free(recv_str);
978                                 }
979                         }
980                         break;
981                 }
982         case DP_PROP_DESTINATION:
983                 {
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;
989                                 } else {
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;
996                                         }
997                                         free(recv_str);
998                                 }
999                         }
1000                         break;
1001                 }
1002         case DP_PROP_TEMP_SAVED_PATH:
1003                 {
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;
1009                                 } else {
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;
1015                                         }
1016                                         free(recv_str);
1017                                 }
1018                         }
1019                         break;
1020                 }
1021         case DP_PROP_FILENAME:
1022                 {
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;
1028                                 } else {
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;
1033                                         }
1034                                         free(recv_str);
1035                                 }
1036                         }
1037                         break;
1038                 }
1039         case DP_PROP_STATE_CALLBACK:
1040                 {
1041                         // check state here
1042                         // DP_ERROR_INVALID_STATE if downloading or finished
1043                         // update database here
1044                         if (requestp != NULL)
1045                                 requestp->state_cb = 1;
1046
1047                         int enable_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;
1051                         }
1052                         break;
1053                 }
1054         case DP_PROP_PROGRESS_CALLBACK:
1055                 {
1056                         // check state here
1057                         // DP_ERROR_INVALID_STATE if downloading or finished
1058                         // update database here
1059                         if (requestp != NULL)
1060                                 requestp->progress_cb = 1;
1061
1062                         int enable_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;
1066                         }
1067                         break;
1068                 }
1069         case DP_PROP_AUTO_DOWNLOAD:
1070                 {
1071                         // update autodownload property as 1 in database
1072                         int enable_cb = 1;
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;
1076                         }
1077                         break;
1078                 }
1079         case DP_PROP_NETWORK_TYPE:
1080                 {
1081                         int recv_int = -1;
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;
1086                         } else {
1087                                 // update in database
1088                                 if (requestp != NULL) {
1089                                         if (requestp->state == DP_STATE_QUEUED) {
1090                                                 dp_queue_manager_clear_queue(requestp);
1091                                         } else {
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);
1098                                                         } else {
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;
1107                                                                 }
1108                                                         }
1109                                                 }
1110                                         }
1111                                 }
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;
1116                                 }
1117                         }
1118                         break;
1119                 }
1120         case DP_PROP_NETWORK_BONDING:
1121                 {
1122                         int recv_int = -1;
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;
1131                                 }
1132                         }
1133                         break;
1134                 }
1135         case DP_PROP_NOTIFICATION_TYPE:
1136                 {
1137                         int recv_int = -1;
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));
1152                                                 }
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));
1155                                         }
1156                                         requestp->noti_type = recv_int;
1157                                 }
1158                                 if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, DP_DB_COL_NOTI_TYPE, (void *)&noti_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;
1161                                 }
1162                         } else {
1163                                 errorcode = DP_ERROR_INVALID_PARAMETER;
1164                         }
1165                         break;
1166                 }
1167         case DP_PROP_NOTIFICATION_SUBJECT:
1168                 {
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;
1174                                 } else {
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;
1179                                         }
1180                                         free(recv_str);
1181                                 }
1182                         }
1183                         break;
1184                 }
1185         case DP_PROP_NOTIFICATION_DESCRIPTION:
1186                 {
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;
1192                                 } else {
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;
1197                                         }
1198                                         free(recv_str);
1199                                 }
1200                         }
1201                         break;
1202                 }
1203         case DP_PROP_NOTIFICATION_RAW: // bundle_type(db column) + bundle_binary
1204                 {
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;
1215                         else
1216                                 errorcode = DP_ERROR_INVALID_PARAMETER;
1217                         // feedback
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;
1222                         }
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;
1230                                 }
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;
1236                                         } else {
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;
1240                                                 } else {
1241                                                         TRACE_DEBUG("sock:%d length:%zd raws", client->channel, raw_info->size);
1242                                                         // save to database
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;
1246                                                         }
1247                                                 }
1248                                                 free(recv_raws);
1249                                         }
1250                                 } else {
1251                                         errorcode = DP_ERROR_IO_ERROR;
1252                                 }
1253                                 free(raw_info);
1254                         }
1255                         break;
1256                 }
1257         case DP_PROP_HTTP_HEADER: //  a request can have one or more fields, a fields can have only one value.
1258                 {
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
1265                         // 5. response
1266                         errorcode = __dp_request_read_string(client->channel, ipc_info, &header_field);
1267                         if (errorcode == DP_ERROR_NONE && header_field != NULL) {
1268                                 // check sql
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;
1272                                 } else {
1273                                         errorcode = DP_ERROR_NONE;
1274                                         // feedback
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;
1279                                         } else {
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;
1286                                                 } else {
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;
1293                                                                         }
1294                                                                 } else { // update
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;
1298                                                                         }
1299                                                                 }
1300                                                         } else {
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;
1306                                                                 }
1307                                                         }
1308                                                 }
1309                                                 free(header_ipc);
1310                                         }
1311                                 }
1312                         } else {
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;
1318                                 }
1319                         }
1320                         free(header_field);
1321                         free(header_value);
1322                         break;
1323                 }
1324         case DP_PROP_VERIFY_HOST:
1325         {
1326                 int recv_int = -1;
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;
1331                 }
1332                 break;
1333         }
1334         default:
1335                 errorcode = DP_ERROR_INVALID_PARAMETER;
1336                 break;
1337         }
1338         // feedback
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);
1342         return errorcode;
1343 }
1344
1345 static int __dp_request_unset_info(dp_client_fmt *client, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
1346 {
1347         if (client == NULL || ipc_info == NULL) {
1348                 TRACE_ERROR("check client or ipc info.");
1349                 return DP_ERROR_INVALID_PARAMETER;
1350         }
1351
1352         int errorcode = DP_ERROR_NONE;
1353
1354         switch (ipc_info->property) {
1355         case DP_PROP_URL:
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));
1359                 break;
1360         case DP_PROP_PROXY:
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));
1363                 break;
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));
1368                 break;
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));
1372                 break;
1373         case DP_PROP_STATE_CALLBACK:
1374                 {
1375                         if (requestp != NULL)
1376                                 requestp->state_cb = 0;
1377
1378                         int enable_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;
1382                         }
1383                         break;
1384                 }
1385         case DP_PROP_PROGRESS_CALLBACK:
1386                 {
1387                         if (requestp != NULL)
1388                                 requestp->progress_cb = 0;
1389
1390                         int enable_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;
1394                         }
1395                         break;
1396                 }
1397         case DP_PROP_AUTO_DOWNLOAD:
1398                 {
1399                         // update autodownload property as 0 in database
1400                         int enable_cb = 0;
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;
1404                         }
1405                         break;
1406                 }
1407         case DP_PROP_NETWORK_TYPE:
1408                 {
1409                         // check state here
1410                         // update database here
1411                         if (requestp != NULL)
1412                                 requestp->network_type = DP_NETWORK_OFF;
1413
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;
1418                         }
1419                         break;
1420                 }
1421         case DP_PROP_NOTIFICATION_TYPE:
1422                 {
1423                         int noti_type = DP_NOTIFICATION_TYPE_NONE;
1424                         if (requestp != NULL)
1425                                 requestp->noti_type = noti_type;
1426
1427                         if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, DP_DB_COL_NOTI_TYPE, (void *)&noti_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;
1430                         }
1431                         break;
1432                 }
1433         case DP_PROP_NOTIFICATION_SUBJECT:
1434                 {
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));
1437                         break;
1438                 }
1439         case DP_PROP_NOTIFICATION_DESCRIPTION:
1440                 {
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));
1443                         break;
1444                 }
1445         case DP_PROP_NOTIFICATION_RAW:
1446                 {
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));
1460                         } else {
1461                                 TRACE_ERROR("invalid param set: %s type:%d", dp_print_property(ipc_info->property), bundle_type);
1462                                 errorcode = DP_ERROR_INVALID_PARAMETER;
1463                         }
1464                         break;
1465                 }
1466         case DP_PROP_HTTP_HEADER: // unset value by field
1467                 {
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);
1472                                 if (is_present < 0)
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;
1479                                 }
1480                         } else {
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;
1486                                 }
1487                         }
1488                         free(header_field);
1489                         break;
1490                 }
1491         default:
1492                 errorcode = DP_ERROR_INVALID_PARAMETER;
1493                 break;
1494         }
1495         // feedback
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);
1499         }
1500         return errorcode;
1501 }
1502
1503 static int __dp_call_cancel_agent(dp_request_fmt *request)
1504 {
1505         int ret = -1;
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)
1511                                 ret = 0;
1512                 } else {
1513                         TRACE_ERROR("invalid agent-id:%d id:%d", request->agent_id,     request->id);
1514                 }
1515         }
1516         return ret;
1517 }
1518
1519 static int __dp_request_controls(dp_client_slots_fmt *slot, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
1520 {
1521         if (slot == NULL) {
1522                 TRACE_ERROR("check slot memory");
1523                 return DP_ERROR_INVALID_PARAMETER;
1524         }
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;
1529         }
1530
1531         int errorcode = DP_ERROR_NONE;
1532
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;
1537                 else
1538                         errorcode = __dp_request_create(client, ipc_info);
1539         } else {
1540
1541                 // get now state.
1542                 int download_state = DP_STATE_NONE;
1543                 if (requestp != NULL) {
1544                         download_state = requestp->state;
1545                 } else {
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;
1549                                 // feedback
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);
1553                                 }
1554                                 return errorcode;
1555                         }
1556                 }
1557                 TRACE_DEBUG("id:%d state:%s set property:%s", ipc_info->id, dp_print_state(download_state), dp_print_property(ipc_info->property));
1558
1559                 if (ipc_info->property == DP_PROP_START) {
1560
1561                         if (download_state == DP_STATE_COMPLETED ||
1562                                         download_state == DP_STATE_DOWNLOADING) {
1563                                 errorcode = DP_ERROR_INVALID_STATE;
1564                         } else {
1565
1566                                 if (requestp == NULL) { // load from databse
1567                                         // check state
1568                                         // load and add new request to client->requests.
1569                                 }
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;
1573                                 }
1574                                 if (errorcode == DP_ERROR_NONE) {
1575                                         // update database
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;
1579                                         } else {
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.
1585                                                 // push to 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;
1592                                                 } else { // push ok
1593                                                         dp_queue_manager_wake_up();
1594                                                         // notification
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);
1598                                                         }
1599                                                 }
1600                                         }
1601                                 }
1602                                 TRACE_DEBUG("id:%d check start error:%s", ipc_info->id, dp_print_errorcode(errorcode));
1603                         }
1604
1605                 } else if (ipc_info->property == DP_PROP_PAUSE) {
1606
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;
1613                                 } else {
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);
1623                                                 }
1624                                                 requestp->state = DP_STATE_PAUSED;
1625                                                 requestp->error = DP_ERROR_NONE;
1626                                         }
1627                                 }
1628                         }
1629
1630                 } else if (ipc_info->property == DP_PROP_CANCEL) {
1631
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;
1638                                 } else {
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);
1649                                                 }
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);
1657                                                 }
1658                                         }
1659                                 }
1660                         }
1661
1662                 } else if (ipc_info->property == DP_PROP_DESTROY) {
1663
1664                         // check state
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);
1674                                         } else {
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);
1678                                         }
1679                                         requestp->state = DP_STATE_CANCELED;
1680                                 }
1681                                 if (requestp->state == DP_STATE_QUEUED || requestp->state == DP_STATE_CANCELED) {
1682
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);
1687                                         }
1688                                 }
1689                                 requestp->agent_id = -1;
1690                         }
1691                         errorcode = dp_request_destroy(client, ipc_info, requestp);
1692
1693                 } else {
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));
1696                 }
1697         }
1698
1699         // feedback
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);
1703         }
1704
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;
1713                         }
1714                 }
1715         }
1716
1717         return errorcode;
1718 }
1719
1720 static int __dp_client_requests(dp_client_slots_fmt *slot, dp_ipc_fmt *ipc_info)
1721 {
1722         if (slot == NULL) {
1723                 TRACE_ERROR("check slot memory");
1724                 return DP_ERROR_INVALID_PARAMETER;
1725         }
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;
1730         }
1731
1732         int errorcode = DP_ERROR_NONE;
1733
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
1739                 int i = 0;
1740                 requestp = client->requests;
1741                 errorcode = DP_ERROR_ID_NOT_FOUND;
1742                 for (; i < MAX_DOWNLOAD_HANDLE; i++) {
1743                         if (requestp == NULL)
1744                                 break;
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;
1748                                 break;
1749                         }
1750                         requestp = requestp->next;
1751                 }
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;
1757                         }
1758                 }
1759         }
1760
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));
1767
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;
1774                         }
1775                 }
1776
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;
1781                 }
1782                 return errorcode;
1783         }
1784
1785         switch (ipc_info->section) {
1786         case DP_SEC_CONTROL:
1787                 errorcode = __dp_request_controls(slot, ipc_info, requestp);
1788                 break;
1789         case DP_SEC_GET:
1790                 errorcode = __dp_request_get_info(client, ipc_info, requestp);
1791                 break;
1792         case DP_SEC_SET:
1793                 errorcode = __dp_request_set_info(slot, ipc_info, requestp);
1794                 break;
1795         case DP_SEC_UNSET:
1796                 errorcode = __dp_request_unset_info(client, ipc_info, requestp);
1797                 break;
1798         default:
1799                 errorcode = DP_ERROR_INVALID_PARAMETER;
1800                 break;
1801         }
1802         return errorcode;
1803 }
1804
1805 static void __dp_client_stop_all_requests(dp_client_slots_fmt *slot)
1806 {
1807         unsigned push_count = 0;
1808         int errorcode = DP_ERROR_NONE;
1809         int i = 0;
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);
1820                 }
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?
1832                         } else {
1833                                 push_count++;
1834                         }
1835                 }
1836                 tailp = tailp->next;
1837         }
1838         if (push_count > 0)
1839                 dp_queue_manager_wake_up();
1840 }
1841
1842 void dp_client_sig_handler(int signo)
1843 {
1844         TRACE_INFO("thread:%lu signal:%d", pthread_self(), signo);
1845 }
1846
1847 void *dp_client_request_thread(void *arg)
1848 {
1849         dp_client_slots_fmt *slot = (dp_client_slots_fmt *)arg;
1850         if (slot == NULL) {
1851                 TRACE_ERROR("slot null, can not launch the thread for client");
1852                 return 0;
1853         }
1854
1855         // wait detaching thread
1856         CLIENT_MUTEX_LOCK(&slot->mutex);
1857
1858         TRACE_INFO("slot %p thread:%lu", slot, slot->thread);
1859
1860         struct sigaction act = {{0},};
1861         sigset_t newmask;
1862         sigemptyset(&newmask);
1863         sigaddset(&newmask, SIGUSR1);
1864         act.sa_handler = dp_client_sig_handler;
1865         sigaction(SIGUSR1, &act, NULL);
1866
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
1872
1873         CLIENT_MUTEX_UNLOCK(&slot->mutex);
1874
1875         pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
1876
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;
1881                 FD_ZERO(&imask);
1882                 FD_ZERO(&emask);
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);
1892                                 continue;
1893                         } else {
1894                                 TRACE_ERROR("interrupted by client-manager sock:%d", client_sock);
1895                                 break;
1896                         }
1897                 }
1898                 if (FD_ISSET(client_sock, &imask) > 0) {
1899
1900                         pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
1901                         CLIENT_MUTEX_LOCK(&slot->mutex);
1902
1903                         client->access_time = (int)time(NULL);
1904
1905                         errorcode = DP_ERROR_NONE;
1906
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;
1912                         } else {
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),
1918                                                 ipc_info->size);
1919
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);
1926                                                 }
1927                                         }
1928                                 }
1929
1930                                 if (errorcode == DP_ERROR_NONE) {
1931                                         // JOB
1932                                         errorcode = __dp_client_requests(slot, ipc_info);
1933                                 }
1934
1935                         }
1936                         free(ipc_info);
1937
1938                         CLIENT_MUTEX_UNLOCK(&slot->mutex);
1939                         pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
1940
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);
1946                                 break;
1947                         }
1948
1949                 } else if (FD_ISSET(client_sock, &emask) > 0) {
1950                         TRACE_ERROR("[EXCEPTION]");
1951                         break;
1952                 } else {
1953
1954                         // timeout
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);
1958
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));
1967                                 }
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);
1972                                         break;
1973                                 }
1974                                 CLIENT_MUTEX_UNLOCK(&slot->mutex);
1975                         }
1976                 }
1977         } // while (slot != NULL && client_sock >= 0 && ....)
1978
1979         if (client_sock >= 0 && client_sock < FD_SETSIZE) {
1980                 FD_CLR(client_sock, &imask);
1981                 FD_CLR(client_sock, &emask);
1982         }
1983
1984         // if no requests, clear slot after disconnect with client.
1985         CLIENT_MUTEX_LOCK(&slot->mutex);
1986
1987         TRACE_INFO("thread done slot %p thread:%lu", slot, slot->thread);
1988
1989         slot->thread = 0;// to prevent kill thread twice
1990
1991         int i = 0;
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;
2001                         else
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);
2006                         continue;
2007                 }
2008                 TRACE_DEBUG("request %d remain: id:%d state:%s", i, tailp->id, dp_print_state(tailp->state));
2009                 prevp = tailp;
2010                 tailp = tailp->next;
2011
2012         }
2013         // if no requests after clear finished requests.
2014         if (slot->client.requests == NULL) {
2015                 dp_client_slot_free(slot);
2016         } else {
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;
2024         }
2025         TRACE_INFO("thread done slot %p thread:%lu sock:%d", slot, slot->thread, client_sock);
2026         CLIENT_MUTEX_UNLOCK(&slot->mutex);
2027         return 0;
2028 }
2029