2 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include <sys/socket.h>
25 #include <sys/types.h>
30 #include <systemd/sd-daemon.h>
31 #include <glib-object.h>
33 #include <cynara-client.h>
34 #include <cynara-client-async.h>
35 #include <cynara-creds-socket.h>
36 #include <cynara-creds-dbus.h>
38 #include <download-provider.h>
39 #include <download-provider-log.h>
40 #include <download-provider-config.h>
41 #include <download-provider-pthread.h>
42 #include <download-provider-smack.h>
43 #include <download-provider-client.h>
44 #include <download-provider-notification.h>
45 #include <download-provider-notification-manager.h>
46 #include <download-provider-utils.h>
47 #include <download-provider-ipc.h>
48 #include <download-provider-notify.h>
49 #include <download-provider-db-defs.h>
50 #include <download-provider-db.h>
51 #include <download-provider-queue-manager.h>
52 #include <download-provider-client-manager.h>
53 #include <download-provider-plugin-download-agent.h>
54 #include <download-provider-network.h>
57 dp_client_slots_fmt *g_dp_client_slots = NULL;
58 static void *g_db_handle = 0;
59 static pthread_mutex_t g_db_mutex = PTHREAD_MUTEX_INITIALIZER;
60 extern pthread_t g_client_manager_tid;
62 void dp_terminate(int signo)
64 TRACE_DEBUG("Received SIGTERM:%d", signo);
67 if (g_client_manager_tid > 0)
68 pthread_kill(g_client_manager_tid, SIGUSR1);
71 void dp_broadcast_signal()
73 TRACE_INFO("broadcast");
74 // announce to all thread for clients
75 // signo 10 : ip changed
76 if (g_dp_client_slots != NULL) {
78 for (; i < DP_MAX_CLIENTS; i++) {
79 if (g_dp_client_slots[i].thread > 0 &&
80 pthread_kill(g_dp_client_slots[i].thread, 0) != ESRCH)
81 pthread_kill(g_dp_client_slots[i].thread, SIGUSR1);
87 char *dp_db_get_client_smack_label(const char *pkgname)
89 char *smack_label = NULL;
91 int errorcode = DP_ERROR_NONE;
93 CLIENT_MUTEX_LOCK(&g_db_mutex);
94 if (dp_db_get_client_property_string(g_db_handle, pkgname, DP_DB_COL_SMACK_LABEL, (unsigned char **)&smack_label, &length, &errorcode) < 0) {
95 TRACE_SECURE_ERROR("failed to get smack label for %s", pkgname);
97 CLIENT_MUTEX_UNLOCK(&g_db_mutex);
102 static int __dp_db_open_client_manager()
104 int errorcode = DP_ERROR_NONE;
105 CLIENT_MUTEX_LOCK(&g_db_mutex);
106 if (g_db_handle == 0 || dp_db_check_connection(g_db_handle) < 0) {
107 if (dp_db_open_client_manager(&g_db_handle, &errorcode) < 0) {
108 TRACE_ERROR("failed to open database errorcode:%d", errorcode);
111 CLIENT_MUTEX_UNLOCK(&g_db_mutex);
115 static void __dp_db_free_client_manager()
117 CLIENT_MUTEX_LOCK(&g_db_mutex);
118 if (g_db_handle != 0) {
119 TRACE_SECURE_DEBUG("TRY to close [%s]", DP_DBFILE_CLIENTS);
120 dp_db_close(g_db_handle);
123 CLIENT_MUTEX_UNLOCK(&g_db_mutex);
126 static int __dp_accept_socket_new()
128 int fd_base, listen_fds = sd_listen_fds(1);
129 TRACE_DEBUG("sd_listen_fds:%d", listen_fds);
131 if(listen_fds > INT_MAX) {
132 TRACE_DEBUG("sd_listen_fds:%d", listen_fds);
136 for (fd_base = 0 ; fd_base < listen_fds; fd_base++) {
137 if (sd_is_socket_unix(fd_base + SD_LISTEN_FDS_START, SOCK_STREAM, 1, IPC_SOCKET, 0) >= 0) {
138 TRACE_INFO("listen systemd socket:%d", fd_base + SD_LISTEN_FDS_START);
139 return fd_base + SD_LISTEN_FDS_START;
145 int dp_client_slot_free(dp_client_slots_fmt *slot)
147 if (slot->client.channel >= 0) {
148 close(slot->client.channel);
149 slot->client.channel = -1;
151 if (slot->client.dbhandle != 0) {
152 dp_db_close(slot->client.dbhandle);
153 slot->client.dbhandle = 0;
156 // remove notify fifo
157 if (slot->client.notify >= 0) {
158 close(slot->client.notify);
159 slot->client.notify = -1;
161 dp_notify_deinit(slot->credential.pid);
163 if (slot->thread != 0)
164 pthread_cancel(slot->thread);
166 if (slot->pkgname != NULL) {
167 TRACE_SECURE_DEBUG("TRY to close [%s]", slot->pkgname);
169 slot->pkgname = NULL;
174 // precondition : all slots are empty
175 static int __dp_manage_client_requests(dp_client_slots_fmt *clients)
177 int errorcode = DP_ERROR_NONE;
181 dp_notification_manager_kill();
182 dp_queue_manager_kill();
184 // get all clients info from clients database.
186 int *ids = (int *)calloc(DP_MAX_CLIENTS, sizeof(int));
188 TRACE_ERROR("failed to allocate the clients");
191 // getting ids of clients
192 int rows_count = dp_db_get_ids(g_db_handle, DP_TABLE_CLIENTS, NULL, ids, NULL, DP_MAX_CLIENTS, DP_DB_COL_ACCESS_TIME, "ASC", &errorcode);
193 for (; i < rows_count; i++) {
194 char *pkgname = NULL;
196 errorcode = DP_ERROR_NONE;
197 if (dp_db_get_property_string(g_db_handle, ids[i], DP_TABLE_CLIENTS, DP_DB_COL_PACKAGE, (unsigned char **)&pkgname, &length, &errorcode) < 0) {
198 TRACE_ERROR("failed to get pkgname for id:%d", ids[i]);
202 if (pkgname != NULL) {
203 if (dp_db_remove_database(pkgname, time(NULL), DP_CARE_CLIENT_INFO_PERIOD * 3600) == 0) { // old database
204 // remove info from client database;
205 if (dp_db_delete(g_db_handle, ids[i], DP_TABLE_CLIENTS, &errorcode) == 0) {
206 TRACE_SECURE_ERROR("clear info for %s", pkgname);
207 // remove database file
209 TRACE_SECURE_INFO("remove database for %s", pkgname);
214 dp_credential credential;
216 if (dp_db_get_property_int(g_db_handle, ids[i], DP_TABLE_CLIENTS, DP_DB_COL_UID, &credential.uid, &errorcode) < 0 ||
217 dp_db_get_property_int(g_db_handle, ids[i], DP_TABLE_CLIENTS, DP_DB_COL_GID, &credential.gid, &errorcode) < 0) {
218 TRACE_SECURE_ERROR("failed to get credential for %s", pkgname);
222 if (dp_mutex_init(&clients[slot_index].mutex, NULL) != 0) {
223 TRACE_SECURE_ERROR("failed to initialize mutex for %s", pkgname);
227 // open database of a clients
228 if (dp_db_open_client_v2(&clients[slot_index].client.dbhandle, pkgname) < 0) {
229 TRACE_SECURE_ERROR("failed to open database for %s", pkgname);
230 // remove this client from clients database
231 if (dp_db_delete(g_db_handle, ids[i], DP_TABLE_CLIENTS, &errorcode) == 0) {
232 TRACE_SECURE_ERROR("clear info for %s", pkgname);
233 // remove database file
234 if (dp_db_remove_database(pkgname, time(NULL), 0) == 0) {
235 TRACE_SECURE_INFO("remove database for %s", pkgname);
237 TRACE_SECURE_ERROR("failed to remove database for %s", pkgname);
244 // get ids if state is QUEUED, CONNECTING or DOWNLOADING with auto_download
245 int *request_ids = (int *)calloc(DP_MAX_REQUEST, sizeof(int));
246 if (request_ids == NULL) {
247 TRACE_SECURE_ERROR("failed to allocate the requests for %s", pkgname);
251 int request_count = dp_db_get_crashed_ids(clients[slot_index].client.dbhandle, DP_TABLE_LOGGING, request_ids, DP_MAX_REQUEST, &errorcode);
252 TRACE_DEBUG("client: %s requests:%d", pkgname, request_count);
254 if (request_count > 0) {
255 clients[slot_index].pkgname = pkgname;
256 clients[slot_index].client.channel = -1;
257 clients[slot_index].client.notify = -1;
258 clients[slot_index].credential.pid = credential.pid;
259 clients[slot_index].credential.uid = credential.uid;
260 clients[slot_index].credential.gid = credential.gid;
261 for (ids_i = 0; ids_i < request_count; ids_i++) {
262 // loading requests from client's database... attach to client.requests
263 dp_request_fmt *request = (dp_request_fmt *) calloc(1, sizeof(dp_request_fmt));
264 if (request == NULL) {
265 TRACE_ERROR("check memory download-id:%d", request_ids[ids_i]);
268 request->id = request_ids[ids_i];
269 request->agent_id = -1;
270 request->state = DP_STATE_QUEUED;
271 request->error = DP_ERROR_NONE;
272 if (dp_db_get_property_int(clients[slot_index].client.dbhandle, request->id, DP_TABLE_REQUEST, DP_DB_COL_NETWORK_TYPE, &request->network_type, &errorcode) < 0) {
273 TRACE_ERROR("failed to get network type for id:%d", request->id);
274 request->network_type = DP_NETWORK_WIFI;
276 request->access_time = (int)time(NULL);
277 request->state_cb = 0;
278 request->progress_cb = 0;
279 if (dp_db_get_property_int(clients[slot_index].client.dbhandle, request->id, DP_TABLE_LOGGING, DP_DB_COL_STARTCOUNT, &request->startcount, &errorcode) < 0) {
280 TRACE_ERROR("failed to get start count for id:%d", request->id);
281 request->startcount = 0;
283 request->startcount++;
284 request->noti_type = DP_NOTIFICATION_TYPE_NONE;
285 if (dp_db_get_property_int(clients[slot_index].client.dbhandle, request->id, DP_TABLE_NOTIFICATION, DP_DB_COL_NOTI_TYPE, &request->noti_type, &errorcode) < 0) {
286 TRACE_ERROR("failed to get notification type for id:%d", request->id);
288 if (request->noti_type == DP_NOTIFICATION_TYPE_NONE) {
289 TRACE_INFO("enable notification for id:%d", request->id);
290 request->noti_type = DP_NOTIFICATION_TYPE_COMPLETE_ONLY;
292 request->progress_lasttime = 0;
293 request->received_size = 0; // ?
294 request->content_type = DP_CONTENT_UNKNOWN;
295 request->file_size = 0; // ?
296 if (dp_db_get_property_int(clients[slot_index].client.dbhandle, request->id, DP_TABLE_NOTIFICATION, DP_DB_COL_NOTI_PRIV_ID, &request->noti_priv_id, &errorcode) < 0) {
297 TRACE_ERROR("failed to get notification noti_priv_id for id:%d", request->id);
298 request->noti_priv_id = -1;
301 dp_request_create(&clients[slot_index].client, request);
303 if (dp_db_update_logging(clients[slot_index].client.dbhandle, request->id, DP_STATE_QUEUED, DP_ERROR_NONE, &errorcode) < 0) {
304 TRACE_ERROR("update log download-id:%d", request->id);
305 errorcode = DP_ERROR_DISK_BUSY;
308 if (dp_queue_manager_push_queue((void *)&clients[slot_index], (void *)request) < 0) {
309 errorcode = DP_ERROR_QUEUE_FULL;
310 TRACE_INFO("failed to push to queue for id:%d", request->id);
311 dp_request_destroy(&(clients[slot_index].client), NULL, request);
315 if (dp_notification_manager_push_notification((void *)&clients[slot_index], (void *)request, DP_NOTIFICATION_ONGOING) < 0) {
316 TRACE_ERROR("failed to register notification for id:%d", request->id);
330 TRACE_DEBUG("slot_index:%d", slot_index);
332 dp_queue_manager_wake_up();
336 static int __dp_client_run(int clientfd, dp_client_slots_fmt *slot,
337 dp_credential credential)
339 int errorcode = DP_ERROR_NONE;
341 slot->client.notify = dp_notify_init(credential.pid);
342 if (slot->client.notify < 0) {
343 TRACE_ERROR("failed to open fifo slot:%d", clientfd);
344 errorcode = DP_ERROR_IO_ERROR;
346 char *smack_label = NULL;
347 if (dp_smack_is_mounted() == 1) {
348 smack_label = dp_smack_get_label_from_socket(clientfd);
349 if (smack_label == NULL) {
350 TRACE_SECURE_ERROR("smack_new_label_from_socket");
353 // save client info to database
354 CLIENT_MUTEX_LOCK(&g_db_mutex);
355 if (dp_db_update_client_info(g_db_handle,
356 slot->pkgname, smack_label,
357 credential.uid, credential.gid, &errorcode) < 0) {
358 TRACE_ERROR("check error:%s", dp_print_errorcode(errorcode));
360 CLIENT_MUTEX_UNLOCK(&g_db_mutex);
363 if (errorcode == DP_ERROR_NONE) {
365 // create a thread for client
366 if (pthread_create(&slot->thread, NULL,
367 dp_client_request_thread, (void *)slot) != 0) {
368 TRACE_ERROR("failed to create client thread slot:%d", clientfd);
369 errorcode = DP_ERROR_OUT_OF_MEMORY;
371 dp_client_slot_free(slot); // => make pkgname as NULL
373 pthread_detach(slot->thread);
374 TRACE_SECURE_INFO("accept client[%s] pid:%d sock:%d",
375 slot->pkgname, credential.pid, clientfd);
376 slot->client.channel = clientfd;
377 slot->credential.pid = credential.pid;
378 slot->credential.uid = credential.uid;
379 slot->credential.gid = credential.gid;
386 static int __dp_client_new(int clientfd, dp_client_slots_fmt *clients,
387 dp_credential credential)
389 // search in clients list.
390 // if same pkgname. update it.
391 // search same pkg or pid in clients
392 int errorcode = DP_ERROR_NONE;
395 char *pkgname = NULL;
397 char buffer[256] = { 0, };
399 // getting the package name via pid
400 if (aul_app_get_appid_bypid_for_uid(credential.pid, buffer, sizeof(buffer), credential.uid) != AUL_R_OK)
401 TRACE_ERROR("[CRITICAL] aul_app_get_appid_bypid_for_uid");
403 pkgname = strdup(buffer);
405 //// TEST CODE ... to allow sample client ( no package name ).
406 if (pkgname == NULL) {
407 //pkgname = dp_strdup("unknown_app");
408 char *temp_pkgname = (char *)calloc(41, sizeof(char));
409 if (temp_pkgname == NULL ||
410 snprintf(temp_pkgname, 41,"unknown_app_%d", credential.pid) < 0) {
411 pkgname = dp_strdup("unknown_app");
413 pkgname = temp_pkgname;
417 if (pkgname == NULL) {
418 TRACE_ERROR("[CRITICAL] app_manager_get_app_id");
419 return DP_ERROR_INVALID_PARAMETER;
422 if ((pkg_len = strlen(pkgname)) <= 0) {
423 TRACE_ERROR("[CRITICAL] pkgname:%s", pkgname);
425 return DP_ERROR_INVALID_PARAMETER;
428 #ifdef SUPPORT_SECURITY_PRIVILEGE_OLD
429 TRACE_DEBUG("SUPPORT_SECURITY_PRIVILEGE_OLD");
430 int result = security_server_check_privilege_by_sockfd(clientfd, SECURITY_PRIVILEGE_INTERNET, "w");
431 if (result != SECURITY_SERVER_API_SUCCESS) {
432 TRACE_ERROR("check privilege permission:%d", result);
433 return DP_ERROR_PERMISSION_DENIED;
438 TRACE_DEBUG("SUPPORT_SECURITY_PRIVILEGE");
439 // Cynara structure init
441 cynara *p_cynara = NULL;
442 cynara_configuration *p_conf = NULL;
443 size_t cache_size = 100;
444 //cynara_configuration conf;
446 if (CYNARA_API_SUCCESS != cynara_configuration_create(&p_conf)) { /* error */}
447 if (CYNARA_API_SUCCESS != cynara_configuration_set_cache_size(p_conf, cache_size)) { /* error */ }
449 ret = cynara_initialize(&p_cynara, NULL);
450 if(ret != CYNARA_API_SUCCESS) { /* error */ }
451 cynara_configuration_destroy(p_conf);
453 // Get client peer credential
455 ret = cynara_creds_socket_get_client(clientfd, CLIENT_METHOD_SMACK, &clientSmack);
456 // In case of D-bus peer credential??
457 // ret = cynara_creds_dbus_get_client(DBusConnection *connection, const char *uniqueName,CLIENT_METHOD_SMACK, &clientSmack);
458 if(ret != CYNARA_API_SUCCESS) { /* error */ }
461 ret = cynara_creds_socket_get_user(clientfd, USER_METHOD_UID, &uid);
462 // In case of D-bus peer credential??
463 // ret = cynara_creds_dbus_get_client(DBusConnection *connection, const char *uniqueName,CLIENT_METHOD_SMACK, &clientSmack);
464 if (ret != CYNARA_API_SUCCESS) { /* error */ }
466 /* Concept of session is service-specific.
467 * Might be empty string if service does not have such concept
469 char *client_session="";
473 ret = cynara_check(p_cynara, clientSmack, client_session, uid, "http://tizen.org/privilege/download");
475 if(ret == CYNARA_API_ACCESS_ALLOWED) {
476 TRACE_DEBUG("CYNARA_API_ACCESS_ALLOWED");
478 TRACE_DEBUG("DP_ERROR_PERMISSION_DENIED");
480 return DP_ERROR_PERMISSION_DENIED;
483 // Cleanup of cynara structure
490 free(client_session);
497 cynara_finish(p_cynara);
501 // EINVAL: empty slot
502 // EBUSY : occupied slot
503 // locked & thread == 0 : downloading without client <= check target
504 // thread == 0, requests == NULL : clear target
506 // Have this client ever been connected before ?
507 for (i = 0; i < DP_MAX_CLIENTS; i++) {
509 int locked = CLIENT_MUTEX_TRYLOCK(&clients[i].mutex);
510 if (locked != 0) { // empty or used by other thread. it would be same client, but it's busy
513 TRACE_DEBUG("locked slot:%d", i);
514 if (locked == 0 && clients[i].thread == 0) { // this slot has run without the client
515 if (clients[i].pkgname != NULL) {
516 // check package name.
517 TRACE_DEBUG("check client[%s] slot:%d", clients[i].pkgname, i);
518 int cname_len = strlen(clients[i].pkgname);
519 if (pkg_len == cname_len &&
520 strncmp(clients[i].pkgname, pkgname, pkg_len) == 0) {
521 TRACE_SECURE_INFO("update client[%s] slot:%d pid:%d sock:%d",
522 pkgname, i, credential.pid, clientfd);
523 if (clients[i].client.channel >= 0 &&
524 clients[i].client.channel != clientfd) {
525 dp_ipc_socket_free(clients[i].client.channel);
526 if (clients[i].client.notify >= 0)
527 close(clients[i].client.notify);
528 dp_notify_deinit(clients[i].credential.pid);
530 errorcode = __dp_client_run(clientfd, &clients[i], credential);
531 CLIENT_MUTEX_UNLOCK(&clients[i].mutex);
532 if (errorcode != DP_ERROR_NONE)
533 dp_mutex_destroy(&clients[i].mutex);
538 if (clients[i].client.requests == NULL) { // clear
539 dp_client_slot_free(&clients[i]);
540 dp_mutex_destroy(&clients[i].mutex);
544 CLIENT_MUTEX_UNLOCK(&clients[i].mutex);
547 TRACE_DEBUG("search empty client[%s] slot:%d", pkgname, i);
549 for (i = 0; i < DP_MAX_CLIENTS; i++) {
550 int locked = CLIENT_MUTEX_TRYLOCK(&clients[i].mutex);
551 if (locked == EINVAL) {
552 if (dp_mutex_init(&clients[i].mutex, NULL) == 0) {
553 CLIENT_MUTEX_LOCK(&clients[i].mutex);
554 TRACE_DEBUG("found empty client[%s] slot:%d", pkgname, i);
555 clients[i].pkgname = pkgname;
556 clients[i].client.dbhandle = 0;
557 clients[i].client.requests = NULL;
558 errorcode = __dp_client_run(clientfd, &clients[i], credential);
559 CLIENT_MUTEX_UNLOCK(&clients[i].mutex);
560 if (errorcode != DP_ERROR_NONE)
561 dp_mutex_destroy(&clients[i].mutex);
566 CLIENT_MUTEX_UNLOCK(&clients[i].mutex);
569 TRACE_SECURE_INFO("busy client[%s] pid:%d sock:%d", pkgname,
570 credential.pid, clientfd);
572 return DP_ERROR_TOO_MANY_DOWNLOADS;
575 void *dp_client_manager(void *arg)
577 fd_set rset, eset, listen_fdset, except_fdset;
578 struct timeval timeout; // for timeout of select
580 struct sockaddr_un clientaddr;
581 dp_credential credential;
583 int errorcode = DP_ERROR_NONE;
584 GMainLoop *event_loop = (GMainLoop *)arg;
586 g_dp_sock = __dp_accept_socket_new();
588 TRACE_ERROR("failed to open listen socket");
589 g_main_loop_quit(event_loop);
593 if (signal(SIGTERM, dp_terminate) == SIG_ERR ||
594 signal(SIGPIPE, SIG_IGN) == SIG_ERR ||
595 signal(SIGINT, dp_terminate) == SIG_ERR) {
596 TRACE_ERROR("failed to register signal callback");
597 g_main_loop_quit(event_loop);
601 dp_notification_clear_ongoings();
604 dp_rebuild_dir(PROVIDER_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
607 dp_rebuild_dir(DATABASE_DIR, S_IRWXU);
609 #ifdef DATABASE_CLIENT_DIR
610 dp_rebuild_dir(DATABASE_CLIENT_DIR, S_IRWXU);
613 dp_rebuild_dir(NOTIFY_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
616 dp_client_slots_fmt *clients =
617 (dp_client_slots_fmt *)calloc(DP_MAX_CLIENTS,
618 sizeof(dp_client_slots_fmt));
619 if (clients == NULL) {
620 TRACE_ERROR("failed to allocate client slots");
621 g_main_loop_quit(event_loop);
624 g_dp_client_slots = clients;
625 for (i = 0; i < DP_MAX_CLIENTS; i++) {
626 dp_mutex_destroy(&clients[i].mutex); // clear mutex init
629 int maxfd = g_dp_sock;
630 FD_ZERO(&listen_fdset);
631 FD_ZERO(&except_fdset);
632 FD_SET(g_dp_sock, &listen_fdset);
633 FD_SET(g_dp_sock, &except_fdset);
635 while (g_dp_sock >= 0) {
639 // initialize timeout structure for calling timeout exactly
640 memset(&timeout, 0x00, sizeof(struct timeval));
641 timeout.tv_sec = DP_CARE_CLIENT_MANAGER_INTERVAL;
649 if (select((maxfd + 1), &rset, 0, &eset, &timeout) < 0) {
650 TRACE_ERROR("interrupted by terminating");
655 TRACE_DEBUG("queue-manager is closed by other thread");
659 if (FD_ISSET(g_dp_sock, &eset) > 0) {
660 TRACE_ERROR("exception of socket");
662 } else if (FD_ISSET(g_dp_sock, &rset) > 0) {
664 // Anyway accept client.
665 clientlen = sizeof(clientaddr);
666 clientfd = accept(g_dp_sock, (struct sockaddr *)&clientaddr,
669 TRACE_ERROR("too many client ? accept failure");
670 // provider need the time of refresh.
671 errorcode = DP_ERROR_DISK_BUSY;
674 // blocking & timeout to prevent the lockup by client.
675 struct timeval tv_timeo = {1, 500000}; // 1.5 sec
676 if (setsockopt(clientfd, SOL_SOCKET, SO_RCVTIMEO, &tv_timeo,
677 sizeof(tv_timeo)) < 0) {
678 TRACE_ERROR("failed to set timeout in blocking socket");
679 errorcode = DP_ERROR_IO_ERROR;
683 memset(&ipc_info, 0x00, sizeof(dp_ipc_fmt));
684 if (read(clientfd, &ipc_info, sizeof(dp_ipc_fmt)) <= 0 ||
685 ipc_info.section == DP_SEC_NONE ||
686 ipc_info.property != DP_PROP_NONE ||
688 ipc_info.size != 0) {
689 TRACE_ERROR("peer terminate ? ignore this connection");
690 errorcode = DP_ERROR_INVALID_PARAMETER;
693 #ifdef SO_PEERCRED // getting the info of client
694 socklen_t cr_len = sizeof(credential);
695 if (getsockopt(clientfd, SOL_SOCKET, SO_PEERCRED,
696 &credential, &cr_len) < 0) {
697 TRACE_ERROR("failed to cred from sock:%d", clientfd);
698 errorcode = DP_ERROR_PERMISSION_DENIED;
700 #else // In case of not supported SO_PEERCRED
701 if (read(clientfd, &credential, sizeof(dp_credential)) <= 0) {
702 TRACE_ERROR("failed to cred from client:%d", clientfd);
703 errorcode = DP_ERROR_PERMISSION_DENIED;
707 if (errorcode == DP_ERROR_NONE) {
708 errorcode = __dp_db_open_client_manager();
711 if (errorcode == DP_ERROR_NONE) {
712 if (ipc_info.section == DP_SEC_INIT) {
715 errorcode = __dp_client_new(clientfd, clients, credential);
718 errorcode = DP_ERROR_INVALID_PARAMETER;
721 if (dp_ipc_query(clientfd, -1, ipc_info.section, DP_PROP_NONE, errorcode, 0) < 0) {
722 TRACE_ERROR("check ipc sock:%d", clientfd);
725 if (errorcode != DP_ERROR_NONE) {
726 TRACE_ERROR("sock:%d id:%d section:%s property:%s errorcode:%s size:%d",
727 clientfd, ipc_info.id,
728 dp_print_section(ipc_info.section),
729 dp_print_property(ipc_info.property),
730 dp_print_errorcode(ipc_info.errorcode),
732 close(clientfd); // ban this client
734 if (errorcode == DP_ERROR_NO_SPACE || errorcode == DP_ERROR_DISK_BUSY) {
735 TRACE_ERROR("provider can't work anymore errorcode:%s", dp_print_errorcode(errorcode));
736 //break; // provider will be terminated after sending errorcode by each thread
741 // take care zombie client, slots
742 unsigned connected_clients = 0;
744 for (; i < DP_MAX_CLIENTS; i++) {
746 int locked = CLIENT_MUTEX_TRYLOCK(&clients[i].mutex);
747 if (locked == EINVAL) { // not initialized
749 } else if (locked == EBUSY) { // already locked
754 if (locked == 0) { // locked
756 // if no client thread, requests should be checked here
757 // if no queued, connecting or downloading, close the slot
758 if (clients[i].pkgname != NULL) {
759 if (clients[i].thread == 0) {
760 dp_client_clear_requests(&clients[i]);
761 if (clients[i].client.requests == NULL) {
762 dp_client_slot_free(&clients[i]);
763 CLIENT_MUTEX_UNLOCK(&clients[i].mutex);
764 dp_mutex_destroy(&clients[i].mutex);
770 CLIENT_MUTEX_UNLOCK(&clients[i].mutex);
773 TRACE_DEBUG("%d clients are active now", connected_clients);
774 // terminating download-provider if no clients.
775 if (connected_clients == 0) {
776 if (__dp_manage_client_requests(clients) <= 0) // if no crashed job
779 dp_queue_manager_wake_up();
780 dp_notification_manager_wake_up();
789 dp_queue_manager_kill();
790 dp_notification_clear_ongoings();
791 dp_notification_manager_kill();
793 __dp_db_free_client_manager();
795 // kill other clients
796 TRACE_DEBUG("try to deallocate the resources for all clients");
797 for (i = 0; i < DP_MAX_CLIENTS; i++) {
798 int locked = CLIENT_MUTEX_TRYLOCK(&clients[i].mutex);
799 if (locked == EBUSY) { // already locked
800 CLIENT_MUTEX_LOCK(&clients[i].mutex);
801 } else if (locked == EINVAL) { // not initialized, empty slot
804 dp_client_slot_free(&clients[i]);
805 CLIENT_MUTEX_UNLOCK(&clients[i].mutex);
806 dp_mutex_destroy(&clients[i].mutex);
809 // free all resources
811 TRACE_INFO("client-manager's working is done");
812 g_main_loop_quit(event_loop);