diff options
Diffstat (limited to 'provider/download-provider-main.c')
-rwxr-xr-x | provider/download-provider-main.c | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/provider/download-provider-main.c b/provider/download-provider-main.c new file mode 100755 index 0000000..6e71cb5 --- /dev/null +++ b/provider/download-provider-main.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <glib.h> +#include <glib-object.h> +#include <pthread.h> +#include <locale.h> +#include <libintl.h> +#include <systemd/sd-daemon.h> + +#include "vconf.h" + +#include "download-provider-config.h" +#include "download-provider-log.h" +#include "download-provider-socket.h" +#include "download-provider-pthread.h" +#include "download-provider-slots.h" +#include "download-provider-db.h" +#include "download-provider-network.h" +#include "download-provider-queue.h" +#include "download-provider-notification.h" +#include "download-provider-da-interface.h" + +// declare functions +int dp_lock_pid(char *path); +void *dp_thread_requests_manager(void *arg); +static pthread_t g_dp_thread_queue_manager_pid = 0; + +// declare global variables +// need for libsoup, decided the life-time by mainloop. +GMainLoop *g_main_loop_handle = 0; + +void dp_terminate(int signo) +{ + TRACE_DEBUG("Received SIGTERM:%d", signo); + if (g_main_loop_is_running(g_main_loop_handle)) + g_main_loop_quit(g_main_loop_handle); +} + +static gboolean __dp_idle_start_service(void *data) +{ + // declare all resources + pthread_t thread_pid; + pthread_attr_t thread_attr; + + // initialize + if (pthread_attr_init(&thread_attr) != 0) { + TRACE_STRERROR("failed to init pthread attr"); + dp_terminate(SIGTERM); + return FALSE; + } + if (pthread_attr_setdetachstate(&thread_attr, + PTHREAD_CREATE_DETACHED) != 0) { + TRACE_STRERROR("failed to set detach option"); + dp_terminate(SIGTERM); + return FALSE; + } + + // create thread for managing QUEUEs + if (pthread_create + (&g_dp_thread_queue_manager_pid, NULL, dp_thread_queue_manager, + data) != 0) { + TRACE_STRERROR + ("failed to create pthread for run_manage_download_server"); + dp_terminate(SIGTERM); + } + + // start service, accept url-download ( client package ) + if (pthread_create + (&thread_pid, &thread_attr, dp_thread_requests_manager, + data) != 0) { + TRACE_STRERROR + ("failed to create pthread for run_manage_download_server"); + dp_terminate(SIGTERM); + } + return FALSE; +} + +void __set_locale() +{ + char *str = NULL; + str = vconf_get_str(VCONFKEY_LANGSET); + if (str != NULL) { + setlocale(LC_ALL, str); + bindtextdomain(PKG_NAME, LOCALE_DIR); + textdomain(PKG_NAME); + } + free(str); +} +void __lang_changed_cb(keynode_t *key, void* data) +{ + __set_locale(); +} + +int main(int argc, char **argv) +{ + dp_privates *privates = NULL; + int lock_fd = -1; + + if (chdir("/") < 0) { + TRACE_STRERROR("failed to call setsid or chdir"); + exit(EXIT_FAILURE); + } + +#if 0 + // close all console I/O + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); +#endif + + if (signal(SIGTERM, dp_terminate) == SIG_ERR) { + TRACE_ERROR("failed to register signal callback"); + exit(EXIT_FAILURE); + } + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { + TRACE_ERROR("failed to register signal callback"); + exit(EXIT_FAILURE); + } + if (signal(SIGINT, dp_terminate) == SIG_ERR) { + TRACE_ERROR("failed to register signal callback"); + exit(EXIT_FAILURE); + } + // write IPC_FD_PATH. and lock + if ((lock_fd = dp_lock_pid(DP_LOCK_PID)) < 0) { + TRACE_ERROR + ("It need to check download-provider is already alive"); + TRACE_ERROR("Or fail to create pid file in (%s)", + DP_LOCK_PID); + exit(EXIT_FAILURE); + } + + g_type_init(); + + // locale + __set_locale(); + if (vconf_notify_key_changed(VCONFKEY_LANGSET, __lang_changed_cb, NULL) != 0) + TRACE_ERROR("Fail to set language changed vconf callback"); + + privates = (dp_privates *) calloc(1, sizeof(dp_privates)); + if (!privates) { + TRACE_ERROR("[CRITICAL] failed to alloc for private info"); + goto DOWNLOAD_EXIT; + } + privates->groups = dp_client_group_slots_new(DP_MAX_GROUP); + if (privates->groups == NULL) { + TRACE_ERROR("[CRITICAL] failed to alloc for groups"); + goto DOWNLOAD_EXIT; + } + privates->requests = dp_request_slots_new(DP_MAX_REQUEST); + if (privates->requests == NULL) { + TRACE_ERROR("[CRITICAL] failed to alloc for requests"); + goto DOWNLOAD_EXIT; + } + + // ready socket ( listen ) + privates->listen_fd = dp_accept_socket_new(); + if (privates->listen_fd < 0) { + TRACE_ERROR("[CRITICAL] failed to bind SOCKET"); + goto DOWNLOAD_EXIT; + } + + dp_db_open(); + + // convert to request type, insert all to privates->requests + // timeout of request thread will start these jobs by queue thread + // load all list from (queue table) + if (dp_db_crashed_list(privates->requests, DP_MAX_REQUEST) > 0) { + int i = 0; + for (i = 0; i < DP_MAX_REQUEST; i++) { + if (!privates->requests[i].request) + continue; + dp_request *request = privates->requests[i].request; + TRACE_DEBUG + ("ID [%d] state[%d]", request->id, request->state); + + // load to memory, Can be started automatically. + if (request->state == DP_STATE_DOWNLOADING || + request->state == DP_STATE_CONNECTING) { + request->state = DP_STATE_QUEUED; + if (dp_db_set_column + (request->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE, + DP_DB_COL_TYPE_INT, &request->state) < 0) { + TRACE_ERROR("[CHECK SQL]"); + } + } + + if (request->state == DP_STATE_QUEUED) { + int auto_download = dp_db_get_int_column(request->id, + DP_DB_TABLE_REQUEST_INFO, + DP_DB_COL_AUTO_DOWNLOAD); + if (auto_download == 1) { + // auto retry... defaultly, show notification + request->auto_notification = 1; + request->start_time = (int)time(NULL); + continue; + } + // do not retry this request + request->state = DP_STATE_FAILED; + request->error = DP_ERROR_SYSTEM_DOWN; + if (dp_db_set_column + (request->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE, + DP_DB_COL_TYPE_INT, &request->state) < 0) { + TRACE_ERROR("[CHECK SQL]"); + } + if (dp_db_set_column + (request->id, DP_DB_TABLE_LOG, + DP_DB_COL_ERRORCODE, DP_DB_COL_TYPE_INT, + &request->error) < 0) { + TRACE_ERROR("[CHECK SQL]"); + } + } + + // if wanna restart, call continue before this line. + // default. update state/error. move to history. unload memory + // remove from memory + dp_request_free(request); + privates->requests[i].request = NULL; + } + } // query crashed_list + +#if 0 + if (argc != 2 || memcmp(argv[1], "service", 7) != 0) { + // in first launch in booting time, not request. terminate by self + if (dp_get_request_count(privates->requests) <= 0) { + TRACE_DEBUG("First Boot, No Request"); + goto DOWNLOAD_EXIT; + } + } +#endif + + dp_clear_downloadinginfo_notification(); + + if (dp_init_agent() != DP_ERROR_NONE) { + TRACE_ERROR("[CRITICAL] failed to init agent"); + goto DOWNLOAD_EXIT; + } + + privates->connection = 0; + privates->network_status = DP_NETWORK_TYPE_OFF; + if (dp_network_connection_init(privates) < 0) { + TRACE_DEBUG("use instant network check"); + privates->connection = 0; + } + + // libsoup need mainloop. + g_main_loop_handle = g_main_loop_new(NULL, 0); + + g_idle_add(__dp_idle_start_service, privates); + + sd_notify(0, "READY=1"); + + g_main_loop_run(g_main_loop_handle); + +DOWNLOAD_EXIT : + + TRACE_DEBUG("Download-Provider will be terminated."); + if (vconf_ignore_key_changed(VCONFKEY_LANGSET, __lang_changed_cb) != 0) + TRACE_ERROR("Fail to unset language changed vconf callback"); + + dp_deinit_agent(); + + if (privates != NULL) { + + if (privates->connection) + dp_network_connection_destroy(privates->connection); + + if (privates->listen_fd >= 0) + privates->listen_fd = -1; + + if (g_dp_thread_queue_manager_pid > 0 && + pthread_kill(g_dp_thread_queue_manager_pid, 0) != ESRCH) { + //pthread_cancel(g_dp_thread_queue_manager_pid); + //send signal to queue thread + dp_thread_queue_manager_wake_up(); + int status; + pthread_join(g_dp_thread_queue_manager_pid, (void **)&status); + g_dp_thread_queue_manager_pid = 0; + } + dp_request_slots_free(privates->requests, DP_MAX_REQUEST); + privates->requests = NULL; + dp_client_group_slots_free(privates->groups, DP_MAX_GROUP); + privates->groups = NULL; + free(privates); + privates = NULL; + } + dp_db_close(); + + // delete pid file + if (access(DP_LOCK_PID, F_OK) == 0) { + close(lock_fd); + unlink(DP_LOCK_PID); + } + exit(EXIT_SUCCESS); +} |