Use the same type to compare values
[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 void _dp_client_clear_stale_db(dp_client_fmt *client)
566 {
567         TRACE_DEBUG("Clear the stale DB data.");
568         int errorcode = DP_ERROR_NONE;
569         if (client && client->dbhandle != 0) {
570                 // maintain only 1000 rows for each client
571                 if (dp_db_limit_rows(client->dbhandle,
572                                         DP_TABLE_LOGGING, DP_LOG_DB_LIMIT_ROWS, &errorcode) < 0)
573                         TRACE_INFO("limit rows error:%s", dp_print_errorcode(errorcode));
574                 // maintain for 48 hours
575                 if (dp_db_limit_time(client->dbhandle,
576                                         DP_TABLE_LOGGING, DP_CARE_CLIENT_INFO_PERIOD, &errorcode) < 0)
577                         TRACE_INFO("limit rows error:%s", dp_print_errorcode(errorcode));
578         }
579 }
580
581 static int __dp_request_read_int(int sock, dp_ipc_fmt *ipc_info, int *value)
582 {
583         int errorcode = DP_ERROR_NONE;
584         if (ipc_info->size == sizeof(int)) {
585                 if (dp_ipc_read(sock, value, ipc_info->size, __FUNCTION__) < 0) {
586                         TRACE_ERROR("sock:%d check ipc length:%zd", sock, ipc_info->size);
587                         errorcode = DP_ERROR_IO_ERROR;
588                 }
589         } else {
590                 errorcode = DP_ERROR_IO_ERROR;
591         }
592         return errorcode;
593 }
594
595 static int __dp_request_feedback_string(int sock, dp_ipc_fmt *ipc_info, void *string, size_t length, int errorvalue)
596 {
597         int errorcode = DP_ERROR_NONE;
598
599         if (length == 0 && errorvalue == DP_ERROR_NONE)
600                 errorvalue = DP_ERROR_NO_DATA;
601
602         if (dp_ipc_query(sock, ipc_info->id, ipc_info->section, ipc_info->property, errorvalue, length * sizeof(char)) < 0) {
603                 errorcode = DP_ERROR_IO_ERROR;
604                 TRACE_ERROR("sock:%d check ipc length:%zd", sock, length);
605         }
606         if (errorvalue == DP_ERROR_NONE && errorcode == DP_ERROR_NONE) {
607                 if (dp_ipc_write(sock, string, sizeof(char) * length) < 0) {
608                         errorcode = DP_ERROR_IO_ERROR;
609                         TRACE_ERROR("sock:%d check ipc length:%zd", sock, length);
610                 }
611         }
612         return errorcode;
613 }
614
615 static int __dp_request_read_string(int sock, dp_ipc_fmt *ipc_info, char **string)
616 {
617         int errorcode = DP_ERROR_NONE;
618         if (ipc_info->size > 0) {
619                 char *recv_str = (char *)calloc((ipc_info->size + (size_t)1), sizeof(char));
620                 if (recv_str == NULL) {
621                         TRACE_ERROR("sock:%d check memory length:%zd", sock, ipc_info->size);
622                         errorcode = DP_ERROR_OUT_OF_MEMORY;
623                 } else {
624                         if (dp_ipc_read(sock, recv_str, ipc_info->size, __FUNCTION__) <= 0) {
625                                 TRACE_ERROR("sock:%d check ipc length:%zd", sock, ipc_info->size);
626                                 errorcode = DP_ERROR_IO_ERROR;
627                                 free(recv_str);
628                         } else {
629                                 recv_str[ipc_info->size] = '\0';
630                                 TRACE_DEBUG("sock:%d length:%zd string:%s", sock, ipc_info->size, recv_str);
631                                 *string = recv_str;
632                         }
633                 }
634         } else {
635                 errorcode = DP_ERROR_IO_ERROR;
636         }
637         return errorcode;
638 }
639
640 static int __dp_request_feedback_int(int sock, dp_ipc_fmt *ipc_info, void *value, int errorvalue, size_t extra_size)
641 {
642         int errorcode = DP_ERROR_NONE;
643         if (errorvalue != DP_ERROR_NONE)
644                 extra_size = 0;
645         if (dp_ipc_query(sock, ipc_info->id, ipc_info->section, ipc_info->property, errorvalue, extra_size) < 0) {
646                 errorcode = DP_ERROR_IO_ERROR;
647                 TRACE_ERROR("sock:%d check ipc length:%zd", sock, extra_size);
648         }
649         if (errorvalue == DP_ERROR_NONE && errorcode == DP_ERROR_NONE) {
650                 if (dp_ipc_write(sock, value, extra_size) < 0) {
651                         errorcode = DP_ERROR_IO_ERROR;
652                         TRACE_ERROR("sock:%d check ipc length:%zd", sock, extra_size);
653                 }
654         }
655         return errorcode;
656 }
657
658 static int __dp_request_get_info_string(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
659 {
660         int errorcode = DP_ERROR_NONE;
661         int bundle_type = -1; // DP_PROP_NOTIFICATION_RAW
662         unsigned length = 0;
663         char *string = NULL;
664         const char *table = __dp_get_db_table_name(ipc_info->property);
665         const char *column = dp_db_column[ipc_info->property];
666
667         if (ipc_info->property == DP_PROP_NOTIFICATION_RAW) {
668                 errorcode = __dp_request_read_int(client->channel, ipc_info, &bundle_type);
669                 TRACE_DEBUG("read %s type:%d", dp_print_property(ipc_info->property), bundle_type);
670
671                 if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_ONGOING)
672                         column = DP_DB_COL_NOTI_RAW_ONGOING;
673                 else if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_COMPLETE)
674                         column = DP_DB_COL_NOTI_RAW_COMPLETE;
675                 else if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_FAILED)
676                         column = DP_DB_COL_NOTI_RAW_FAIL;
677
678                 if (column == NULL) {
679                         errorcode = DP_ERROR_INVALID_PARAMETER;
680                         TRACE_ERROR("invalid type %s type:%d",
681                                         dp_print_property(ipc_info->property), bundle_type);
682                         if (dp_ipc_query(client->channel, ipc_info->id,
683                                                 ipc_info->section, ipc_info->property, errorcode, 0) < 0) {
684                                 errorcode = DP_ERROR_IO_ERROR;
685                                 TRACE_ERROR("check ipc sock:%d", client->channel);
686                         }
687                         return errorcode;
688                 }
689         }
690
691         if (dp_db_get_property_string(client->dbhandle, ipc_info->id,
692                                 table, column, (unsigned char **)&string, &length, &errorcode) < 0)
693                 errorcode = DP_ERROR_NO_DATA;
694
695         if (__dp_request_feedback_string(client->channel, ipc_info,
696                                 string, length, errorcode) == DP_ERROR_IO_ERROR) {
697                 errorcode = DP_ERROR_IO_ERROR;
698                 TRACE_ERROR("check ipc sock:%d", client->channel);
699         }
700
701         free(string);
702
703         return errorcode;
704 }
705
706 static int __dp_request_get_info_int_from_db(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
707 {
708         int errorcode = DP_ERROR_NONE;
709         int is_file_size = 0;
710         int ival = 0;
711         unsigned long long lval = 0;
712         const char *table = __dp_get_db_table_name(ipc_info->property);
713         size_t size = sizeof(int);
714
715         if (ipc_info->property == DP_PROP_RECEIVED_SIZE
716                         || ipc_info->property == DP_PROP_TOTAL_FILE_SIZE) {
717                 is_file_size = 1;
718                 size = sizeof(unsigned long long);
719         }
720
721         if (dp_db_get_property_int(client->dbhandle, ipc_info->id,
722                                 table, dp_db_column[ipc_info->property],
723                                 (is_file_size ? (void *)&lval : (void *)&ival), &errorcode) < 0) {
724                 TRACE_ERROR("failed to get %s", dp_print_property(ipc_info->property));
725                 errorcode = DP_ERROR_NO_DATA;
726         }
727
728         if (__dp_request_feedback_int(client->channel, ipc_info,
729                                 (is_file_size ? (void *)&lval : (void *)&ival),
730                                 errorcode, size) == DP_ERROR_IO_ERROR) {
731                 errorcode = DP_ERROR_IO_ERROR;
732                 TRACE_ERROR("check ipc sock:%d", client->channel);
733         }
734         return errorcode;
735 }
736
737
738 static int __dp_request_get_info_int_from_request(dp_client_fmt *client,
739                 dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
740 {
741         void *val = NULL;
742         int errorcode = DP_ERROR_NONE;
743         size_t size = sizeof(int);
744
745         if (requestp) {
746                 switch (ipc_info->property) {
747                 case DP_PROP_RECEIVED_SIZE:
748                         val = &requestp->received_size;
749                         size = sizeof(unsigned long long);
750                         break;
751                 case DP_PROP_STATE_CALLBACK:
752                         val = &requestp->state_cb;
753                         break;
754                 case DP_PROP_PROGRESS_CALLBACK:
755                         val = &requestp->progress_cb;
756                         break;
757                 case DP_PROP_NETWORK_TYPE:
758                         val = &requestp->network_type;
759                         break;
760                 case DP_PROP_STATE:
761                         val = &requestp->state;
762                         break;
763                 case DP_PROP_ERROR:
764                         val = &requestp->error;
765                         break;
766                 case DP_PROP_TOTAL_FILE_SIZE:
767                         val = &requestp->file_size;
768                         size = sizeof(unsigned long long);
769                         break;
770                 case DP_PROP_NOTIFICATION_TYPE:
771                         val = &requestp->noti_type;
772                         break;
773                 default:
774                         break;
775                 }
776         } else {
777                 if (ipc_info->property == DP_PROP_RECEIVED_SIZE) {
778                         errorcode = DP_ERROR_INVALID_STATE;
779                         goto DONE;
780                 }
781                 return __dp_request_get_info_int_from_db(client, ipc_info);
782         }
783
784 DONE:
785         if (__dp_request_feedback_int(client->channel, ipc_info,
786                                 val, errorcode, size) == DP_ERROR_IO_ERROR) {
787                 errorcode = DP_ERROR_IO_ERROR;
788                 TRACE_ERROR("check ipc sock:%d", client->channel);
789         }
790         return errorcode;
791 }
792
793 static int __dp_request_get_http_headers_info(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
794 {
795         int errorcode = DP_ERROR_NONE;
796         int field_count = dp_db_check_duplicated_int(client->dbhandle,
797                         DP_TABLE_HEADERS, DP_DB_COL_ID, ipc_info->id, &errorcode);
798
799         if (field_count < 0) {
800                 TRACE_ERROR("failed to get %s", dp_print_property(ipc_info->property));
801                 errorcode = DP_ERROR_DISK_BUSY;
802                 field_count = 0;
803         }
804
805         int result = __dp_request_feedback_int(client->channel,
806                         ipc_info, (void *)&field_count, errorcode, sizeof(int));
807         if (result == DP_ERROR_IO_ERROR) {
808                 errorcode = DP_ERROR_IO_ERROR;
809                 TRACE_ERROR("check ipc sock:%d", client->channel);
810         } else if (field_count > 0) {
811                 // get fields from database.
812                 int *ids = (int *)calloc(field_count, sizeof(int));
813                 if (ids == NULL) {
814                         TRACE_ERROR("failed to allocate the clients");
815                         errorcode = DP_ERROR_OUT_OF_MEMORY;
816                 } else {
817                         // getting ids of clients
818                         int i = 0;
819                         int rows_count = dp_db_get_cond_ids(client->dbhandle,
820                                         DP_TABLE_HEADERS, DP_DB_COL_ROW_ID, DP_DB_COL_ID,
821                                         ipc_info->id, ids, field_count, &errorcode);
822                         for (; i < rows_count; i++) {
823                                 char *string = NULL;
824                                 unsigned length = 0;
825                                 if (dp_db_get_cond_string(client->dbhandle,
826                                                         DP_TABLE_HEADERS, DP_DB_COL_ROW_ID,
827                                                         ids[i], DP_DB_COL_HEADER_FIELD,
828                                                         (unsigned char **)&string, &length, &errorcode) < 0) {
829                                         TRACE_ERROR("failed to get %s", dp_print_property(ipc_info->property));
830                                         errorcode = DP_ERROR_NO_DATA;
831                                 }
832                                 result = __dp_request_feedback_string(client->channel,
833                                                 ipc_info, string, length, errorcode);
834                                 free(string);
835                                 if (result == DP_ERROR_IO_ERROR) {
836                                         errorcode = DP_ERROR_IO_ERROR;
837                                         TRACE_ERROR("check ipc sock:%d", client->channel);
838                                 }
839                         }
840                 }
841                 if (ids)
842                         free(ids);
843         }
844         return errorcode;
845 }
846
847
848 /* 1. read field string
849  * 2. response with extra size
850  * 3. send string.
851  */
852 static int __dp_request_get_http_header_info(dp_client_fmt *client, dp_ipc_fmt *ipc_info)
853 {
854         char *header_field = NULL;
855         char *string = NULL;
856         unsigned length = 0;
857         int errorcode = __dp_request_read_string(client->channel, ipc_info, &header_field);
858         if (errorcode == DP_ERROR_NONE && header_field != NULL) {
859                 if (dp_db_get_header_value(client->dbhandle, ipc_info->id,
860                                         header_field, (unsigned char **)&string, &length, &errorcode) < 0)
861                         errorcode = DP_ERROR_NO_DATA;
862         } else if (header_field == NULL) {
863                 errorcode = DP_ERROR_INVALID_PARAMETER;
864         }
865
866         if (__dp_request_feedback_string(client->channel,
867                                 ipc_info, string, length, errorcode) == DP_ERROR_IO_ERROR) {
868                 errorcode = DP_ERROR_IO_ERROR;
869                 TRACE_ERROR("check ipc sock:%d", client->channel);
870         }
871
872         free(header_field);
873         free(string);
874
875         return errorcode;
876 }
877
878 static int __dp_request_get_info(dp_client_fmt *client, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
879 {
880         int errorcode = DP_ERROR_NONE;
881
882         switch (ipc_info->property) {
883         case DP_PROP_URL:
884         case DP_PROP_PROXY:
885         case DP_PROP_DESTINATION:
886         case DP_PROP_FILENAME:
887         case DP_PROP_SAVED_PATH:
888         case DP_PROP_TEMP_SAVED_PATH:
889         case DP_PROP_MIME_TYPE:
890         case DP_PROP_CONTENT_NAME:
891         case DP_PROP_ETAG:
892         case DP_PROP_NOTIFICATION_SUBJECT:
893         case DP_PROP_NOTIFICATION_DESCRIPTION:
894         case DP_PROP_NOTIFICATION_RAW:
895                 errorcode = __dp_request_get_info_string(client, ipc_info);
896                 break;
897         case DP_PROP_RECEIVED_SIZE:
898         case DP_PROP_STATE_CALLBACK:
899         case DP_PROP_PROGRESS_CALLBACK:
900         case DP_PROP_NETWORK_TYPE:
901         case DP_PROP_STATE:
902         case DP_PROP_ERROR:
903         case DP_PROP_TOTAL_FILE_SIZE:
904         case DP_PROP_NOTIFICATION_TYPE:
905                 errorcode = __dp_request_get_info_int_from_request(client, ipc_info, requestp);
906                 break;
907         case DP_PROP_NETWORK_BONDING:
908         case DP_PROP_AUTO_DOWNLOAD:
909         case DP_PROP_HTTP_STATUS:
910                 errorcode = __dp_request_get_info_int_from_db(client, ipc_info);
911                 break;
912         case DP_PROP_HTTP_HEADERS:
913                 errorcode = __dp_request_get_http_headers_info(client, ipc_info);
914                 break;
915         case DP_PROP_HTTP_HEADER:
916                 errorcode = __dp_request_get_http_header_info(client, ipc_info);
917                 break;
918         default:
919                 errorcode = DP_ERROR_INVALID_PARAMETER;
920                 break;
921         }
922
923         if (errorcode != DP_ERROR_NONE)
924                 TRACE_ERROR("failed to get %s, error:%s",
925                                 dp_print_property(ipc_info->property), dp_print_errorcode(errorcode));
926
927         return errorcode;
928 }
929
930 static int __dp_request_set_info(dp_client_slots_fmt *slot, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
931 {
932         if (slot == NULL) {
933                 TRACE_ERROR("check slot memory");
934                 return DP_ERROR_INVALID_PARAMETER;
935         }
936         dp_client_fmt *client = &slot->client;
937         if (client == NULL || ipc_info == NULL) {
938                 TRACE_ERROR("check client or ipc info.");
939                 return DP_ERROR_INVALID_PARAMETER;
940         }
941
942         int errorcode = DP_ERROR_NONE;
943
944         // if completed or downloading, invalid state.
945         int download_state = DP_STATE_NONE;
946         if (requestp != NULL) {
947                 download_state = requestp->state;
948         } else {
949                 if (dp_db_get_property_int(client->dbhandle, ipc_info->id, DP_TABLE_LOGGING, DP_DB_COL_STATE, &download_state, &errorcode) < 0) {
950                         TRACE_ERROR("failed to get %s", dp_print_property(ipc_info->property));
951                         errorcode = DP_ERROR_ID_NOT_FOUND;
952                         // feedback
953                         if (dp_ipc_query(client->channel, ipc_info->id, DP_SEC_SET,
954                                                 ipc_info->property, errorcode, 0) < 0) {
955                                 TRACE_ERROR("check ipc sock:%d", client->channel);
956                         }
957                         return errorcode;
958                 }
959         }
960         // should the state be checked ?
961         TRACE_DEBUG("state:%s set property:%s", dp_print_state(download_state), dp_print_property(ipc_info->property));
962
963         switch (ipc_info->property) {
964         case DP_PROP_URL:
965                 {
966                         char *recv_str = NULL;
967                         errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
968                         if (errorcode == DP_ERROR_NONE) {
969                                 if (recv_str == NULL) {
970                                         errorcode = DP_ERROR_INVALID_PARAMETER;
971                                 } else {
972                                         // write to database here
973                                         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) {
974                                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
975                                                 errorcode = DP_ERROR_DISK_BUSY;
976                                         }
977                                         free(recv_str);
978                                 }
979                         }
980                         break;
981                 }
982         case DP_PROP_PROXY:
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                                         // write to database here
991                                         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)
992                                                 TRACE_ERROR("failed to set %s errorcode:%s", dp_print_property(ipc_info->property), dp_print_errorcode(errorcode));
993                                         free(recv_str);
994                                 }
995                         }
996                         break;
997                 }
998         case DP_PROP_DESTINATION:
999                 {
1000                         char *recv_str = NULL;
1001                         errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
1002                         if (errorcode == DP_ERROR_NONE) {
1003                                 if (recv_str == NULL) {
1004                                         errorcode = DP_ERROR_INVALID_PARAMETER;
1005                                 } else {
1006                                         // check here destination is available
1007                                         errorcode = dp_is_valid_dir(slot->credential, recv_str);
1008                                         if (errorcode == DP_ERROR_NONE &&
1009                                                 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) {
1010                                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1011                                                 errorcode = DP_ERROR_DISK_BUSY;
1012                                         }
1013                                         free(recv_str);
1014                                 }
1015                         }
1016                         break;
1017                 }
1018         case DP_PROP_TEMP_SAVED_PATH:
1019                 {
1020                         char *recv_str = NULL;
1021                         errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
1022                         if (errorcode == DP_ERROR_NONE) {
1023                                 if (recv_str == NULL) {
1024                                         errorcode = DP_ERROR_INVALID_PARAMETER;
1025                                 } else {
1026                                         errorcode = dp_is_valid_dir(slot->credential, recv_str);
1027                                         if (errorcode == DP_ERROR_NONE &&
1028                                                 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) {
1029                                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1030                                                 errorcode = DP_ERROR_DISK_BUSY;
1031                                         }
1032                                         free(recv_str);
1033                                 }
1034                         }
1035                         break;
1036                 }
1037         case DP_PROP_FILENAME:
1038                 {
1039                         char *recv_str = NULL;
1040                         errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
1041                         if (errorcode == DP_ERROR_NONE) {
1042                                 if (recv_str == NULL) {
1043                                         errorcode = DP_ERROR_INVALID_PARAMETER;
1044                                 } else {
1045                                         // write to database here
1046                                         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) {
1047                                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1048                                                 errorcode = DP_ERROR_DISK_BUSY;
1049                                         }
1050                                         free(recv_str);
1051                                 }
1052                         }
1053                         break;
1054                 }
1055         case DP_PROP_STATE_CALLBACK:
1056                 {
1057                         // check state here
1058                         // DP_ERROR_INVALID_STATE if downloading or finished
1059                         // update database here
1060                         if (requestp != NULL)
1061                                 requestp->state_cb = 1;
1062
1063                         int enable_cb = 1;
1064                         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) {
1065                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1066                                 errorcode = DP_ERROR_DISK_BUSY;
1067                         }
1068                         break;
1069                 }
1070         case DP_PROP_PROGRESS_CALLBACK:
1071                 {
1072                         // check state here
1073                         // DP_ERROR_INVALID_STATE if downloading or finished
1074                         // update database here
1075                         if (requestp != NULL)
1076                                 requestp->progress_cb = 1;
1077
1078                         int enable_cb = 1;
1079                         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) {
1080                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1081                                 errorcode = DP_ERROR_DISK_BUSY;
1082                         }
1083                         break;
1084                 }
1085         case DP_PROP_AUTO_DOWNLOAD:
1086                 {
1087                         // update autodownload property as 1 in database
1088                         int enable_cb = 1;
1089                         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) {
1090                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1091                                 errorcode = DP_ERROR_DISK_BUSY;
1092                         }
1093                         break;
1094                 }
1095         case DP_PROP_NETWORK_TYPE:
1096                 {
1097                         int recv_int = -1;
1098                         errorcode = __dp_request_read_int(client->channel, ipc_info, &recv_int);
1099                         if (recv_int <= DP_NETWORK_OFF ||
1100                                         recv_int > DP_NETWORK_ALL) {
1101                                 errorcode = DP_ERROR_INVALID_PARAMETER;
1102                         } else {
1103                                 // update in database
1104                                 if (requestp != NULL) {
1105                                         if (requestp->state == DP_STATE_QUEUED) {
1106                                                 dp_queue_manager_clear_queue(requestp);
1107                                         } else {
1108                                                 requestp->network_type = recv_int;
1109                                                 if (requestp->state == DP_STATE_CONNECTING ||
1110                                                                 requestp->state == DP_STATE_DOWNLOADING) {
1111                                                         // pause & push queue
1112                                                         if (dp_pause_agent_download_without_update(requestp->agent_id) < 0) {
1113                                                                 TRACE_ERROR("failed to pause download(%d) id:%d", requestp->agent_id, ipc_info->id);
1114                                                         } else {
1115                                                                 requestp->state = DP_STATE_PAUSED;
1116                                                                 requestp->error = DP_ERROR_NONE;
1117                                                                 if (dp_queue_manager_push_queue(slot, requestp) < 0) {
1118                                                                         if (dp_db_update_logging(client->dbhandle, ipc_info->id, DP_STATE_FAILED, DP_ERROR_QUEUE_FULL, &errorcode) < 0)
1119                                                                                 TRACE_ERROR("update log sock:%d download-id:%d", client->channel, ipc_info->id);
1120                                                                         requestp->state = DP_STATE_FAILED;
1121                                                                         requestp->error = DP_ERROR_QUEUE_FULL;
1122                                                                         errorcode = DP_ERROR_QUEUE_FULL;
1123                                                                 }
1124                                                         }
1125                                                 }
1126                                         }
1127                                 }
1128                                 int enable_cb = recv_int;
1129                                 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) {
1130                                         TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1131                                         errorcode = DP_ERROR_DISK_BUSY;
1132                                 }
1133                         }
1134                         break;
1135                 }
1136         case DP_PROP_NETWORK_BONDING:
1137                 {
1138                         int recv_int = -1;
1139                         errorcode = __dp_request_read_int(client->channel, ipc_info, &recv_int);
1140                         if (errorcode == DP_ERROR_NONE) {
1141                                 if (requestp != NULL && requestp->network_type != DP_NETWORK_ALL) {
1142                                         errorcode =  DP_ERROR_INVALID_NETWORK_TYPE;
1143                                         TRACE_ERROR("[ERROR] wrong network type");
1144                                 } 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) {
1145                                         TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1146                                         errorcode = DP_ERROR_DISK_BUSY;
1147                                 }
1148                         }
1149                         break;
1150                 }
1151         case DP_PROP_NOTIFICATION_TYPE:
1152                 {
1153                         int recv_int = -1;
1154                         errorcode = __dp_request_read_int(client->channel, ipc_info, &recv_int);
1155                         if (recv_int == DP_NOTIFICATION_TYPE_NONE ||
1156                                         recv_int == DP_NOTIFICATION_TYPE_COMPLETE_ONLY ||
1157                                         recv_int == DP_NOTIFICATION_TYPE_ALL) {
1158                                 // check state request->state == DP_STATE_COMPLETED
1159                                 // DP_ERROR_INVALID_STATE
1160                                 // update notificatio type in database
1161                                 int noti_type = recv_int;
1162                                 if (requestp != NULL) {
1163                                         if (recv_int < requestp->noti_type) {
1164                                                 // if already notification, unregister from notification bar.
1165                                                 if (recv_int == DP_NOTIFICATION_TYPE_NONE) {
1166                                                         if (dp_notification_manager_clear_notification(slot, requestp, DP_NOTIFICATION) < 0)
1167                                                                 TRACE_ERROR("failed to clear notification %s", dp_print_property(ipc_info->property));
1168                                                 }
1169                                                 if (dp_notification_manager_clear_notification(slot, requestp, DP_NOTIFICATION_ONGOING) < 0)
1170                                                         TRACE_ERROR("failed to clear ongoing %s", dp_print_property(ipc_info->property));
1171                                         }
1172                                         requestp->noti_type = recv_int;
1173                                 }
1174                                 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) {
1175                                         TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1176                                         errorcode = DP_ERROR_DISK_BUSY;
1177                                 }
1178                         } else {
1179                                 errorcode = DP_ERROR_INVALID_PARAMETER;
1180                         }
1181                         break;
1182                 }
1183         case DP_PROP_NOTIFICATION_SUBJECT:
1184                 {
1185                         char *recv_str = NULL;
1186                         errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
1187                         if (errorcode == DP_ERROR_NONE) {
1188                                 if (recv_str == NULL) {
1189                                         errorcode = DP_ERROR_INVALID_PARAMETER;
1190                                 } else {
1191                                         // write to database here
1192                                         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) {
1193                                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1194                                                 errorcode = DP_ERROR_DISK_BUSY;
1195                                         }
1196                                         free(recv_str);
1197                                 }
1198                         }
1199                         break;
1200                 }
1201         case DP_PROP_NOTIFICATION_DESCRIPTION:
1202                 {
1203                         char *recv_str = NULL;
1204                         errorcode = __dp_request_read_string(client->channel, ipc_info, &recv_str);
1205                         if (errorcode == DP_ERROR_NONE) {
1206                                 if (recv_str == NULL) {
1207                                         errorcode = DP_ERROR_INVALID_PARAMETER;
1208                                 } else {
1209                                         // write to database here
1210                                         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) {
1211                                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1212                                                 errorcode = DP_ERROR_DISK_BUSY;
1213                                         }
1214                                         free(recv_str);
1215                                 }
1216                         }
1217                         break;
1218                 }
1219         case DP_PROP_NOTIFICATION_RAW: // bundle_type(db column) + bundle_binary
1220                 {
1221                         int bundle_type = -1;
1222                         errorcode = __dp_request_read_int(client->channel, ipc_info, &bundle_type);
1223                         TRACE_DEBUG("read %s type:%d", dp_print_property(ipc_info->property), bundle_type);
1224                         char *raw_column = NULL;
1225                         if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_ONGOING)
1226                                 raw_column = DP_DB_COL_NOTI_RAW_ONGOING;
1227                         else if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_COMPLETE)
1228                                 raw_column = DP_DB_COL_NOTI_RAW_COMPLETE;
1229                         else if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_FAILED)
1230                                 raw_column = DP_DB_COL_NOTI_RAW_FAIL;
1231                         else
1232                                 errorcode = DP_ERROR_INVALID_PARAMETER;
1233                         // feedback
1234                         if (dp_ipc_query(client->channel, ipc_info->id, DP_SEC_SET,
1235                                                 ipc_info->property, errorcode, 0) < 0) {
1236                                 TRACE_ERROR("check ipc sock:%d", client->channel);
1237                                 errorcode = DP_ERROR_IO_ERROR;
1238                         }
1239                         if (errorcode == DP_ERROR_NONE) {
1240                                 dp_ipc_fmt *raw_info = dp_ipc_get_fmt(client->channel);
1241                                 if (raw_info == NULL || raw_info->section != ipc_info->section ||
1242                                                 raw_info->property != ipc_info->property ||
1243                                                 (raw_info->id != ipc_info->id)) {
1244                                         TRACE_ERROR("there is a confusion waiting raw binary in %s section", dp_print_property(ipc_info->property));
1245                                         errorcode = DP_ERROR_IO_ERROR;
1246                                 }
1247                                 if (raw_info != NULL && raw_info->size > 0 && raw_info->size < SIZE_MAX) {
1248                                         unsigned char *recv_raws = (unsigned char *)calloc(raw_info->size, sizeof(unsigned char));
1249                                         if (recv_raws == NULL) {
1250                                                 TRACE_ERROR("sock:%d check memory length:%zd", client->channel, raw_info->size);
1251                                                 errorcode = DP_ERROR_OUT_OF_MEMORY;
1252                                         } else {
1253                                                 if (dp_ipc_read(client->channel, recv_raws, raw_info->size, __FUNCTION__) <= 0) {
1254                                                         TRACE_ERROR("sock:%d check ipc length:%zd", client->channel, raw_info->size);
1255                                                         errorcode = DP_ERROR_IO_ERROR;
1256                                                 } else {
1257                                                         TRACE_DEBUG("sock:%d length:%zd raws", client->channel, raw_info->size);
1258                                                         // save to database
1259                                                         if (dp_db_replace_property(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, raw_column, (void *)recv_raws, raw_info->size, 3, &errorcode) < 0) {
1260                                                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1261                                                                 errorcode = DP_ERROR_DISK_BUSY;
1262                                                         }
1263                                                 }
1264                                                 free(recv_raws);
1265                                         }
1266                                 } else {
1267                                         errorcode = DP_ERROR_IO_ERROR;
1268                                 }
1269                                 free(raw_info);
1270                         }
1271                         break;
1272                 }
1273         case DP_PROP_HTTP_HEADER: //  a request can have one or more fields, a fields can have only one value.
1274                 {
1275                         char *header_field = NULL;
1276                         char *header_value = NULL;
1277                         // 1. read field string
1278                         // 2. response after checking sql status
1279                         // 3. read query IPC for checking IPC
1280                         // 4. read value string
1281                         // 5. response
1282                         errorcode = __dp_request_read_string(client->channel, ipc_info, &header_field);
1283                         if (errorcode == DP_ERROR_NONE && header_field != NULL) {
1284                                 // check sql
1285                                 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);
1286                                 if (check_field < 0) {
1287                                         errorcode = DP_ERROR_DISK_BUSY;
1288                                 } else {
1289                                         errorcode = DP_ERROR_NONE;
1290                                         // feedback
1291                                         if (dp_ipc_query(client->channel, ipc_info->id, ipc_info->section,
1292                                                                 ipc_info->property, errorcode, 0) < 0) {
1293                                                 TRACE_ERROR("check ipc sock:%d", client->channel);
1294                                                 errorcode = DP_ERROR_IO_ERROR;
1295                                         } else {
1296                                                 dp_ipc_fmt *header_ipc = dp_ipc_get_fmt(client->channel);
1297                                                 if (header_ipc == NULL || header_ipc->section != ipc_info->section ||
1298                                                                 header_ipc->property != ipc_info->property ||
1299                                                                 (header_ipc->id != ipc_info->id)) {
1300                                                         TRACE_ERROR("there is a confusion during waiting http string in %s section", dp_print_property(ipc_info->property));
1301                                                         errorcode = DP_ERROR_IO_ERROR;
1302                                                 } else {
1303                                                         errorcode = __dp_request_read_string(client->channel, header_ipc, &header_value);
1304                                                         if (errorcode == DP_ERROR_NONE && header_value != NULL) {
1305                                                                 if (check_field == 0) { // insert
1306                                                                         if (dp_db_new_header(client->dbhandle, ipc_info->id, header_field, header_value, &errorcode) < 0) {
1307                                                                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1308                                                                                 errorcode = DP_ERROR_DISK_BUSY;
1309                                                                         }
1310                                                                 } else { // update
1311                                                                         if (dp_db_update_header(client->dbhandle, ipc_info->id, header_field, header_value, &errorcode) < 0) {
1312                                                                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1313                                                                                 errorcode = DP_ERROR_DISK_BUSY;
1314                                                                         }
1315                                                                 }
1316                                                         } else {
1317                                                                 if (errorcode != DP_ERROR_NONE)
1318                                                                         TRACE_ERROR("failed to set %s, error:%s", dp_print_property(ipc_info->property), dp_print_errorcode(errorcode));
1319                                                                 if (header_value == NULL) {
1320                                                                         TRACE_ERROR("failed to set %s, do you want to run as unset?", dp_print_property(ipc_info->property));
1321                                                                         errorcode = DP_ERROR_INVALID_PARAMETER;
1322                                                                 }
1323                                                         }
1324                                                 }
1325                                                 free(header_ipc);
1326                                         }
1327                                 }
1328                         } else {
1329                                 if (errorcode != DP_ERROR_NONE)
1330                                         TRACE_ERROR("failed to set %s, error:%s", dp_print_property(ipc_info->property), dp_print_errorcode(errorcode));
1331                                 if (header_field == NULL) {
1332                                         TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1333                                         errorcode = DP_ERROR_INVALID_PARAMETER;
1334                                 }
1335                         }
1336                         free(header_field);
1337                         free(header_value);
1338                         break;
1339                 }
1340         case DP_PROP_VERIFY_HOST:
1341         {
1342                 int recv_int = -1;
1343                 errorcode = __dp_request_read_int(client->channel, ipc_info, &recv_int);
1344                 if (errorcode == DP_ERROR_NONE) {
1345                         if (requestp != NULL)
1346                                 requestp->disable_verify_host = recv_int ? 0 : 1;
1347                 }
1348                 break;
1349         }
1350         default:
1351                 errorcode = DP_ERROR_INVALID_PARAMETER;
1352                 break;
1353         }
1354         // feedback
1355         if (dp_ipc_query(client->channel, ipc_info->id, DP_SEC_SET,
1356                                 ipc_info->property, errorcode, 0) < 0)
1357                 TRACE_ERROR("check ipc sock:%d", client->channel);
1358         return errorcode;
1359 }
1360
1361 static int __dp_request_unset_info(dp_client_fmt *client, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
1362 {
1363         if (client == NULL || ipc_info == NULL) {
1364                 TRACE_ERROR("check client or ipc info.");
1365                 return DP_ERROR_INVALID_PARAMETER;
1366         }
1367
1368         int errorcode = DP_ERROR_NONE;
1369
1370         switch (ipc_info->property) {
1371         case DP_PROP_URL:
1372                 // it would be run like cancel operation
1373                 if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_URL, &errorcode) < 0)
1374                         TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1375                 break;
1376         case DP_PROP_PROXY:
1377                 if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_PROXY, &errorcode) < 0)
1378                         TRACE_ERROR("failed to unset %s errorcode:%s", dp_print_property(ipc_info->property), dp_print_errorcode(errorcode));
1379                 break;
1380         case DP_PROP_DESTINATION:
1381                 // if downloading, change destination to da_agent
1382                 if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_DESTINATION, &errorcode) < 0)
1383                         TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1384                 break;
1385         case DP_PROP_FILENAME:
1386                 if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_REQUEST, DP_DB_COL_FILENAME, &errorcode) < 0)
1387                         TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1388                 break;
1389         case DP_PROP_STATE_CALLBACK:
1390                 {
1391                         if (requestp != NULL)
1392                                 requestp->state_cb = 0;
1393
1394                         int enable_cb = 0;
1395                         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) {
1396                                 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1397                                 errorcode = DP_ERROR_DISK_BUSY;
1398                         }
1399                         break;
1400                 }
1401         case DP_PROP_PROGRESS_CALLBACK:
1402                 {
1403                         if (requestp != NULL)
1404                                 requestp->progress_cb = 0;
1405
1406                         int enable_cb = 0;
1407                         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) {
1408                                 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1409                                 errorcode = DP_ERROR_DISK_BUSY;
1410                         }
1411                         break;
1412                 }
1413         case DP_PROP_AUTO_DOWNLOAD:
1414                 {
1415                         // update autodownload property as 0 in database
1416                         int enable_cb = 0;
1417                         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) {
1418                                 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1419                                 errorcode = DP_ERROR_DISK_BUSY;
1420                         }
1421                         break;
1422                 }
1423         case DP_PROP_NETWORK_TYPE:
1424                 {
1425                         // check state here
1426                         // update database here
1427                         if (requestp != NULL)
1428                                 requestp->network_type = DP_NETWORK_OFF;
1429
1430                         int enable_cb = DP_NETWORK_OFF;
1431                         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) {
1432                                 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1433                                 errorcode = DP_ERROR_DISK_BUSY;
1434                         }
1435                         break;
1436                 }
1437         case DP_PROP_NOTIFICATION_TYPE:
1438                 {
1439                         int noti_type = DP_NOTIFICATION_TYPE_NONE;
1440                         if (requestp != NULL)
1441                                 requestp->noti_type = noti_type;
1442
1443                         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) {
1444                                 TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1445                                 errorcode = DP_ERROR_DISK_BUSY;
1446                         }
1447                         break;
1448                 }
1449         case DP_PROP_NOTIFICATION_SUBJECT:
1450                 {
1451                         if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, DP_DB_COL_NOTI_SUBJECT, &errorcode) < 0)
1452                                 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1453                         break;
1454                 }
1455         case DP_PROP_NOTIFICATION_DESCRIPTION:
1456                 {
1457                         if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, DP_DB_COL_NOTI_DESCRIPTION, &errorcode) < 0)
1458                                 TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1459                         break;
1460                 }
1461         case DP_PROP_NOTIFICATION_RAW:
1462                 {
1463                         int bundle_type = -1;
1464                         errorcode = __dp_request_read_int(client->channel, ipc_info, &bundle_type);
1465                         TRACE_DEBUG("read %s type:%d", dp_print_property(ipc_info->property), bundle_type);
1466                         char *raw_column = NULL;
1467                         if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_ONGOING)
1468                                 raw_column = DP_DB_COL_NOTI_RAW_ONGOING;
1469                         else if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_COMPLETE)
1470                                 raw_column = DP_DB_COL_NOTI_RAW_COMPLETE;
1471                         else if (bundle_type == DP_NOTIFICATION_BUNDLE_TYPE_FAILED)
1472                                 raw_column = DP_DB_COL_NOTI_RAW_FAIL;
1473                         if (raw_column != NULL) {
1474                                 if (dp_db_unset_property_string(client->dbhandle, ipc_info->id, DP_TABLE_NOTIFICATION, raw_column, &errorcode) < 0)
1475                                         TRACE_ERROR("failed to unset %s", dp_print_property(ipc_info->property));
1476                         } else {
1477                                 TRACE_ERROR("invalid param set: %s type:%d", dp_print_property(ipc_info->property), bundle_type);
1478                                 errorcode = DP_ERROR_INVALID_PARAMETER;
1479                         }
1480                         break;
1481                 }
1482         case DP_PROP_HTTP_HEADER: // unset value by field
1483                 {
1484                         char *header_field = NULL;
1485                         errorcode = __dp_request_read_string(client->channel, ipc_info, &header_field);
1486                         if (errorcode == DP_ERROR_NONE && header_field != NULL) {
1487                                 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);
1488                                 if (is_present < 0)
1489                                         errorcode = DP_ERROR_DISK_BUSY;
1490                                 else if (is_present == 0)
1491                                         errorcode = DP_ERROR_FIELD_NOT_FOUND;
1492                                 else if (dp_db_cond_delete(client->dbhandle, ipc_info->id, DP_TABLE_HEADERS, DP_DB_COL_HEADER_FIELD, header_field, 2, &errorcode) < 0) {
1493                                         TRACE_ERROR("failed to unset %s for %s", dp_print_property(ipc_info->property), header_field);
1494                                         errorcode = DP_ERROR_DISK_BUSY;
1495                                 }
1496                         } else {
1497                                 if (errorcode != DP_ERROR_NONE)
1498                                         TRACE_ERROR("failed to set %s, error:%s", dp_print_property(ipc_info->property), dp_print_errorcode(errorcode));
1499                                 if (header_field == NULL) {
1500                                         TRACE_ERROR("failed to set %s", dp_print_property(ipc_info->property));
1501                                         errorcode = DP_ERROR_INVALID_PARAMETER;
1502                                 }
1503                         }
1504                         free(header_field);
1505                         break;
1506                 }
1507         default:
1508                 errorcode = DP_ERROR_INVALID_PARAMETER;
1509                 break;
1510         }
1511         // feedback
1512         if (dp_ipc_query(client->channel, ipc_info->id, DP_SEC_UNSET,
1513                                 ipc_info->property, errorcode, 0) < 0) {
1514                 TRACE_ERROR("check ipc sock:%d", client->channel);
1515         }
1516         return errorcode;
1517 }
1518
1519 static int __dp_call_cancel_agent(dp_request_fmt *request)
1520 {
1521         int ret = -1;
1522         if (request != NULL) {
1523                 if (request->agent_id >= 0) {
1524                         TRACE_INFO("cancel download(%d) id: %d state:%s", request->agent_id,
1525                                         request->id, dp_print_state(request->state));
1526                         if (dp_cancel_agent_download_without_update(request->agent_id) == 0)
1527                                 ret = 0;
1528                 } else {
1529                         TRACE_ERROR("invalid agent-id:%d id:%d", request->agent_id,     request->id);
1530                 }
1531         }
1532         return ret;
1533 }
1534
1535 static int __dp_request_controls(dp_client_slots_fmt *slot, dp_ipc_fmt *ipc_info, dp_request_fmt *requestp)
1536 {
1537         if (slot == NULL) {
1538                 TRACE_ERROR("check slot memory");
1539                 return DP_ERROR_INVALID_PARAMETER;
1540         }
1541         dp_client_fmt *client = &slot->client;
1542         if (client == NULL || ipc_info == NULL) {
1543                 TRACE_ERROR("check client or ipc info.");
1544                 return DP_ERROR_INVALID_PARAMETER;
1545         }
1546
1547         int errorcode = DP_ERROR_NONE;
1548
1549         if (ipc_info->property == DP_PROP_CREATE) {
1550                 // check packets again
1551                 if (ipc_info->size != 0 || ipc_info->id != -1)
1552                         errorcode = DP_ERROR_IO_ERROR;
1553                 else
1554                         errorcode = __dp_request_create(client, ipc_info);
1555         } else {
1556
1557                 // get now state.
1558                 int download_state = DP_STATE_NONE;
1559                 if (requestp != NULL) {
1560                         download_state = requestp->state;
1561                 } else {
1562                         if (dp_db_get_property_int(client->dbhandle, ipc_info->id, DP_TABLE_LOGGING, DP_DB_COL_STATE, &download_state, &errorcode) < 0) {
1563                                 TRACE_ERROR("failed to get %s", dp_print_property(ipc_info->property));
1564                                 errorcode = DP_ERROR_ID_NOT_FOUND;
1565                                 // feedback
1566                                 if (dp_ipc_query(client->channel, ipc_info->id, DP_SEC_SET,
1567                                                         ipc_info->property, errorcode, 0) < 0) {
1568                                         TRACE_ERROR("check ipc sock:%d", client->channel);
1569                                 }
1570                                 return errorcode;
1571                         }
1572                 }
1573                 TRACE_DEBUG("id:%d state:%s set property:%s", ipc_info->id, dp_print_state(download_state), dp_print_property(ipc_info->property));
1574
1575                 if (ipc_info->property == DP_PROP_START) {
1576
1577                         if (download_state == DP_STATE_COMPLETED ||
1578                                         download_state == DP_STATE_DOWNLOADING) {
1579                                 errorcode = DP_ERROR_INVALID_STATE;
1580                         } else {
1581
1582                                 if (requestp == NULL) { // load from databse
1583                                         // check state
1584                                         // load and add new request to client->requests.
1585                                 }
1586                                 if (requestp == NULL) {
1587                                         TRACE_ERROR("failed to load id:%d from database sock:%d", ipc_info->id, client->channel);
1588                                         errorcode = DP_ERROR_DISK_BUSY;
1589                                 }
1590                                 if (errorcode == DP_ERROR_NONE) {
1591                                         // update database
1592                                         if (dp_db_update_logging(client->dbhandle, ipc_info->id, DP_STATE_QUEUED, DP_ERROR_NONE, &errorcode) < 0) {
1593                                                 TRACE_ERROR("update log sock:%d download-id:%d", client->channel, ipc_info->id);
1594                                                 errorcode = DP_ERROR_DISK_BUSY;
1595                                         } else {
1596                                                 requestp->state = DP_STATE_QUEUED;
1597                                                 requestp->error = DP_ERROR_NONE;
1598                                                 // if it's the first request for this client-> push a request at the head of queue.
1599                                                 // check count queued, connecting.downloading in requets of client
1600                                                 // else push at the tail of queue.
1601                                                 // push to queue
1602                                                 if (dp_queue_manager_push_queue(slot, requestp) < 0) {
1603                                                         if (dp_db_update_logging(client->dbhandle, ipc_info->id, DP_STATE_FAILED, DP_ERROR_QUEUE_FULL, &errorcode) < 0)
1604                                                                 TRACE_ERROR("update log sock:%d download-id:%d", client->channel, ipc_info->id);
1605                                                         requestp->state = DP_STATE_FAILED;
1606                                                         requestp->error = DP_ERROR_QUEUE_FULL;
1607                                                         errorcode = DP_ERROR_QUEUE_FULL;
1608                                                 } else { // push ok
1609                                                         dp_queue_manager_wake_up();
1610                                                         // notification
1611                                                         if (requestp->noti_type == DP_NOTIFICATION_TYPE_ALL) {
1612                                                                 if (dp_notification_manager_push_notification(slot, requestp, DP_NOTIFICATION_ONGOING) < 0)
1613                                                                         TRACE_ERROR("failed to register notification for id:%d", ipc_info->id);
1614                                                         }
1615                                                 }
1616                                         }
1617                                 }
1618                                 TRACE_DEBUG("id:%d check start error:%s", ipc_info->id, dp_print_errorcode(errorcode));
1619                         }
1620
1621                 } else if (ipc_info->property == DP_PROP_PAUSE) {
1622
1623                         if (download_state > DP_STATE_DOWNLOADING) {
1624                                 errorcode = DP_ERROR_INVALID_STATE;
1625                         } else { // change state regardless it's on memory or not.
1626                                 if (dp_db_update_logging(client->dbhandle, ipc_info->id, DP_STATE_PAUSED, DP_ERROR_NONE, &errorcode) < 0) {
1627                                         TRACE_ERROR("update log sock:%d download-id:%d", client->channel, ipc_info->id);
1628                                         errorcode = DP_ERROR_DISK_BUSY;
1629                                 } else {
1630                                         // call da_pause API
1631                                         if (requestp != NULL) {
1632                                                 // pop from queue. if state is queued.
1633                                                 if (requestp->state == DP_STATE_QUEUED) {
1634                                                         dp_queue_manager_clear_queue(requestp);
1635                                                 } else if (requestp->state == DP_STATE_CONNECTING ||
1636                                                                 requestp->state == DP_STATE_DOWNLOADING) {
1637                                                         if (dp_pause_agent_download_without_update(requestp->agent_id) < 0)
1638                                                                 TRACE_ERROR("failed to pause download(%d) id:%d", requestp->agent_id, ipc_info->id);
1639                                                 }
1640                                                 requestp->state = DP_STATE_PAUSED;
1641                                                 requestp->error = DP_ERROR_NONE;
1642                                         }
1643                                 }
1644                         }
1645
1646                 } else if (ipc_info->property == DP_PROP_CANCEL) {
1647
1648                         if (download_state > DP_STATE_COMPLETED) {
1649                                 errorcode = DP_ERROR_INVALID_STATE;
1650                         } else { // change state regardless it's on memory or not.
1651                                 if (dp_db_update_logging(client->dbhandle, ipc_info->id, DP_STATE_CANCELED, DP_ERROR_NONE, &errorcode) < 0) {
1652                                         TRACE_ERROR("update log sock:%d download-id:%d", client->channel, ipc_info->id);
1653                                         errorcode = DP_ERROR_DISK_BUSY;
1654                                 } else {
1655                                         // call da_cancel API
1656                                         if (requestp != NULL) {
1657                                                 // pop from queue. if state is queued.
1658                                                 if (requestp->state == DP_STATE_QUEUED) {
1659                                                         dp_queue_manager_clear_queue(requestp);
1660                                                 } else if (requestp->state == DP_STATE_CONNECTING ||
1661                                                                 requestp->state == DP_STATE_DOWNLOADING ||
1662                                                                 requestp->state == DP_STATE_PAUSED) {
1663                                                         if (__dp_call_cancel_agent(requestp) < 0)
1664                                                                 TRACE_ERROR("failed to cancel download(%d) id:%d", requestp->agent_id, ipc_info->id);
1665                                                 }
1666                                                 requestp->agent_id = -1;
1667                                                 requestp->state = DP_STATE_CANCELED;
1668                                                 requestp->error = DP_ERROR_NONE;
1669                                                 if (requestp->noti_type == DP_NOTIFICATION_TYPE_COMPLETE_ONLY ||
1670                                                                 requestp->noti_type == DP_NOTIFICATION_TYPE_ALL) {
1671                                                         if (dp_notification_manager_push_notification(slot, requestp, DP_NOTIFICATION) < 0)
1672                                                                 TRACE_ERROR("failed to register notification for id:%d", ipc_info->id);
1673                                                 }
1674                                         }
1675                                 }
1676                         }
1677
1678                 } else if (ipc_info->property == DP_PROP_DESTROY) {
1679
1680                         // check state
1681                         // pop from queue. if state is queued.
1682                         if (requestp != NULL) {
1683                                 if (requestp->state == DP_STATE_QUEUED)
1684                                         dp_queue_manager_clear_queue(requestp);
1685                                 if (requestp->state == DP_STATE_CONNECTING ||
1686                                                 requestp->state == DP_STATE_DOWNLOADING) {
1687                                         // update state property database;
1688                                         if (dp_db_update_logging(client->dbhandle, ipc_info->id, DP_STATE_CANCELED, DP_ERROR_NONE, &errorcode) < 0) {
1689                                                 TRACE_ERROR("update log sock:%d download-id:%d", client->channel, ipc_info->id);
1690                                         } else {
1691                                                 // call da_cancel API
1692                                                 if (__dp_call_cancel_agent(requestp) < 0)
1693                                                         TRACE_ERROR("failed to cancel download(%d) id:%d", requestp->agent_id, ipc_info->id);
1694                                         }
1695                                         requestp->state = DP_STATE_CANCELED;
1696                                 }
1697                                 if (requestp->state == DP_STATE_QUEUED || requestp->state == DP_STATE_CANCELED) {
1698
1699                                         if (requestp->noti_type == DP_NOTIFICATION_TYPE_COMPLETE_ONLY ||
1700                                                         requestp->noti_type == DP_NOTIFICATION_TYPE_ALL) {
1701                                                 if (dp_notification_manager_push_notification(slot, requestp, DP_NOTIFICATION) < 0)
1702                                                         TRACE_ERROR("failed to register notification for id:%d", ipc_info->id);
1703                                         }
1704                                 }
1705                                 requestp->agent_id = -1;
1706                         }
1707                         errorcode = dp_request_destroy(client, ipc_info, requestp);
1708
1709                 } else {
1710                         errorcode = DP_ERROR_INVALID_PARAMETER;
1711                         TRACE_ERROR("invalid param - id:%d set property:%s", ipc_info->id, dp_print_property(ipc_info->property));
1712                 }
1713         }
1714
1715         // feedback
1716         if (dp_ipc_query(client->channel, ipc_info->id, DP_SEC_CONTROL,
1717                                 ipc_info->property, errorcode, 0) < 0) {
1718                 TRACE_ERROR("check ipc sock:%d", client->channel);
1719         }
1720
1721         // workaround. client still request the feedback by cancelation
1722         if (ipc_info->property == DP_PROP_CANCEL ||
1723                         ipc_info->property == DP_PROP_PAUSE) {
1724                 if (requestp != NULL && requestp->state_cb == 1) {
1725                         if (slot->client.notify < 0 ||
1726                                         dp_notify_feedback(slot->client.notify, slot, ipc_info->id, requestp->state, errorcode, 0) < 0) {
1727                                 TRACE_ERROR("id:%d disable state callback by IO_ERROR", ipc_info->id);
1728                                 requestp->state_cb = 0;
1729                         }
1730                 }
1731         }
1732
1733         return errorcode;
1734 }
1735
1736 static int __dp_client_requests(dp_client_slots_fmt *slot, dp_ipc_fmt *ipc_info)
1737 {
1738         if (slot == NULL) {
1739                 TRACE_ERROR("check slot memory");
1740                 return DP_ERROR_INVALID_PARAMETER;
1741         }
1742         dp_client_fmt *client = &slot->client;
1743         if (client == NULL || ipc_info == NULL) {
1744                 TRACE_ERROR("check client or ipc info.");
1745                 return DP_ERROR_INVALID_PARAMETER;
1746         }
1747
1748         int errorcode = DP_ERROR_NONE;
1749
1750         // check id except create command  /////////// DP_ERROR_ID_NOT_FOUND
1751         dp_request_fmt *requestp = NULL;
1752         if (ipc_info->section != DP_SEC_CONTROL ||
1753                         ipc_info->property != DP_PROP_CREATE) {
1754                 // check on requests
1755                 int i = 0;
1756                 requestp = client->requests;
1757                 errorcode = DP_ERROR_ID_NOT_FOUND;
1758                 for (; i < MAX_DOWNLOAD_HANDLE; i++) {
1759                         if (requestp == NULL)
1760                                 break;
1761                         //TRACE_DEBUG("link %d info: id:%d access-time:%d", i, requestp->id, requestp->access_time);
1762                         if (requestp->id == ipc_info->id) {
1763                                 errorcode = DP_ERROR_NONE;
1764                                 break;
1765                         }
1766                         requestp = requestp->next;
1767                 }
1768                 if (errorcode == DP_ERROR_ID_NOT_FOUND) {
1769                         // check in database
1770                         if (dp_db_check_duplicated_int(client->dbhandle, DP_TABLE_LOGGING, DP_DB_COL_ID, ipc_info->id, &errorcode) > 0) {
1771                                 //TRACE_DEBUG("found %d from database", ipc_info->id);
1772                                 errorcode = DP_ERROR_NONE;
1773                         }
1774                 }
1775         }
1776
1777         if (errorcode != DP_ERROR_NONE) { // prechecking
1778                 TRACE_ERROR("precheck errorcode:%s sock:%d id:%d section:%s property:%s",
1779                                 dp_print_errorcode(errorcode),
1780                                 client->channel, ipc_info->id,
1781                                 dp_print_section(ipc_info->section),
1782                                 dp_print_property(ipc_info->property));
1783
1784                 // clear followed packets.
1785                 if (ipc_info->size > 0) {
1786                         char garbage[ipc_info->size];
1787                         if (read(client->channel, &garbage, ipc_info->size) == 0) {
1788                                 TRACE_ERROR("sock:%d closed peer", client->channel);
1789                                 errorcode = DP_ERROR_IO_ERROR;
1790                         }
1791                 }
1792
1793                 if (dp_ipc_query(client->channel, ipc_info->id,
1794                                         ipc_info->section, ipc_info->property, errorcode, 0) < 0) {
1795                         TRACE_ERROR("check ipc sock:%d", client->channel);
1796                         errorcode = DP_ERROR_IO_ERROR;
1797                 }
1798                 return errorcode;
1799         }
1800
1801         switch (ipc_info->section) {
1802         case DP_SEC_CONTROL:
1803                 errorcode = __dp_request_controls(slot, ipc_info, requestp);
1804                 break;
1805         case DP_SEC_GET:
1806                 errorcode = __dp_request_get_info(client, ipc_info, requestp);
1807                 break;
1808         case DP_SEC_SET:
1809                 errorcode = __dp_request_set_info(slot, ipc_info, requestp);
1810                 break;
1811         case DP_SEC_UNSET:
1812                 errorcode = __dp_request_unset_info(client, ipc_info, requestp);
1813                 break;
1814         default:
1815                 errorcode = DP_ERROR_INVALID_PARAMETER;
1816                 break;
1817         }
1818         return errorcode;
1819 }
1820
1821 static void __dp_client_stop_all_requests(dp_client_slots_fmt *slot)
1822 {
1823         unsigned push_count = 0;
1824         int errorcode = DP_ERROR_NONE;
1825         int i = 0;
1826         dp_request_fmt *tailp = slot->client.requests;
1827         for (; tailp != NULL; i++) {
1828                 TRACE_DEBUG("request %d stop id:%d state:%s", i, tailp->id, dp_print_state(tailp->state));
1829                 int state = tailp->state;
1830                 if (state == DP_STATE_CONNECTING) {
1831                         if (dp_cancel_agent_download_without_update(tailp->agent_id) < 0)
1832                                 TRACE_ERROR("failed to cancel download(%d) id:%d", tailp->agent_id, tailp->id);
1833                 } else if (state == DP_STATE_DOWNLOADING) {
1834                         if (dp_pause_agent_download(tailp->agent_id) < 0)
1835                                 TRACE_ERROR("failed to pause download(%d) id:%d", tailp->agent_id, tailp->id);
1836                 }
1837                 if (state == DP_STATE_DOWNLOADING || state == DP_STATE_CONNECTING) {
1838                         tailp->state = DP_STATE_QUEUED;
1839                         // This is error code for checking the reason when changing ip configuration process
1840                         tailp->error = DP_ERROR_IO_EAGAIN;
1841                         // push to queue now
1842                         // in da callback, check DP_ERROR_IO_EAGAIN, then ignore.
1843                         if (dp_db_update_logging(slot->client.dbhandle, tailp->id, tailp->state, DP_ERROR_NONE, &errorcode) < 0)
1844                                 TRACE_ERROR("update log sock:%d download-id:%d", slot->client.channel, tailp->id);
1845                         if (dp_queue_manager_push_queue(slot, tailp) < 0) {
1846                                 TRACE_ERROR("Fail to push queueg sock:%d download-id:%d", slot->client.channel, tailp->id);
1847                                 // FIXME later : error case. How can handle this item?
1848                         } else {
1849                                 push_count++;
1850                         }
1851                 }
1852                 tailp = tailp->next;
1853         }
1854         if (push_count > 0)
1855                 dp_queue_manager_wake_up();
1856 }
1857
1858 void dp_client_sig_handler(int signo)
1859 {
1860         TRACE_INFO("thread:%lu signal:%d", pthread_self(), signo);
1861 }
1862
1863 void *dp_client_request_thread(void *arg)
1864 {
1865         dp_client_slots_fmt *slot = (dp_client_slots_fmt *)arg;
1866         if (slot == NULL) {
1867                 TRACE_ERROR("slot null, can not launch the thread for client");
1868                 return 0;
1869         }
1870
1871         // wait detaching thread
1872         CLIENT_MUTEX_LOCK(&slot->mutex);
1873
1874         TRACE_INFO("slot %p thread:%lu", slot, slot->thread);
1875
1876         struct sigaction act = {{0},};
1877         sigset_t newmask;
1878         sigemptyset(&newmask);
1879         sigaddset(&newmask, SIGUSR1);
1880         act.sa_handler = dp_client_sig_handler;
1881         sigaction(SIGUSR1, &act, NULL);
1882
1883         fd_set imask, emask;
1884         int errorcode = DP_ERROR_NONE;
1885         dp_client_fmt *client = &slot->client;
1886         int client_sock = client->channel;
1887         struct timeval timeout; // for timeout of select
1888
1889         CLIENT_MUTEX_UNLOCK(&slot->mutex);
1890
1891         pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
1892
1893         while (slot != NULL && client_sock >= 0 &&
1894                         client_sock == slot->client.channel) {
1895                 memset(&timeout, 0x00, sizeof(struct timeval));
1896                 timeout.tv_sec = DP_CARE_CLIENT_REQUEST_INTERVAL;
1897                 FD_ZERO(&imask);
1898                 FD_ZERO(&emask);
1899                 FD_SET(client_sock, &imask);
1900                 FD_SET(client_sock, &emask);
1901                 if (select(client_sock + 1, &imask, 0, &emask, &timeout) < 0) {
1902                         if (slot != NULL && slot->client.channel >= 0) {
1903                                 TRACE_INFO("broadcast by client-manager");
1904                                 CLIENT_MUTEX_LOCK(&slot->mutex);
1905                                 // check all requests
1906                                 __dp_client_stop_all_requests(slot);
1907                                 CLIENT_MUTEX_UNLOCK(&slot->mutex);
1908                                 continue;
1909                         } else {
1910                                 TRACE_ERROR("interrupted by client-manager sock:%d", client_sock);
1911                                 break;
1912                         }
1913                 }
1914                 if (FD_ISSET(client_sock, &imask) > 0) {
1915
1916                         pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
1917                         CLIENT_MUTEX_LOCK(&slot->mutex);
1918
1919                         client->access_time = (int)time(NULL);
1920
1921                         errorcode = DP_ERROR_NONE;
1922
1923                         // read ipc_fmt first. below func will deal followed packets
1924                         dp_ipc_fmt *ipc_info = dp_ipc_get_fmt(client_sock);
1925                         if (ipc_info == NULL) {
1926                                 TRACE_ERROR("sock:%d maybe closed", client_sock);
1927                                 errorcode = DP_ERROR_IO_ERROR;
1928                         } else {
1929                                 TRACE_INFO("sock:%d id:%d section:%s property:%s errorcode:%s size:%zd",
1930                                                 client_sock, ipc_info->id,
1931                                                 dp_print_section(ipc_info->section),
1932                                                 dp_print_property(ipc_info->property),
1933                                                 dp_print_errorcode(ipc_info->errorcode),
1934                                                 ipc_info->size);
1935
1936                                 if (client->dbhandle == 0 || dp_db_check_connection(client->dbhandle) < 0) {
1937                                         if (dp_db_open_client(&client->dbhandle, slot->pkgname, &errorcode) < 0) {
1938                                                 TRACE_ERROR("failed to open database for sock:%d errorcode:%s",
1939                                                                 client_sock, dp_print_errorcode(errorcode));
1940                                                 if (dp_ipc_query(client->channel, ipc_info->id,
1941                                                                         ipc_info->section, ipc_info->property, errorcode, 0) < 0) {
1942                                                         TRACE_ERROR("check ipc sock:%d", client->channel);
1943                                                 }
1944                                         }
1945                                 }
1946
1947                                 if (errorcode == DP_ERROR_NONE) {
1948                                         // JOB
1949                                         errorcode = __dp_client_requests(slot, ipc_info);
1950                                 }
1951
1952                         }
1953                         free(ipc_info);
1954
1955                         CLIENT_MUTEX_UNLOCK(&slot->mutex);
1956                         pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
1957
1958                         if (errorcode == DP_ERROR_IO_ERROR ||
1959                                         errorcode == DP_ERROR_OUT_OF_MEMORY ||
1960                                         errorcode == DP_ERROR_INVALID_PARAMETER) {
1961                                 TRACE_ERROR("disconnect client errorcode:%s sock:%d",
1962                                                 dp_print_errorcode(errorcode), client_sock);
1963                                 break;
1964                         }
1965
1966                 } else if (FD_ISSET(client_sock, &emask) > 0) {
1967                         TRACE_ERROR("[EXCEPTION]");
1968                         break;
1969                 } else {
1970                         TRACE_ERROR("[TIMEOUT]");
1971                         if (CLIENT_MUTEX_TRYLOCK(&slot->mutex) == 0) {
1972                                 // 1. clear zombie requests. clean requests finished. paused or ready for long time
1973                                 dp_client_clear_requests(slot);
1974
1975                                 // 2. if no requests, exit by itself.
1976                                 if (slot->client.requests == NULL) {
1977                                         TRACE_DEBUG("no requests");
1978                                         CLIENT_MUTEX_UNLOCK(&slot->mutex);
1979                                         break;
1980                                 }
1981                                 CLIENT_MUTEX_UNLOCK(&slot->mutex);
1982                         }
1983                 }
1984         } // while (slot != NULL && client_sock >= 0 && ....)
1985
1986         _dp_client_clear_stale_db(client);
1987
1988         if (client_sock >= 0 && client_sock < FD_SETSIZE) {
1989                 FD_CLR(client_sock, &imask);
1990                 FD_CLR(client_sock, &emask);
1991         }
1992
1993         // if no requests, clear slot after disconnect with client.
1994         CLIENT_MUTEX_LOCK(&slot->mutex);
1995
1996         TRACE_INFO("thread done slot %p thread:%lu", slot, slot->thread);
1997
1998         slot->thread = 0;// to prevent kill thread twice
1999
2000         int i = 0;
2001         dp_request_fmt *tailp = slot->client.requests;
2002         dp_request_fmt *prevp = NULL;
2003         for (; tailp != NULL; i++) {
2004                 if (tailp->state != DP_STATE_QUEUED &&
2005                                 tailp->state != DP_STATE_CONNECTING &&
2006                                 tailp->state != DP_STATE_DOWNLOADING) {
2007                         dp_request_fmt *removep = tailp;
2008                         if (prevp == NULL) // first request.
2009                                 client->requests = tailp->next;
2010                         else
2011                                 prevp->next = tailp->next;
2012                         tailp = tailp->next;
2013                         TRACE_DEBUG("request %d remove: id:%d state:%s", i, removep->id, dp_print_state(removep->state));
2014                         dp_request_free(removep);
2015                         continue;
2016                 }
2017                 TRACE_DEBUG("request %d remain: id:%d state:%s", i, tailp->id, dp_print_state(tailp->state));
2018                 prevp = tailp;
2019                 tailp = tailp->next;
2020
2021         }
2022         // if no requests after clear finished requests.
2023         if (slot->client.requests == NULL) {
2024                 dp_client_slot_free(slot);
2025         } else {
2026                 if (slot->client.notify >= 0)
2027                         close(slot->client.notify);
2028                 dp_notify_deinit(slot->credential.pid);
2029                 slot->client.notify = -1;
2030                 if (slot->client.channel > 0)
2031                         close(slot->client.channel);
2032                 slot->client.channel = -1;
2033         }
2034         TRACE_INFO("thread done slot %p thread:%lu sock:%d", slot, slot->thread, client_sock);
2035         CLIENT_MUTEX_UNLOCK(&slot->mutex);
2036         return 0;
2037 }
2038