summaryrefslogtreecommitdiff
path: root/provider
diff options
context:
space:
mode:
Diffstat (limited to 'provider')
-rwxr-xr-xprovider/CMakeLists.txt71
-rwxr-xr-xprovider/download-provider-da-interface.c903
-rwxr-xr-xprovider/download-provider-db.c2352
-rwxr-xr-xprovider/download-provider-main.c311
-rwxr-xr-xprovider/download-provider-network.c397
-rwxr-xr-xprovider/download-provider-notification.c616
-rwxr-xr-xprovider/download-provider-pid.c34
-rwxr-xr-xprovider/download-provider-request.c930
-rwxr-xr-xprovider/download-provider-slots.c174
-rwxr-xr-xprovider/download-provider-socket.c351
-rwxr-xr-xprovider/download-provider-thread-queue.c398
-rwxr-xr-xprovider/download-provider-thread-request.c2158
-rwxr-xr-xprovider/include/download-provider-config.h46
-rwxr-xr-xprovider/include/download-provider-da-interface.h29
-rwxr-xr-xprovider/include/download-provider-db.h243
-rwxr-xr-xprovider/include/download-provider-defs.h94
-rwxr-xr-xprovider/include/download-provider-log.h58
-rwxr-xr-xprovider/include/download-provider-network.h34
-rwxr-xr-xprovider/include/download-provider-notification.h27
-rwxr-xr-xprovider/include/download-provider-pthread.h96
-rwxr-xr-xprovider/include/download-provider-queue.h23
-rwxr-xr-xprovider/include/download-provider-request.h58
-rwxr-xr-xprovider/include/download-provider-slots.h90
-rwxr-xr-xprovider/include/download-provider-socket.h43
-rwxr-xr-xprovider/include/download-provider.h120
25 files changed, 9656 insertions, 0 deletions
diff --git a/provider/CMakeLists.txt b/provider/CMakeLists.txt
new file mode 100755
index 0000000..fef1222
--- /dev/null
+++ b/provider/CMakeLists.txt
@@ -0,0 +1,71 @@
+
+## PROJECT NAME
+PROJECT(${PKG_NAME} C)
+
+IF("${CMAKE_BUILD_TYPE}" STREQUAL "")
+ SET(CMAKE_BUILD_TYPE "Debug")
+ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "")
+MESSAGE("Build type: ${CMAKE_BUILD_TYPE}")
+
+INCLUDE(FindPkgConfig)
+
+pkg_check_modules(dp2_pkgs REQUIRED glib-2.0
+ gobject-2.0
+ sqlite3
+ capi-appfw-app-manager
+ capi-network-connection
+ wifi-direct
+ notification
+ appsvc
+ bundle
+ libsmack
+ libsystemd-daemon
+ libtzplatform-config
+ dlog)
+
+FOREACH(flag ${dp2_pkgs_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+## INCLUDES
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/agent/include)
+
+set(DP2_LINK_LIBRARIES ${GLIB-2_LIBRARIES}
+ ${GOBJECT-2_LIBRARIES}
+ pthread
+ capi-appfw-app-manager
+ )
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -Wall")
+
+IF(DEFINED DATABASE_SCHEMA_FILE)
+ ADD_DEFINITIONS(-DDATABASE_SCHEMA_FILE=\"${DATABASE_SCHEMA_FILE}\")
+ENDIF(DEFINED DATABASE_SCHEMA_FILE)
+
+IF(DEFINED IMAGE_DIR)
+ ADD_DEFINITIONS(-DIMAGE_DIR=\"${IMAGE_DIR}\")
+ENDIF(DEFINED IMAGE_DIR)
+
+IF(DEFINED LOCALE_DIR)
+ ADD_DEFINITIONS(-DPKG_NAME=\"${PKG_NAME}\")
+ ADD_DEFINITIONS(-DLOCALE_DIR=\"${LOCALE_DIR}\")
+ENDIF(DEFINED LOCALE_DIR)
+
+
+ADD_EXECUTABLE(${PROJECT_NAME}
+ ${CMAKE_CURRENT_SOURCE_DIR}/download-provider-pid.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/download-provider-socket.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/download-provider-slots.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/download-provider-network.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/download-provider-db.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/download-provider-request.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/download-provider-da-interface.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/download-provider-thread-request.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/download-provider-thread-queue.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/download-provider-notification.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/download-provider-main.c )
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${dp2_pkgs_LDFLAGS} ${DP2_LINK_LIBRARIES} -ldl)
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${BIN_INSTALL_DIR})
+
+INSTALL(FILES include/download-provider-defs.h DESTINATION ${INCLUDE_INSTALL_DIR}/${PKG_NAME})
diff --git a/provider/download-provider-da-interface.c b/provider/download-provider-da-interface.c
new file mode 100755
index 0000000..87eb375
--- /dev/null
+++ b/provider/download-provider-da-interface.c
@@ -0,0 +1,903 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <string.h>
+#include <dlfcn.h> // dlopen
+
+#include <sys/smack.h>
+#include "download-provider.h"
+#include "download-provider-log.h"
+#include "download-provider-pthread.h"
+#include "download-provider-socket.h"
+#include "download-provider-db.h"
+#include "download-provider-queue.h"
+#include "download-provider-notification.h"
+#include "download-provider-request.h"
+#include "download-provider-network.h"
+#include "download-provider-da-interface.h"
+
+#include "download-agent-defs.h"
+#include "download-agent-interface.h"
+
+#define DP_SDCARD_MNT_POINT "/opt/storage/sdcard"
+
+static void *g_da_handle = NULL;
+static int (*download_agent_init)(da_client_cb_t *) = NULL; // int da_init(da_client_cb_t *da_client_callback);
+static int (*download_agent_deinit)() = NULL; // int da_deinit();
+static int (*download_agent_is_alive)(int) = NULL; // int da_is_valid_download_id(int download_id);
+static int (*download_agent_suspend)(int) = NULL; // int da_suspend_download(int download_id);
+static int (*download_agent_resume)(int) = NULL; // int da_resume_download(int download_id);
+static int (*download_agent_cancel)(int) = NULL; // int da_cancel_download(int download_id);
+static int (*download_agent_start)(const char *, extension_data_t *, int *) = NULL; // int da_start_download_with_extension(const char *url, extension_data_t *ext_data, int *download_id);
+
+
+int dp_is_file_exist(const char *file_path)
+{
+ struct stat file_state;
+ int stat_ret;
+
+ if (file_path == NULL) {
+ TRACE_ERROR("[NULL-CHECK] file path is NULL");
+ return -1;
+ }
+
+ stat_ret = stat(file_path, &file_state);
+
+ if (stat_ret == 0)
+ if (file_state.st_mode & S_IFREG)
+ return 0;
+
+ return -1;
+}
+
+static int __change_error(int err)
+{
+ int ret = DP_ERROR_NONE;
+ switch (err) {
+ case DA_RESULT_OK:
+ ret = DP_ERROR_NONE;
+ break;
+ case DA_ERR_INVALID_ARGUMENT:
+ ret = DP_ERROR_INVALID_PARAMETER;
+ break;
+ case DA_ERR_FAIL_TO_MEMALLOC:
+ ret = DP_ERROR_OUT_OF_MEMORY;
+ break;
+ case DA_ERR_UNREACHABLE_SERVER:
+ ret = DP_ERROR_NETWORK_UNREACHABLE;
+ break;
+ case DA_ERR_HTTP_TIMEOUT:
+ ret = DP_ERROR_CONNECTION_TIMED_OUT;
+ break;
+ case DA_ERR_DISK_FULL:
+ ret = DP_ERROR_NO_SPACE;
+ break;
+ case DA_ERR_INVALID_STATE:
+ ret = DP_ERROR_INVALID_STATE;
+ break;
+ case DA_ERR_NETWORK_FAIL:
+ ret = DP_ERROR_CONNECTION_FAILED;
+ break;
+ case DA_ERR_INVALID_URL:
+ ret = DP_ERROR_INVALID_URL;
+ break;
+ case DA_ERR_INVALID_INSTALL_PATH:
+ ret = DP_ERROR_INVALID_DESTINATION;
+ break;
+ case DA_ERR_ALREADY_MAX_DOWNLOAD:
+ ret = DP_ERROR_TOO_MANY_DOWNLOADS;
+ break;
+ case DA_ERR_FAIL_TO_CREATE_THREAD:
+ case DA_ERR_FAIL_TO_OBTAIN_MUTEX:
+ case DA_ERR_FAIL_TO_ACCESS_FILE:
+ case DA_ERR_FAIL_TO_GET_CONF_VALUE:
+ case DA_ERR_FAIL_TO_ACCESS_STORAGE:
+ default:
+ ret = DP_ERROR_IO_ERROR;
+ break;
+ }
+ return ret;
+}
+
+static void __download_info_cb(user_download_info_t *info, void *user_data)
+{
+ if (!info) {
+ TRACE_ERROR("[NULL-CHECK] Agent info");
+ return ;
+ }
+ dp_request_slots *request_slot = (dp_request_slots *) user_data;
+ if (request_slot == NULL) {
+ TRACE_ERROR("[NULL-CHECK] request req_id:%d", info->download_id);
+ return ;
+ }
+ CLIENT_MUTEX_LOCK(&request_slot->mutex);
+ if (request_slot->request == NULL) {
+ TRACE_ERROR("[NULL-CHECK] request req_id:%d", info->download_id);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+ dp_request *request = request_slot->request;
+ if (request->id < 0 || (request->agent_id != info->download_id)) {
+ TRACE_ERROR("[NULL-CHECK] agent_id : %d req_id %d",
+ request->agent_id, info->download_id);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+
+ int request_id = request->id;
+
+ // update info before sending event
+ if (info->tmp_saved_path != NULL) {
+
+ TRACE_SECURE_DEBUG("[STARTED][%d] [%s]", request_id, info->tmp_saved_path);
+ int conds_count = 6; // id + tmp_saved_path + file_size + content_name + etag
+ int conds_index = 0;
+ db_conds_list_fmt conds_p[conds_count];
+ memset(&conds_p, 0x00, conds_count * sizeof(db_conds_list_fmt));
+
+ conds_p[conds_index].column = DP_DB_COL_TMP_SAVED_PATH;
+ conds_p[conds_index].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[conds_index].value = info->tmp_saved_path;
+ conds_index++;
+ if (info->file_type != NULL) {
+ conds_p[conds_index].column = DP_DB_COL_MIMETYPE;
+ conds_p[conds_index].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[conds_index].value = info->file_type;
+ conds_index++;
+ }
+ if (info->content_name != NULL) {
+ conds_p[conds_index].column = DP_DB_COL_CONTENT_NAME;
+ conds_p[conds_index].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[conds_index].value = info->content_name;
+ conds_index++;
+ }
+ if (info->etag != NULL) {
+ conds_p[conds_index].column = DP_DB_COL_ETAG;
+ conds_p[conds_index].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[conds_index].value = info->etag;
+ conds_index++;
+ }
+ if (info->file_size > 0) {
+ request->file_size = info->file_size;
+ conds_p[conds_index].column = DP_DB_COL_CONTENT_SIZE;
+ conds_p[conds_index].type = DP_DB_COL_TYPE_INT64;
+ conds_p[conds_index].value = &info->file_size;
+ conds_index++;
+ }
+
+ int check_id = dp_db_get_int_column(request_id, DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_ID);
+ if (check_id == request_id) { // update
+ if (dp_db_update_columns(request_id, DP_DB_TABLE_DOWNLOAD_INFO, conds_index, conds_p) < 0) {
+ if (dp_db_is_full_error() == 0) {
+ request->error = DP_ERROR_NO_SPACE;
+ TRACE_ERROR("[SQLITE_FULL][%d]", request_id);
+ if (dp_cancel_agent_download(request->agent_id) < 0)
+ TRACE_ERROR("[fail][%d]cancel_agent", request_id);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+ }
+ } else { // insert
+ conds_p[conds_index].column = DP_DB_COL_ID;
+ conds_p[conds_index].type = DP_DB_COL_TYPE_INT;
+ conds_p[conds_index].value = &request_id;
+ conds_index++;
+ if (dp_db_insert_columns(DP_DB_TABLE_DOWNLOAD_INFO, conds_index, conds_p) < 0) {
+ if (dp_db_is_full_error() == 0) {
+ request->error = DP_ERROR_NO_SPACE;
+ TRACE_ERROR("[SQLITE_FULL][%d]", request_id);
+ if (dp_cancel_agent_download(request->agent_id) < 0)
+ TRACE_ERROR("[fail][%d]cancel_agent", request_id);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+ }
+ }
+
+ }
+
+ request->ip_changed = 0;
+ request->state = DP_STATE_DOWNLOADING;
+ request->error = DP_ERROR_NONE;
+ dp_request_state_response(request);
+
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+}
+
+static void __progress_cb(user_progress_info_t *info, void *user_data)
+{
+ if (!info) {
+ TRACE_ERROR("[NULL-CHECK] Agent info");
+ return ;
+ }
+ dp_request_slots *request_slot = (dp_request_slots *) user_data;
+ if (request_slot == NULL) {
+ TRACE_ERROR("[NULL-CHECK] request req_id:%d", info->download_id);
+ return ;
+ }
+ CLIENT_MUTEX_LOCK(&request_slot->mutex);
+ if (request_slot->request == NULL) {
+ TRACE_ERROR("[NULL-CHECK] request req_id:%d", info->download_id);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+ dp_request *request = request_slot->request;
+ if (request->id < 0 || (request->agent_id != info->download_id)) {
+ TRACE_ERROR("[NULL-CHECK] agent_id : %d req_id %d",
+ request->agent_id, info->download_id);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+
+ if (request->state == DP_STATE_DOWNLOADING) {
+ request->received_size = info->received_size;
+ time_t tt = time(NULL);
+ struct tm *localTime = localtime(&tt);
+ // send event every 1 second.
+ if (request->progress_lasttime != localTime->tm_sec) {
+ request->progress_lasttime = localTime->tm_sec;
+ if (request->auto_notification) {
+ dp_update_downloadinginfo_notification
+ (request->noti_priv_id,
+ (double)request->received_size,
+ (double)request->file_size);
+ } else {
+ int noti_type = dp_db_get_int_column(request->id, DP_DB_TABLE_NOTIFICATION, DP_DB_COL_NOTI_TYPE);
+ if(noti_type == DP_NOTIFICATION_TYPE_ALL)
+ dp_update_downloadinginfo_notification
+ (request->noti_priv_id,
+ (double)request->received_size,
+ (double)request->file_size);
+ }
+
+ if (request->progress_cb && request->group != NULL &&
+ request->group->event_socket >= 0 &&
+ request->received_size > 0)
+ dp_ipc_send_event(request->group->event_socket,
+ request->id, request->state, request->error,
+ request->received_size);
+ }
+ }
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+}
+
+static int __is_transmute_smack(char *path)
+{
+ char *dir_label = NULL;
+ int ret = -1;
+ if (smack_getlabel(path, &dir_label, SMACK_LABEL_TRANSMUTE) == 0 &&
+ dir_label != NULL) {
+ if (strncmp(dir_label, "TRUE", strlen(dir_label)) == 0)
+ ret = 0;
+ }
+ free(dir_label);
+ return ret;
+}
+
+static dp_error_type __set_dir_smack_label(char *smack_label, char *dir_path, char *saved_path)
+{
+ if (smack_label == NULL || dir_path== NULL || saved_path == NULL)
+ return DP_ERROR_PERMISSION_DENIED;
+
+ int is_setted_dir_label = 0;
+ dp_error_type errorcode = DP_ERROR_NONE;
+
+ TRACE_SECURE_INFO("[PARSE] dir path [%s]", dir_path);
+ if (__is_transmute_smack(dir_path) < 0) {
+ TRACE_DEBUG("[SMACK] no transmute");
+ } else {
+ char *dir_label = NULL;
+ if (smack_getlabel(dir_path, &dir_label,
+ SMACK_LABEL_ACCESS) == 0) {
+ if (smack_have_access(smack_label, dir_label, "t") > 0) {
+ if (smack_setlabel(saved_path, dir_label,
+ SMACK_LABEL_ACCESS) != 0) {
+ TRACE_SECURE_ERROR("[SMACK ERROR] label:%s",
+ dir_label);
+ errorcode = DP_ERROR_PERMISSION_DENIED;
+ } else {
+ is_setted_dir_label = 1;
+ }
+ } else {
+ TRACE_SECURE_ERROR("[SMACK ERROR] access:%s/%s",
+ smack_label, dir_label);
+ errorcode = DP_ERROR_PERMISSION_DENIED;
+ }
+ } else {
+ TRACE_SECURE_ERROR("[SMACK ERROR] no label:", dir_path);
+ errorcode = DP_ERROR_PERMISSION_DENIED;
+ }
+ free(dir_label);
+ }
+ if (is_setted_dir_label == 0 &&
+ smack_setlabel(saved_path, smack_label,
+ SMACK_LABEL_ACCESS) != 0) {
+ TRACE_SECURE_ERROR("[SMACK ERROR] label:%s", smack_label);
+ errorcode = DP_ERROR_PERMISSION_DENIED;
+ // remove file.
+ if (dp_is_file_exist(saved_path) == 0)
+ unlink(saved_path);
+ }
+ return errorcode;
+}
+
+static dp_error_type __set_file_permission_to_client(dp_request *request, char *saved_path)
+{
+ dp_error_type errorcode = DP_ERROR_NONE;
+ char *str = NULL;
+ char *smack_label = NULL;
+ str = strrchr(saved_path, '/');
+ dp_credential cred;
+ if (request->group == NULL) {
+ cred.uid = dp_db_cond_get_int(DP_DB_TABLE_GROUPS,
+ DP_DB_GROUPS_COL_UID,
+ DP_DB_GROUPS_COL_PKG,
+ DP_DB_COL_TYPE_TEXT, request->packagename);
+ cred.gid = dp_db_cond_get_int(DP_DB_TABLE_GROUPS,
+ DP_DB_GROUPS_COL_GID,
+ DP_DB_GROUPS_COL_PKG,
+ DP_DB_COL_TYPE_TEXT, request->packagename);
+ } else {
+ cred = request->group->credential;
+ }
+ TRACE_DEBUG
+ ("[chown][%d] [%d][%d]", request->id, cred.uid, cred.gid);
+ if (chown(saved_path, cred.uid, cred.gid) < 0)
+ TRACE_STRERROR("[ERROR][%d] chown", request->id);
+ if (chmod(saved_path,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0)
+ TRACE_STRERROR("[ERROR][%d] chmod", request->id);
+ if (dp_is_smackfs_mounted() == 1) {
+ if (request->group == NULL) {
+ // get smack_label from sql
+ smack_label =
+ dp_db_cond_get_text(DP_DB_TABLE_GROUPS,
+ DP_DB_GROUPS_COL_SMACK_LABEL,
+ DP_DB_GROUPS_COL_PKG,
+ DP_DB_COL_TYPE_TEXT, request->packagename);
+ } else {
+ smack_label = dp_strdup(request->group->smack_label);
+ }
+ if (smack_label == NULL) {
+ TRACE_SECURE_ERROR("[SMACK][%d] no label", request->id);
+ errorcode = DP_ERROR_PERMISSION_DENIED;
+ } else {
+ size_t len = str - (saved_path);
+ char *dir_path = (char *)calloc(len + 1, sizeof(char));
+ if (dir_path != NULL) {
+ strncpy(dir_path, saved_path, len);
+ errorcode =
+ __set_dir_smack_label(smack_label, dir_path,
+ saved_path);
+ free(dir_path);
+ } else {
+ TRACE_SECURE_ERROR("[ERROR] calloc");
+ errorcode = DP_ERROR_OUT_OF_MEMORY;
+ }
+ free(smack_label);
+ }
+ }
+ return errorcode;
+}
+
+static void __finished_cb(user_finished_info_t *info, void *user_data)
+{
+ if (!info) {
+ TRACE_ERROR("[NULL-CHECK] Agent info");
+ return ;
+ }
+ dp_request_slots *request_slot = (dp_request_slots *) user_data;
+ if (request_slot == NULL) {
+ TRACE_ERROR("[NULL-CHECK] request req_id:%d", info->download_id);
+ return ;
+ }
+ CLIENT_MUTEX_LOCK(&request_slot->mutex);
+ if (request_slot->request == NULL) {
+ TRACE_ERROR("[NULL-CHECK] request req_id:%d", info->download_id);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+ dp_request *request = request_slot->request;
+ if (request->id < 0 || (request->agent_id != info->download_id)) {
+ TRACE_ERROR("[NULL-CHECK] agent_id : %d req_id %d",
+ request->agent_id, info->download_id);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+
+ int request_id = request->id;
+ dp_state_type state = DP_STATE_NONE;
+ dp_error_type errorcode = DP_ERROR_NONE;
+
+ if (info->http_status > 0)
+ if (dp_db_replace_column(request_id, DP_DB_TABLE_DOWNLOAD_INFO,
+ DP_DB_COL_HTTP_STATUS,
+ DP_DB_COL_TYPE_INT, &info->http_status) < 0)
+ TRACE_ERROR("[ERROR][%d][SQL]", request_id);
+
+ if (info->err == DA_RESULT_OK) {
+
+ int conds_count = 5; // id + saved_path + content_name + http_status + file_size
+ int conds_index = 0;
+ db_conds_list_fmt conds_p[conds_count];
+ memset(&conds_p, 0x00, conds_count * sizeof(db_conds_list_fmt));
+
+ char *content_name = NULL;
+ if (info->saved_path != NULL) {
+ char *str = NULL;
+ if(!(strncmp(DP_SDCARD_MNT_POINT, info->saved_path,
+ strlen(DP_SDCARD_MNT_POINT)) == 0)) {
+ errorcode = __set_file_permission_to_client(request,
+ info->saved_path);
+ }
+ str = strrchr(info->saved_path, '/');
+ if (str != NULL) {
+ str++;
+ content_name = dp_strdup(str);
+ TRACE_SECURE_DEBUG("[PARSE][%d] content_name [%s]",
+ request_id, content_name);
+ }
+
+ conds_p[conds_index].column = DP_DB_COL_SAVED_PATH;
+ conds_p[conds_index].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[conds_index].value = info->saved_path;
+ conds_index++;
+ if (content_name != NULL) {
+ conds_p[conds_index].column = DP_DB_COL_CONTENT_NAME;
+ conds_p[conds_index].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[conds_index].value = content_name;
+ conds_index++;
+ }
+
+ if (errorcode == DP_ERROR_NONE) {
+ state = DP_STATE_COMPLETED;
+ TRACE_SECURE_INFO("[COMPLETED][%d] saved to [%s]",
+ request_id, info->saved_path);
+ } else {
+ state = DP_STATE_FAILED;
+ TRACE_SECURE_INFO("[FAILED][%d] saved to [%s]",
+ request_id, info->saved_path);
+ }
+ } else {
+ TRACE_ERROR("Cannot enter here");
+ TRACE_ERROR("[ERROR][%d] No SavedPath", request_id);
+ errorcode = DP_ERROR_INVALID_DESTINATION;
+ state = DP_STATE_FAILED;
+ }
+ if (request->file_size == 0) {
+ request->file_size = request->received_size;
+ conds_p[conds_index].column = DP_DB_COL_CONTENT_SIZE;
+ conds_p[conds_index].type = DP_DB_COL_TYPE_INT64;
+ conds_p[conds_index].value = &request->file_size;
+ conds_index++;
+ }
+
+ int check_id = dp_db_get_int_column(request_id, DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_ID);
+ if (check_id == request_id) { // update
+ if (dp_db_update_columns(request_id, DP_DB_TABLE_DOWNLOAD_INFO, conds_index, conds_p) < 0) {
+ if (dp_db_is_full_error() == 0) {
+ request->error = DP_ERROR_NO_SPACE;
+ TRACE_ERROR("[SQLITE_FULL][%d]", request_id);
+ if (dp_cancel_agent_download(request->agent_id) < 0)
+ TRACE_ERROR("[fail][%d]cancel_agent", request_id);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+ }
+ } else { // insert
+ conds_p[conds_index].column = DP_DB_COL_ID;
+ conds_p[conds_index].type = DP_DB_COL_TYPE_INT;
+ conds_p[conds_index].value = &request_id;
+ conds_index++;
+ if (dp_db_insert_columns(DP_DB_TABLE_DOWNLOAD_INFO, conds_index, conds_p) < 0) {
+ if (dp_db_is_full_error() == 0) {
+ request->error = DP_ERROR_NO_SPACE;
+ TRACE_ERROR("[SQLITE_FULL][%d]", request_id);
+ if (dp_cancel_agent_download(request->agent_id) < 0)
+ TRACE_ERROR("[fail][%d]cancel_agent", request_id);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+ }
+ }
+ free(content_name);
+ } else {
+ char *tmp_saved_path =
+ dp_request_get_tmpsavedpath(request_id, request, &errorcode);
+
+ if (tmp_saved_path != NULL) {
+ errorcode = __set_file_permission_to_client(request, tmp_saved_path);
+ free(tmp_saved_path);
+ } else {
+ TRACE_ERROR("Cannot enter here");
+ TRACE_ERROR("[ERROR][%d] No SavedPath", request_id);
+ }
+
+ if (info->err == DA_RESULT_USER_CANCELED) {
+ state = DP_STATE_CANCELED;
+ errorcode = request->error;
+ TRACE_INFO("[CANCELED][%d]", request_id);
+ } else {
+ state = DP_STATE_FAILED;
+ errorcode = __change_error(info->err);
+ TRACE_ERROR("[FAILED][%d][%s]", request_id,
+ dp_print_errorcode(errorcode));
+ }
+ }
+
+ request->state = state;
+ request->error = errorcode;
+
+ // auto resume when failed by ip_changed.
+ if (state == DP_STATE_FAILED && info->err == DA_ERR_NETWORK_FAIL &&
+ request->network_type != DP_NETWORK_TYPE_WIFI_DIRECT) {
+ if (request->ip_changed == 1 &&
+ dp_get_network_connection_instant_status() !=
+ DP_NETWORK_TYPE_OFF) {
+ // resume
+ TRACE_DEBUG("[RESUME][%d] will be queued", request_id);
+ request->state = DP_STATE_QUEUED;
+ request->error = DP_ERROR_NONE;
+ } else {
+ TRACE_DEBUG("[CHECK][%d] check again in timeout", request_id);
+ }
+ } else {
+ // stay on memory till called destroy by client or timeout
+ if (request->group != NULL &&
+ request->group->event_socket >= 0) {
+ /* update the received file size.
+ * The last received file size cannot update
+ * because of reducing update algorithm*/
+ if (request->received_size > 0) {
+ dp_ipc_send_event(request->group->event_socket,
+ request->id, DP_STATE_DOWNLOADING, request->error,
+ request->received_size);
+ }
+ }
+ dp_request_state_response(request);
+ }
+
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+
+ dp_thread_queue_manager_wake_up();
+}
+
+static void __paused_cb(user_paused_info_t *info, void *user_data)
+{
+ dp_request_slots *request_slot = (dp_request_slots *) user_data;
+ if (request_slot == NULL) {
+ TRACE_ERROR("[NULL-CHECK] request req_id:%d", info->download_id);
+ return ;
+ }
+ CLIENT_MUTEX_LOCK(&request_slot->mutex);
+ if (request_slot->request == NULL) {
+ TRACE_ERROR("[NULL-CHECK] request req_id:%d", info->download_id);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+ dp_request *request = request_slot->request;
+ if (request->id < 0 || (request->agent_id != info->download_id)) {
+ TRACE_ERROR("[NULL-CHECK] agent_id : %d req_id %d",
+ request->agent_id, info->download_id);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+
+ if (request->state != DP_STATE_PAUSE_REQUESTED) {
+ TRACE_ERROR("[CHECK] now status:%d", request->state);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return ;
+ }
+
+ int request_id = request->id;
+
+ if (dp_db_update_date
+ (request_id, DP_DB_TABLE_LOG, DP_DB_COL_ACCESS_TIME) < 0)
+ TRACE_ERROR("[ERROR][%d][SQL]", request_id);
+
+ request->state = DP_STATE_PAUSED;
+ request->error = DP_ERROR_NONE;
+ dp_request_state_response(request);
+
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+
+ dp_thread_queue_manager_wake_up();
+}
+
+int dp_init_agent()
+{
+
+ g_da_handle = dlopen("libdownloadagent2.so", RTLD_LAZY | RTLD_GLOBAL);
+ if (!g_da_handle) {
+ TRACE_ERROR("[dlopen] %s", dlerror());
+ g_da_handle = NULL;
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+ dlerror(); /* Clear any existing error */
+
+ *(void **) (&download_agent_init) = dlsym(g_da_handle, "da_init");
+ if (download_agent_init == NULL ) {
+ TRACE_ERROR("[dlsym] da_init:%s", dlerror());
+ dlclose(g_da_handle);
+ g_da_handle = NULL;
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+
+ *(void **) (&download_agent_deinit) = dlsym(g_da_handle, "da_deinit");
+ if (download_agent_deinit == NULL ) {
+ TRACE_ERROR("[dlsym] da_deinit:%s", dlerror());
+ dlclose(g_da_handle);
+ g_da_handle = NULL;
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+
+ *(void **) (&download_agent_is_alive) = dlsym(g_da_handle, "da_is_valid_download_id");
+ if (download_agent_is_alive == NULL ) {
+ TRACE_ERROR("[dlsym] da_is_valid_download_id:%s", dlerror());
+ dlclose(g_da_handle);
+ g_da_handle = NULL;
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+
+ *(void **) (&download_agent_suspend) = dlsym(g_da_handle, "da_suspend_download");
+ if (download_agent_suspend == NULL ) {
+ TRACE_ERROR("[dlsym] da_suspend_download:%s", dlerror());
+ dlclose(g_da_handle);
+ g_da_handle = NULL;
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+
+ *(void **) (&download_agent_resume) = dlsym(g_da_handle, "da_resume_download");
+ if (download_agent_resume == NULL ) {
+ TRACE_ERROR("[dlsym] da_resume_download:%s", dlerror());
+ dlclose(g_da_handle);
+ g_da_handle = NULL;
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+
+ *(void **) (&download_agent_cancel) = dlsym(g_da_handle, "da_cancel_download");
+ if (download_agent_cancel == NULL ) {
+ TRACE_ERROR("[dlsym] da_cancel_download:%s", dlerror());
+ dlclose(g_da_handle);
+ g_da_handle = NULL;
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+
+ *(void **) (&download_agent_start) = dlsym(g_da_handle, "da_start_download_with_extension");
+ if (download_agent_start == NULL ) {
+ TRACE_ERROR("[dlsym] da_start_download_with_extension:%s", dlerror());
+ dlclose(g_da_handle);
+ g_da_handle = NULL;
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+
+ int da_ret = -1;
+ da_client_cb_t da_cb = {
+ __download_info_cb,
+ __progress_cb,
+ __finished_cb,
+ __paused_cb
+ };
+ da_ret = (*download_agent_init)(&da_cb);
+ if (da_ret != DA_RESULT_OK) {
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+ return DP_ERROR_NONE;
+}
+
+void dp_deinit_agent()
+{
+ if (g_da_handle != NULL) {
+ if (download_agent_deinit != NULL)
+ (*download_agent_deinit)();
+
+ dlclose(g_da_handle);
+ g_da_handle = NULL;
+ }
+}
+
+// 1 : alive
+// 0 : not alive
+int dp_is_alive_download(int req_id)
+{
+ int da_ret = 0;
+ if (req_id < 0) {
+ TRACE_ERROR("[NULL-CHECK] req_id");
+ return 0;
+ }
+ if (download_agent_is_alive != NULL)
+ da_ret = (*download_agent_is_alive)(req_id);
+ return da_ret;
+}
+
+// 0 : success
+// -1 : failed
+dp_error_type dp_cancel_agent_download(int req_id)
+{
+ if (req_id < 0) {
+ TRACE_ERROR("[NULL-CHECK] req_id");
+ return -1;
+ }
+ if (dp_is_alive_download(req_id) == 0) {
+ TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
+ return -1;
+ }
+ if (download_agent_cancel != NULL) {
+ if ((*download_agent_cancel)(req_id) == DA_RESULT_OK)
+ return 0;
+ }
+ return -1;
+}
+
+// 0 : success
+// -1 : failed
+dp_error_type dp_pause_agent_download(int req_id)
+{
+ if (req_id < 0) {
+ TRACE_ERROR("[NULL-CHECK] req_id");
+ return -1;
+ }
+ if (dp_is_alive_download(req_id) == 0) {
+ TRACE_ERROR("[CHECK agent-id:%d] dead request", req_id);
+ return -1;
+ }
+ if (download_agent_suspend != NULL) {
+ if ((*download_agent_suspend)(req_id) == DA_RESULT_OK)
+ return 0;
+ }
+ return -1;
+}
+
+
+// 0 : success
+// -1 : failed
+// -2 : pended
+dp_error_type dp_start_agent_download(dp_request_slots *request_slot)
+{
+ int da_ret = -1;
+ int req_dl_id = -1;
+ dp_error_type errorcode = DP_ERROR_NONE;
+ extension_data_t ext_data = {0,};
+ char *etag = NULL;
+
+ if (request_slot == NULL) {
+ TRACE_ERROR("[NULL-CHECK] download_clientinfo_slot");
+ return DP_ERROR_INVALID_PARAMETER;
+ }
+
+ if (request_slot->request == NULL) {
+ TRACE_ERROR("[NULL-CHECK] download_clientinfo_slot");
+ return DP_ERROR_INVALID_PARAMETER;
+ }
+
+ dp_request *request = request_slot->request;
+
+ char *url = dp_request_get_url(request->id, &errorcode);
+ if (url == NULL) {
+ TRACE_ERROR("[ERROR][%d] URL is NULL", request->id);
+ return DP_ERROR_INVALID_URL;
+ }
+ char *destination =
+ dp_request_get_destination(request->id, request, &errorcode);
+ if (destination != NULL)
+ ext_data.install_path = destination;
+
+ char *filename =
+ dp_request_get_filename(request->id, request, &errorcode);
+ if (filename != NULL)
+ ext_data.file_name = filename;
+
+ // call start_download() of download-agent
+
+ char *tmp_saved_path =
+ dp_request_get_tmpsavedpath(request->id, request, &errorcode);
+ if (tmp_saved_path) {
+ etag = dp_request_get_etag(request->id, request, &errorcode);
+ if (etag) {
+ TRACE_DEBUG("[RESUME][%d]", request->id);
+ ext_data.etag = etag;
+ ext_data.temp_file_path = tmp_saved_path;
+ } else {
+ /* FIXME later : It is better to handle the unlink function in download agaent module
+ * or in upload the request data to memory after the download provider process is restarted */
+ TRACE_SECURE_INFO("[RESTART][%d] try to remove tmp file [%s]",
+ request->id, tmp_saved_path);
+ if (dp_is_file_exist(tmp_saved_path) == 0)
+ if (unlink(tmp_saved_path) != 0)
+ TRACE_STRERROR
+ ("[ERROR][%d] remove file", request->id);
+ }
+ }
+ char *pkg_name = dp_request_get_pkg_name(request->id, request, &errorcode);
+ if (pkg_name != NULL)
+ ext_data.pkg_name = pkg_name;
+ // get headers list from httpheaders table(DB)
+ int headers_count = dp_db_get_cond_rows_count
+ (request->id, DP_DB_TABLE_HTTP_HEADERS, NULL, 0, NULL);
+ if (headers_count > 0) {
+ ext_data.request_header = calloc(headers_count, sizeof(char*));
+ if (ext_data.request_header != NULL) {
+ ext_data.request_header_count = dp_db_get_http_headers_list
+ (request->id, (char**)ext_data.request_header);
+ }
+ }
+
+ ext_data.user_data = (void *)request_slot;
+
+ // call start API of agent lib
+ if (download_agent_start != NULL)
+ da_ret = (*download_agent_start)(url, &ext_data, &req_dl_id);
+ if (ext_data.request_header_count > 0) {
+ int len = 0;
+ int i = 0;
+ len = ext_data.request_header_count;
+ for (i = 0; i < len; i++) {
+ if (ext_data.request_header[i])
+ free((void *)(ext_data.request_header[i]));
+ }
+ free(ext_data.request_header);
+ }
+ free(url);
+ if (destination)
+ free(destination);
+ if (filename)
+ free(filename);
+ if (tmp_saved_path)
+ free(tmp_saved_path);
+ if (etag)
+ free(etag);
+ if (pkg_name)
+ free(pkg_name);
+
+ // if start_download() return error cause of maximun download limitation,
+ // set state to DOWNLOAD_STATE_PENDED.
+ if (da_ret == DA_ERR_ALREADY_MAX_DOWNLOAD) {
+ TRACE_DEBUG("[PENDING][%d] DA_ERR_ALREADY_MAX_DOWNLOAD [%d]",
+ request->id, da_ret);
+ return DP_ERROR_TOO_MANY_DOWNLOADS;
+ } else if (da_ret != DA_RESULT_OK) {
+ TRACE_ERROR("[ERROR][%d] DP_ERROR_CONNECTION_FAILED [%d]",
+ request->id, da_ret);
+ return __change_error(da_ret);
+ }
+ TRACE_DEBUG("[SUCCESS][%d] agent_id [%d]", request->id, req_dl_id);
+ request->agent_id = req_dl_id;
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_resume_agent_download(int req_id)
+{
+ int da_ret = -1;
+ if (req_id < 0) {
+ TRACE_ERROR("[NULL-CHECK] req_id");
+ return DP_ERROR_INVALID_PARAMETER;
+ }
+ if (download_agent_resume != NULL)
+ da_ret = (*download_agent_resume)(req_id);
+ if (da_ret == DA_RESULT_OK)
+ return DP_ERROR_NONE;
+ else if (da_ret == DA_ERR_INVALID_STATE)
+ return DP_ERROR_INVALID_STATE;
+ return __change_error(da_ret);
+}
+
diff --git a/provider/download-provider-db.c b/provider/download-provider-db.c
new file mode 100755
index 0000000..6f1d5cf
--- /dev/null
+++ b/provider/download-provider-db.c
@@ -0,0 +1,2352 @@
+/*
+ * 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 <string.h>
+#include <errno.h>
+#include <tzplatform_config.h>
+
+#include <stdlib.h>
+#include <sqlite3.h>
+
+#include "download-provider-config.h"
+#include "download-provider-db.h"
+#include "download-provider-slots.h"
+#include "download-provider-log.h"
+#include "download-provider-pthread.h"
+
+#define DATABASE_FILE tzplatform_mkpath(TZ_SYS_DB,".download-provider.db")
+
+//BASIC
+#define DP_DB_BASIC_GET_QUERY_FORMAT "SELECT %s FROM %s WHERE id = ?"
+#define DP_DB_BASIC_SET_QUERY_FORMAT "UPDATE %s SET %s = ? WHERE id = ?"
+#define DP_DB_BASIC_INSERT_QUERY_FORMAT "INSERT INTO %s (id, %s) VALUES (?, ?)"
+#define DP_DB_BASIC_NOW_DATE_QUERY_FORMAT "UPDATE %s SET %s = DATETIME('now') WHERE id = ?"
+
+// COND
+#define DP_DB_COND_GET_QUERY_FORMAT "SELECT %s FROM %s WHERE id = ? AND %s = ?"
+#define DP_DB_COND_SET_QUERY_FORMAT "UPDATE %s SET %s = ? WHERE id = ? AND %s = ?"
+
+typedef enum {
+ DP_DB_QUERY_TYPE_GET = 10,
+ DP_DB_QUERY_TYPE_SET = 20,
+ DP_DB_QUERY_TYPE_INSERT = 30,
+ DP_DB_QUERY_TYPE_NOW_DATE = 40
+} db_query_type;
+
+sqlite3 *g_dp_db_handle = 0;
+sqlite3_stmt *g_dp_db_logging_new_stmt = NULL;
+sqlite3_stmt *g_dp_db_logging_status_stmt = NULL;
+sqlite3_stmt *g_dp_db_logging_get_state_stmt = NULL;
+
+static void __dp_finalize(sqlite3_stmt *stmt)
+{
+ if (sqlite3_finalize(stmt) != SQLITE_OK)
+ TRACE_ERROR("failed sqlite3_finalize [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+}
+
+// called when terminating process
+void dp_db_close()
+{
+ if (g_dp_db_handle) {
+ if (g_dp_db_logging_new_stmt != NULL)
+ __dp_finalize(g_dp_db_logging_new_stmt);
+ if (g_dp_db_logging_status_stmt != NULL)
+ __dp_finalize(g_dp_db_logging_status_stmt);
+ sqlite3_exec(g_dp_db_handle, "VACUUM;", 0, 0, 0); // remove empty page of db
+ sqlite3_close(g_dp_db_handle);
+ }
+ g_dp_db_handle = 0;
+}
+
+static void __load_sql_schema()
+{
+ char *rebuild_query =
+ sqlite3_mprintf("sqlite3 %s '.read %s'", DATABASE_FILE, DATABASE_SCHEMA_FILE);
+ if (rebuild_query != NULL) {
+ TRACE_SECURE_INFO("[QUERY] %s", rebuild_query);
+ system(rebuild_query);
+ sqlite3_free(rebuild_query);
+ }
+}
+
+static int __dp_sql_open()
+{
+ return dp_db_open();
+}
+
+static int __check_table(char *table)
+{
+ //"SELECT name FROM sqlite_master WHERE type='table' AND name='" + table +"'";
+ sqlite3_stmt *stmt = NULL;
+
+ if (table == NULL) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[OPEN] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ char *query = sqlite3_mprintf("SELECT name FROM sqlite_master WHERE type='table' AND name='%s'", table);
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE]");
+ return -1;
+ }
+
+ int ret = sqlite3_prepare_v2(g_dp_db_handle, query, -1, &stmt, NULL);
+ sqlite3_free(query);
+ if (ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ if (sqlite3_step(stmt) == SQLITE_ROW) {
+ __dp_finalize(stmt);
+ return 1;
+ }
+ __dp_finalize(stmt);
+ return 0;
+}
+
+// called when launching process or in every API
+int dp_db_open()
+{
+ if (g_dp_db_handle == 0) {
+ TRACE_SECURE_INFO("TRY to open [%s]", DATABASE_FILE);
+ if (sqlite3_open_v2(DATABASE_FILE, &g_dp_db_handle,
+ SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK) {
+ TRACE_ERROR("[ERROR][%s][%s]", DATABASE_FILE,
+ sqlite3_errmsg(g_dp_db_handle));
+ int errorcode = sqlite3_errcode(g_dp_db_handle);
+ dp_db_close();
+ if (errorcode == SQLITE_CORRUPT) {
+ TRACE_SECURE_INFO("unlink [%s]", DATABASE_FILE);
+ unlink(DATABASE_FILE);
+ errorcode = SQLITE_CANTOPEN;
+ }
+ if (errorcode == SQLITE_CANTOPEN) {
+ __load_sql_schema();
+ return dp_db_open();
+ }
+ return -1;
+ }
+ sqlite3_exec(g_dp_db_handle, "PRAGMA journal_mode=PERSIST;", 0, 0, 0);
+ sqlite3_exec(g_dp_db_handle, "PRAGMA foreign_keys=ON;", 0, 0, 0);
+
+ // if not found group table. load again. (FOTA)
+ // new table(groups) created by smack_label. 2013.07.09
+ if (__check_table(DP_DB_TABLE_GROUPS) == 0)
+ __load_sql_schema();
+ }
+ return g_dp_db_handle ? 0 : -1;
+}
+
+int dp_db_is_full_error()
+{
+ if (g_dp_db_handle == 0) {
+ TRACE_ERROR("HANDLE is null");
+ return -1;
+ }
+ if (sqlite3_errcode(g_dp_db_handle) == SQLITE_FULL)
+ return 0;
+ return -1;
+}
+
+int dp_db_get_count_by_limit_time()
+{
+ int errorcode = SQLITE_OK;
+ sqlite3_stmt *stmt = NULL;
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("db_util_open is failed [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ errorcode =
+ sqlite3_prepare_v2(g_dp_db_handle,
+ "SELECT count(id) FROM logging \
+ WHERE createtime < DATETIME('now','-48 hours')",
+ -1, &stmt, NULL);
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_prepare_v2 is failed. [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_ROW) {
+ int count = sqlite3_column_int(stmt, 0);
+ __dp_finalize(stmt);
+ return count;
+ }
+ __dp_finalize(stmt);
+ return 0;
+}
+
+int dp_db_get_list_by_limit_time(dp_request_slots *requests, int limit)
+{
+ int errorcode = SQLITE_OK;
+ int i = 0;
+ sqlite3_stmt *stmt = NULL;
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("db_util_open is failed [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ errorcode =
+ sqlite3_prepare_v2(g_dp_db_handle,
+ "SELECT id, state FROM logging WHERE \
+ createtime < DATETIME('now','-48 hours') \
+ ORDER BY createtime ASC LIMIT ?",
+ -1, &stmt, NULL);
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_prepare_v2 is failed. [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ if (sqlite3_bind_int(stmt, 1, limit)
+ != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_bind_int[%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ while ((errorcode = sqlite3_step(stmt)) == SQLITE_ROW && i < limit) {
+ // allocation & initialization
+ requests[i].request = dp_request_new();
+ // ID
+ requests[i].request->id = sqlite3_column_int(stmt, 0);
+ // state
+ requests[i].request->state = sqlite3_column_int(stmt, 1);
+ i++;
+ }
+
+ __dp_finalize(stmt);
+ return i;
+}
+
+int dp_db_crashed_list(dp_request_slots *requests, int limit)
+{
+ int errorcode = SQLITE_OK;
+ int i = 0;
+ int buffer_length = 0;
+ sqlite3_stmt *stmt = NULL;
+ char *buffer = NULL;
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("db_util_open is failed [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ errorcode =
+ sqlite3_prepare_v2(g_dp_db_handle,
+ "SELECT id, state, packagename FROM logging WHERE \
+ (state = ? OR state = ? OR state = ?) \
+ AND createtime > DATETIME('now','-48 hours') LIMIT ?",
+ -1, &stmt, NULL);
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_prepare_v2 is failed. [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ if (sqlite3_bind_int(stmt, 1, DP_STATE_QUEUED) != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_bind_int [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ if (sqlite3_bind_int(stmt, 2, DP_STATE_DOWNLOADING) != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_bind_int [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ if (sqlite3_bind_int(stmt, 3, DP_STATE_CONNECTING) != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_bind_int [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ if (sqlite3_bind_int(stmt, 4, limit)
+ != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_bind_int[%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ while ((errorcode = sqlite3_step(stmt)) == SQLITE_ROW) {
+ // allocation & initialization
+ requests[i].request = dp_request_new();
+ // ID
+ requests[i].request->id = sqlite3_column_int(stmt, 0);
+ // state
+ requests[i].request->state = sqlite3_column_int(stmt, 1);
+ // packagename
+ buffer = (char *)(sqlite3_column_text(stmt, 2));
+ requests[i].request->packagename = NULL;
+ if (buffer) {
+ buffer_length = strlen(buffer);
+ if (buffer_length > 1) {
+ requests[i].request->packagename
+ = (char *)calloc(buffer_length + 1, sizeof(char));
+ memcpy(requests[i].request->packagename, buffer,
+ buffer_length * sizeof(char));
+ requests[i].request->packagename[buffer_length] = '\0';
+ }
+ }
+ i++;
+ }
+
+ __dp_finalize(stmt);
+ return i;
+}
+
+int dp_db_limit_rows(int limit)
+{
+ int errorcode = SQLITE_OK;
+ sqlite3_stmt *stmt = NULL;
+
+ if (limit <= 0) {
+ TRACE_ERROR("[CHECK LIMIT] %d", limit);
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("__dp_sql_open[%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ // apply "ON DELETE CASCADE"
+ errorcode =
+ sqlite3_prepare_v2(g_dp_db_handle,
+ "DELETE FROM logging WHERE id NOT IN \
+ (SELECT id FROM logging ORDER BY createtime ASC LIMIT ?)",
+ -1, &stmt, NULL);
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_prepare_v2 [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ if (sqlite3_bind_int(stmt, 1, limit)
+ != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_bind_int[%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ __dp_finalize(stmt);
+ return 0;
+ }
+ __dp_finalize(stmt);
+ return -1;
+}
+
+dp_request *dp_db_load_logging_request(int id)
+{
+ int errorcode = SQLITE_OK;
+ int buffer_length = 0;
+ sqlite3_stmt *stmt = NULL;
+ char *buffer = NULL;
+ dp_request *request = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return NULL;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("db_util_open is failed [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ return NULL;
+ }
+
+ errorcode =
+ sqlite3_prepare_v2(g_dp_db_handle,
+ "SELECT state, errorcode, startcount, packagename \
+ FROM logging WHERE id = ?",
+ -1, &stmt, NULL);
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_prepare_v2 is failed. [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return NULL;
+ }
+ if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_bind_int is failed. [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return NULL;
+ }
+
+ if ((errorcode = sqlite3_step(stmt)) == SQLITE_ROW) {
+ request = dp_request_new();
+ if (request == NULL) {
+ TRACE_ERROR("dp_request_new failed");
+ __dp_finalize(stmt);
+ return NULL;
+ }
+ request->id = id;
+ request->state = sqlite3_column_int(stmt, 0);
+ request->error = sqlite3_column_int(stmt, 1);
+ request->startcount = sqlite3_column_int(stmt, 2);
+
+ buffer = (char *)(sqlite3_column_text(stmt, 3));
+ if (buffer) {
+ buffer_length = strlen(buffer);
+ if (buffer_length > 1) {
+ request->packagename
+ = (char *)calloc(buffer_length + 1, sizeof(char));
+ memcpy(request->packagename, buffer,
+ buffer_length * sizeof(char));
+ request->packagename[buffer_length] = '\0';
+ }
+ }
+ } else {
+ TRACE_ERROR("sqlite3_step is failed. [%s] errorcode[%d]",
+ sqlite3_errmsg(g_dp_db_handle), errorcode);
+ __dp_finalize(stmt);
+ return NULL;
+ }
+ __dp_finalize(stmt);
+ return request;
+}
+
+int dp_db_remove_all(int id)
+{
+ #if 0
+ dp_db_remove(id, DP_DB_TABLE_REQUEST_INFO);
+ dp_db_remove(id, DP_DB_TABLE_DOWNLOAD_INFO);
+ dp_db_remove(id, DP_DB_TABLE_HTTP_HEADERS);
+ dp_db_remove(id, DP_DB_TABLE_NOTIFICATION);
+ #endif
+ // apply "ON DELETE CASCADE"
+ dp_db_remove(id, DP_DB_TABLE_LOG);
+ return -1;
+}
+
+int dp_db_remove(int id, char *table)
+{
+ int errorcode = SQLITE_OK;
+ int query_len = 0;
+ int ret = -1;
+ sqlite3_stmt *stmt = NULL;
+ char *query_format = NULL;
+ char *query = NULL;
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("__dp_sql_open[%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ query_format = "DELETE FROM %s WHERE id = ? ";
+ // 2 means the length of one %s
+ query_len = strlen(query_format) - 2 + strlen(table);
+ if (query_len < strlen(query_format)) {
+ TRACE_ERROR("[CHECK QUERY FORMAT] [%s][%s]",
+ query_format, table);
+ return -1;
+ }
+
+ query = (char *)calloc((query_len + 1), sizeof(char));
+ if (query == NULL) {
+ TRACE_STRERROR("[CALLOC]");
+ return -1;
+ }
+ query[query_len] = '\0';
+
+ ret = snprintf(query, query_len + 1, query_format, table);
+
+ if (ret < 0) {
+ TRACE_STRERROR("[CHECK COMBINE] [%s]", query);
+ free(query);
+ return -1;
+ }
+
+ // check error of sqlite3_prepare_v2
+ if (sqlite3_prepare_v2
+ (g_dp_db_handle, query, -1, &stmt, NULL) != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ free(query);
+ return -1;
+ }
+ free(query);
+
+ if (sqlite3_bind_int(stmt, 1, id)
+ != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_bind_int[%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ __dp_finalize(stmt);
+ return 0;
+ }
+ TRACE_ERROR("[SQL] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+}
+
+static sqlite3_stmt *__prepare_query(sqlite3 *handle,
+ db_query_type type, char *table, char *column)
+{
+ sqlite3_stmt *stmt = NULL;
+ char *query_format = NULL;
+ char *query = NULL;
+ int ret = -1;
+
+ if (type == DP_DB_QUERY_TYPE_GET) {
+ query_format = DP_DB_BASIC_GET_QUERY_FORMAT;
+ } else if (type == DP_DB_QUERY_TYPE_SET) {
+ query_format = DP_DB_BASIC_SET_QUERY_FORMAT;
+ } else if (type == DP_DB_QUERY_TYPE_INSERT) {
+ query_format = DP_DB_BASIC_INSERT_QUERY_FORMAT;
+ } else if (type == DP_DB_QUERY_TYPE_NOW_DATE) {
+ query_format = DP_DB_BASIC_NOW_DATE_QUERY_FORMAT;
+ } else {
+ TRACE_ERROR("[CHECK QUERY TYPE] [%d]", type);
+ return NULL;
+ }
+
+ if (type == DP_DB_QUERY_TYPE_GET)
+ query = sqlite3_mprintf(query_format, column, table);
+ else
+ query = sqlite3_mprintf(query_format, table, column);
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE] [%s]", query_format);
+ return NULL;
+ }
+
+ ret = sqlite3_prepare_v2(handle, query, -1, &stmt, NULL);
+ sqlite3_free(query);
+ if ( ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(handle));
+ __dp_finalize(stmt);
+ return NULL;
+ }
+ return stmt;
+}
+
+int dp_db_insert_column(int id, char *table, char *column,
+ db_column_data_type datatype, void *value)
+{
+ sqlite3_stmt *stmt = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+
+ if (!column) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[OPEN] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ stmt = __prepare_query
+ (g_dp_db_handle, DP_DB_QUERY_TYPE_INSERT, table, column);
+ if (stmt == NULL) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ int errorcode = SQLITE_OK;
+ if (datatype == DP_DB_COL_TYPE_INT) {
+ int *cast_value = value;
+ errorcode = sqlite3_bind_int(stmt, 2, *cast_value);
+ } else if (datatype == DP_DB_COL_TYPE_INT64) {
+#ifdef SQLITE_INT64_TYPE
+ sqlite3_int64 *cast_value = value;
+ errorcode = sqlite3_bind_int64(stmt, 2, *cast_value);
+#else
+ int *cast_value = value;
+ errorcode = sqlite3_bind_int(stmt, 2, *cast_value);
+#endif
+ } else if (datatype == DP_DB_COL_TYPE_TEXT) {
+ errorcode = sqlite3_bind_text(stmt, 2, (char*)value, -1, NULL);
+ } else {
+ TRACE_ERROR("[CHECK TYPE] Not Support [%d]", datatype);
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%d] [%s]",
+ datatype, sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ // VALUES ( id )
+ if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ __dp_finalize(stmt);
+ return 0;
+ }
+ TRACE_ERROR("[SQL] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+}
+
+int dp_db_insert_blob_column(int id, char *table, char *column,
+ void *value, unsigned length)
+{
+ sqlite3_stmt *stmt = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+
+ if (!column) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[OPEN] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ stmt = __prepare_query
+ (g_dp_db_handle, DP_DB_QUERY_TYPE_INSERT, table, column);
+ if (stmt == NULL) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ int errorcode = SQLITE_OK;
+ errorcode = sqlite3_bind_blob(stmt, 2, value, (int)length, NULL);
+
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ // VALUES ( id )
+ if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ __dp_finalize(stmt);
+ return 0;
+ }
+ TRACE_ERROR("[SQL] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+}
+
+int dp_db_set_column(int id, char *table, char *column,
+ db_column_data_type datatype, void *value)
+{
+ sqlite3_stmt *stmt = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+
+ if (!column) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[OPEN] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ stmt = __prepare_query
+ (g_dp_db_handle, DP_DB_QUERY_TYPE_SET, table, column);
+ if (stmt == NULL) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ int errorcode = SQLITE_OK;
+ if (datatype == DP_DB_COL_TYPE_INT) {
+ int *cast_value = value;
+ errorcode = sqlite3_bind_int(stmt, 1, *cast_value);
+ } else if (datatype == DP_DB_COL_TYPE_INT64) {
+#ifdef SQLITE_INT64_TYPE
+ sqlite3_int64 *cast_value = value;
+ errorcode = sqlite3_bind_int64(stmt, 1, *cast_value);
+#else
+ int *cast_value = value;
+ errorcode = sqlite3_bind_int(stmt, 1, *cast_value);
+#endif
+ } else if (datatype == DP_DB_COL_TYPE_TEXT) {
+ errorcode = sqlite3_bind_text(stmt, 1, (char*)value, -1, NULL);
+ } else {
+ TRACE_ERROR("[CHECK TYPE] Not Support [%d]", datatype);
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%d] [%s]",
+ datatype, sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ // WHERE id = ?
+ if (sqlite3_bind_int(stmt, 2, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ __dp_finalize(stmt);
+ return 0;
+ }
+ TRACE_ERROR("[SQL] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+}
+
+int dp_db_set_blob_column(int id, char *table, char *column,
+ void *value, unsigned length)
+{
+ sqlite3_stmt *stmt = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+
+ if (!column) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[OPEN] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ stmt = __prepare_query
+ (g_dp_db_handle, DP_DB_QUERY_TYPE_SET, table, column);
+ if (stmt == NULL) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ int errorcode = SQLITE_OK;
+ errorcode = sqlite3_bind_blob(stmt, 1, value, (int)length, NULL);
+
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ // WHERE id = ?
+ if (sqlite3_bind_int(stmt, 2, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ __dp_finalize(stmt);
+ return 0;
+ }
+ TRACE_ERROR("[SQL] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+}
+
+int dp_db_replace_column(int id, char *table, char *column,
+ db_column_data_type datatype, void *value)
+{
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+
+ if (!column) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+
+ int check_id = dp_db_get_int_column(id, table, DP_DB_COL_ID);
+ if (check_id != id) // INSERT
+ return dp_db_insert_column(id, table, column, datatype, value);
+ // UPDATE
+ return dp_db_set_column(id, table, column, datatype, value);
+}
+
+int dp_db_replace_blob_column(int id, char *table, char *column1,
+ void *value, unsigned length)
+{
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+ if (!column1) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+ int check_id = dp_db_get_int_column(id, table, DP_DB_COL_ID);
+ if (check_id != id) // INSERT
+ {
+ return dp_db_insert_blob_column(id, table, column1, value, length);
+ }
+ // UPDATE
+ return dp_db_set_blob_column(id, table, column1, value, length);
+}
+
+// success : 0
+// error : -1
+char *dp_db_get_text_column(int id, char *table, char *column)
+{
+ sqlite3_stmt *stmt = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return NULL;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return NULL;
+ }
+
+ if (!column) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return NULL;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[OPEN] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return NULL;
+ }
+
+ stmt = __prepare_query
+ (g_dp_db_handle, DP_DB_QUERY_TYPE_GET, table, column);
+ if (stmt == NULL) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return NULL;
+ }
+
+ // WHERE id = ?
+ if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return NULL;
+ }
+
+ if (sqlite3_step(stmt) == SQLITE_ROW) {
+ int buffer_length = 0;
+ char *columntext = NULL;
+ char *buffer = (char *)(sqlite3_column_text(stmt, 0));
+ if (buffer && (buffer_length = strlen(buffer)) > 1) {
+ columntext = (char *)calloc(buffer_length + 1, sizeof(char));
+ memcpy(columntext, buffer, buffer_length * sizeof(char));
+ columntext[buffer_length] = '\0';
+ }
+ __dp_finalize(stmt);
+ return columntext;
+ }
+ __dp_finalize(stmt);
+ return NULL;
+}
+
+// success : 0
+// error : -1
+void *dp_db_get_blob_column(int id, char *table, char *column, int *length)
+{
+ sqlite3_stmt *stmt = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return NULL;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return NULL;
+ }
+
+ if (!column) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return NULL;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[OPEN] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return NULL;
+ }
+
+ stmt = __prepare_query
+ (g_dp_db_handle, DP_DB_QUERY_TYPE_GET, table, column);
+ if (stmt == NULL) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return NULL;
+ }
+
+ // WHERE id = ?
+ if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return NULL;
+ }
+
+ if (sqlite3_step(stmt) == SQLITE_ROW) {
+ int blob_length = 0;
+ void *blob_data = NULL;
+ blob_length = sqlite3_column_bytes(stmt, 0);
+ if(blob_length > 0){
+ blob_data = (void*)calloc(blob_length, sizeof(unsigned char));
+ if(blob_data != NULL){
+ memcpy(blob_data, sqlite3_column_blob(stmt, 0),
+ sizeof(unsigned char)*blob_length);
+ } else {
+ TRACE_ERROR("[MEM] allocating");
+ blob_length = -1;
+ }
+ } else {
+ TRACE_ERROR("NO DATA");
+ blob_length = -1;
+ }
+ __dp_finalize(stmt);
+ *length = blob_length;
+ return blob_data;
+ }
+ __dp_finalize(stmt);
+ return NULL;
+}
+
+
+int dp_db_get_int_column(int id, char *table, char *column)
+{
+ sqlite3_stmt *stmt = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+
+ if (!column) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[OPEN] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ stmt = __prepare_query
+ (g_dp_db_handle, DP_DB_QUERY_TYPE_GET, table, column);
+ if (stmt == NULL) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ // WHERE id = ?
+ if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ if (sqlite3_step(stmt) == SQLITE_ROW) {
+ int columnvalue = sqlite3_column_int(stmt, 0);
+ __dp_finalize(stmt);
+ return columnvalue;
+ }
+ __dp_finalize(stmt);
+ return -1;
+}
+
+long long dp_db_get_int64_column(int id, char *table, char *column)
+{
+ sqlite3_stmt *stmt = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+
+ if (!column) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[OPEN] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ stmt = __prepare_query
+ (g_dp_db_handle, DP_DB_QUERY_TYPE_GET, table, column);
+ if (stmt == NULL) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ // WHERE id = ?
+ if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ if (sqlite3_step(stmt) == SQLITE_ROW) {
+ long long columnvalue = sqlite3_column_int64(stmt, 0);
+ __dp_finalize(stmt);
+ return columnvalue;
+ }
+ __dp_finalize(stmt);
+ return -1;
+}
+
+int dp_db_update_date(int id, char *table, char *column)
+{
+ int errorcode = SQLITE_OK;
+ sqlite3_stmt *stmt = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("__dp_sql_open [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ stmt = __prepare_query
+ (g_dp_db_handle, DP_DB_QUERY_TYPE_NOW_DATE, table, column);
+ if (stmt == NULL) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ // WHERE id = ?
+ if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_bind_int [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ __dp_finalize(stmt);
+ return 0;
+ }
+ TRACE_ERROR("Failed : [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+}
+
+static sqlite3_stmt *__prepare_cond_query(sqlite3 *handle,
+ db_query_type type, char *table,
+ char *column, char *cond_column)
+{
+ sqlite3_stmt *stmt = NULL;
+ char *query_format = NULL;
+ char *query = NULL;
+ int ret = -1;
+
+ if (type == DP_DB_QUERY_TYPE_GET) {
+ query_format = DP_DB_COND_GET_QUERY_FORMAT;
+ } else if (type == DP_DB_QUERY_TYPE_SET) {
+ query_format = DP_DB_COND_SET_QUERY_FORMAT;
+ } else {
+ TRACE_ERROR("[CHECK QUERY TYPE] [%d]", type);
+ return NULL;
+ }
+
+ if (type == DP_DB_QUERY_TYPE_GET)
+ query = sqlite3_mprintf(query_format, column, table, cond_column);
+ else
+ query = sqlite3_mprintf(query_format, table, column, cond_column);
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE] [%s]", query_format);
+ return NULL;
+ }
+
+ ret = sqlite3_prepare_v2(handle, query, -1, &stmt, NULL);
+ sqlite3_free(query);
+ if ( ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(handle));
+ __dp_finalize(stmt);
+ return NULL;
+ }
+ return stmt;
+
+}
+
+int dp_db_cond_set_column(int id, char *table, char *column,
+ db_column_data_type datatype, void *value,
+ char *condcolumn, db_column_data_type condtype, void *condvalue)
+{
+ int errorcode = SQLITE_OK;
+ sqlite3_stmt *stmt = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+
+ if (!column) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+
+ if (!condcolumn) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[OPEN] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ stmt = __prepare_cond_query
+ (g_dp_db_handle, DP_DB_QUERY_TYPE_SET, table, column, condcolumn);
+ if (stmt == NULL) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ if (datatype == DP_DB_COL_TYPE_INT) {
+ int *cast_value = value;
+ errorcode = sqlite3_bind_int(stmt, 1, *cast_value);
+ } else if (datatype == DP_DB_COL_TYPE_INT64) {
+#ifdef SQLITE_INT64_TYPE
+ sqlite3_int64 *cast_value = value;
+ errorcode = sqlite3_bind_int64(stmt, 1, *cast_value);
+#else
+ int *cast_value = value;
+ errorcode = sqlite3_bind_int(stmt, 1, *cast_value);
+#endif
+ } else if (datatype == DP_DB_COL_TYPE_TEXT) {
+ errorcode = sqlite3_bind_text(stmt, 1, (char*)value, -1, NULL);
+ } else {
+ TRACE_ERROR("[CHECK TYPE] Not Support [%d]", datatype);
+ __dp_finalize(stmt);
+ return -1;
+ }
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%d] [%s]",
+ datatype, sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ if (condtype == DP_DB_COL_TYPE_INT) {
+ int *cast_value = condvalue;
+ errorcode = sqlite3_bind_int(stmt, 3, *cast_value);
+ } else if (condtype == DP_DB_COL_TYPE_INT64) {
+#ifdef SQLITE_INT64_TYPE
+ sqlite3_int64 *cast_value = condvalue;
+ errorcode = sqlite3_bind_int64(stmt, 3, *cast_value);
+#else
+ int *cast_value = condvalue;
+ errorcode = sqlite3_bind_int(stmt, 3, *cast_value);
+#endif
+ } else if (condtype == DP_DB_COL_TYPE_TEXT) {
+ errorcode = sqlite3_bind_text(stmt, 3, (char*)condvalue, -1, NULL);
+ } else {
+ TRACE_ERROR("[CHECK TYPE] Not Support [%d]", condtype);
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%d] [%s]",
+ datatype, sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ // WHERE id = ?
+ if (sqlite3_bind_int(stmt, 2, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ __dp_finalize(stmt);
+ return 0;
+ }
+ __dp_finalize(stmt);
+ return -1;
+}
+
+char *dp_db_cond_get_text_column(int id, char *table, char *column,
+ char *condcolumn, db_column_data_type condtype,
+ void *condvalue)
+{
+ sqlite3_stmt *stmt = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return NULL;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return NULL;
+ }
+
+ if (!column) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return NULL;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[OPEN] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return NULL;
+ }
+
+ stmt = __prepare_cond_query
+ (g_dp_db_handle, DP_DB_QUERY_TYPE_GET, table, column, condcolumn);
+ if (stmt == NULL) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return NULL;
+ }
+
+ int errorcode = SQLITE_OK;
+ if (condtype == DP_DB_COL_TYPE_INT) {
+ int *cast_value = condvalue;
+ errorcode = sqlite3_bind_int(stmt, 2, *cast_value);
+ } else if (condtype == DP_DB_COL_TYPE_INT64) {
+#ifdef SQLITE_INT64_TYPE
+ sqlite3_int64 *cast_value = condvalue;
+ errorcode = sqlite3_bind_int64(stmt, 2, *cast_value);
+#else
+ int *cast_value = condvalue;
+ errorcode = sqlite3_bind_int(stmt, 2, *cast_value);
+#endif
+ } else if (condtype == DP_DB_COL_TYPE_TEXT) {
+ errorcode = sqlite3_bind_text(stmt, 2, (char*)condvalue, -1, NULL);
+ } else {
+ TRACE_ERROR("[CHECK TYPE] Not Support [%d]", condtype);
+ __dp_finalize(stmt);
+ return NULL;
+ }
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%d] [%s]",
+ condtype, sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return NULL;
+ }
+
+ // WHERE id = ?
+ if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return NULL;
+ }
+
+ if (sqlite3_step(stmt) == SQLITE_ROW) {
+ int buffer_length = 0;
+ char *columntext = NULL;
+ char *buffer = (char *)(sqlite3_column_text(stmt, 0));
+ if (buffer && (buffer_length = strlen(buffer)) > 1) {
+ columntext = (char *)calloc(buffer_length + 1, sizeof(char));
+ memcpy(columntext, buffer, buffer_length * sizeof(char));
+ columntext[buffer_length] = '\0';
+ }
+ __dp_finalize(stmt);
+ return columntext;
+ }
+ TRACE_ERROR("[SQL] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return NULL;
+}
+
+int dp_db_cond_remove(int id, char *table,
+ char *condcolumn, db_column_data_type condtype,
+ void *condvalue)
+{
+ int errorcode = SQLITE_OK;
+ int ret = -1;
+ sqlite3_stmt *stmt = NULL;
+ char *query_format = NULL;
+ char *query = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+
+ if (!condcolumn) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("__dp_sql_open[%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ query_format = "DELETE FROM %s WHERE id = ? AND %s = ?";
+
+ query = sqlite3_mprintf(query_format, table, condcolumn);
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE] [%s]", query_format);
+ return -1;
+ }
+
+ ret = sqlite3_prepare_v2(g_dp_db_handle, query, -1, &stmt, NULL);
+ sqlite3_free(query);
+ if ( ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ if (condtype == DP_DB_COL_TYPE_INT) {
+ int *cast_value = condvalue;
+ errorcode = sqlite3_bind_int(stmt, 2, *cast_value);
+ } else if (condtype == DP_DB_COL_TYPE_INT64) {
+#ifdef SQLITE_INT64_TYPE
+ sqlite3_int64 *cast_value = condvalue;
+ errorcode = sqlite3_bind_int64(stmt, 2, *cast_value);
+#else
+ int *cast_value = condvalue;
+ errorcode = sqlite3_bind_int(stmt, 2, *cast_value);
+#endif
+ } else if (condtype == DP_DB_COL_TYPE_TEXT) {
+ errorcode = sqlite3_bind_text(stmt, 2, (char*)condvalue, -1, NULL);
+ } else {
+ TRACE_ERROR("[CHECK TYPE] Not Support [%d]", condtype);
+ __dp_finalize(stmt);
+ return -1;
+ }
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%d] [%s]",
+ condtype, sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ if (sqlite3_bind_int(stmt, 1, id)
+ != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_bind_int[%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ __dp_finalize(stmt);
+ return 0;
+ }
+ TRACE_ERROR("[SQL] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+}
+
+static int __dp_sql_bind_value(sqlite3_stmt *stmt,
+ db_column_data_type condtype, void *value, int index)
+{
+ int errorcode = SQLITE_ERROR;
+ int *cast_value = 0;
+
+ if (stmt == NULL)
+ return SQLITE_ERROR;
+
+ switch (condtype) {
+ case DP_DB_COL_TYPE_INT:
+ cast_value = value;
+ errorcode = sqlite3_bind_int(stmt, index, *cast_value);
+ break;
+ case DP_DB_COL_TYPE_INT64:
+#ifdef SQLITE_INT64_TYPE
+ sqlite3_int64 *cast_value = value;
+ errorcode = sqlite3_bind_int64(stmt, index, *cast_value);
+#else
+ cast_value = value;
+ errorcode = sqlite3_bind_int(stmt, index, *cast_value);
+#endif
+ break;
+ case DP_DB_COL_TYPE_TEXT:
+ errorcode =
+ sqlite3_bind_text(stmt, index, (char *)value, -1, SQLITE_STATIC);
+ break;
+ default:
+ errorcode = SQLITE_ERROR;
+ break;
+ }
+ return errorcode;
+}
+
+char *dp_db_cond_get_text(char *table, char *column, char *condcolumn,
+ db_column_data_type condtype, void *condvalue)
+{
+ sqlite3_stmt *stmt = NULL;
+ char *query = NULL;
+ int ret = -1;
+
+ if (table == NULL) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return NULL;
+ }
+
+ if (column == NULL) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return NULL;
+ }
+ if (condcolumn == NULL) {
+ TRACE_ERROR("[CHECK Condition]");
+ return NULL;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("__dp_sql_open[%s]", sqlite3_errmsg(g_dp_db_handle));
+ return NULL;
+ }
+
+ query = sqlite3_mprintf("SELECT %s FROM %s WHERE %s IS ?",
+ column, table, condcolumn);
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE]");
+ return NULL;
+ }
+ ret = sqlite3_prepare_v2(g_dp_db_handle, query, -1, &stmt, NULL);
+ sqlite3_free(query);
+ if ( ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return NULL;
+ }
+
+ if (__dp_sql_bind_value(stmt, condtype, condvalue, 1) != SQLITE_OK) {
+ TRACE_ERROR
+ ("[BIND][%d][%s]", condtype, sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return NULL;
+ }
+ if (sqlite3_step(stmt) == SQLITE_ROW &&
+ sqlite3_column_type(stmt, 0) == SQLITE_TEXT) {
+ int getbytes = sqlite3_column_bytes(stmt, 0);
+ if (getbytes > 0) {
+ char *getstr = (char *)calloc(getbytes + 1, sizeof(char));
+ if (getstr != NULL) {
+ memcpy(getstr, sqlite3_column_text(stmt, 0),
+ getbytes * sizeof(char));
+ getstr[getbytes] = '\0';
+ }
+ __dp_finalize(stmt);
+ return getstr;
+ }
+ }
+ __dp_finalize(stmt);
+ return NULL;
+}
+
+int dp_db_cond_get_int(char *table, char *column, char *condcolumn,
+ db_column_data_type condtype, void *condvalue)
+{
+ sqlite3_stmt *stmt = NULL;
+ char *query = NULL;
+ int ret = -1;
+
+ if (table == NULL) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+
+ if (column == NULL) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+ if (condcolumn == NULL) {
+ TRACE_ERROR("[CHECK Condition]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("__dp_sql_open[%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ query = sqlite3_mprintf("SELECT %s FROM %s WHERE %s IS ?",
+ column, table, condcolumn);
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE]");
+ return -1;
+ }
+ ret = sqlite3_prepare_v2(g_dp_db_handle, query, -1, &stmt, NULL);
+ sqlite3_free(query);
+ if ( ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ if (__dp_sql_bind_value(stmt, condtype, condvalue, 1) != SQLITE_OK) {
+ TRACE_ERROR
+ ("[BIND][%d][%s]", condtype, sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ if (sqlite3_step(stmt) == SQLITE_ROW &&
+ sqlite3_column_type(stmt, 0) == SQLITE_INTEGER) {
+ int columnvalue = sqlite3_column_int(stmt, 0);
+ __dp_finalize(stmt);
+ return columnvalue;
+ }
+ __dp_finalize(stmt);
+ return -1;
+}
+
+int dp_db_get_cond_rows_count(int id, char *table,
+ char *condcolumn, db_column_data_type condtype,
+ void *condvalue)
+{
+ int errorcode = SQLITE_OK;
+ int ret = -1;
+ sqlite3_stmt *stmt = NULL;
+ char *query = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (!table) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("db_util_open is failed [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ if (condcolumn)
+ query =
+ sqlite3_mprintf
+ ("SELECT count(id) FROM %s WHERE id = ? AND %s = ?",
+ table, condcolumn);
+ else
+ query =
+ sqlite3_mprintf
+ ("SELECT count(id) FROM %s WHERE id = ?", table);
+
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE]");
+ return -1;
+ }
+
+ ret = sqlite3_prepare_v2(g_dp_db_handle, query, -1, &stmt, NULL);
+ sqlite3_free(query);
+ if (ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ if (condcolumn) {
+ if (condtype == DP_DB_COL_TYPE_INT) {
+ int *cast_value = condvalue;
+ errorcode = sqlite3_bind_int(stmt, 2, *cast_value);
+ } else if (condtype == DP_DB_COL_TYPE_INT64) {
+#ifdef SQLITE_INT64_TYPE
+ sqlite3_int64 *cast_value = condvalue;
+ errorcode = sqlite3_bind_int64(stmt, 2, *cast_value);
+#else
+ int *cast_value = condvalue;
+ errorcode = sqlite3_bind_int(stmt, 2, *cast_value);
+#endif
+ } else if (condtype == DP_DB_COL_TYPE_TEXT) {
+ errorcode = sqlite3_bind_text(stmt, 2, (char*)condvalue, -1, NULL);
+ } else {
+ TRACE_ERROR("[CHECK TYPE] Not Support [%d]", condtype);
+ __dp_finalize(stmt);
+ return -1;
+ }
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%d] [%s]",
+ condtype, sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ }
+
+ if (sqlite3_bind_int(stmt, 1, id)
+ != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_bind_int[%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_ROW) {
+ int count = sqlite3_column_int(stmt, 0);
+ __dp_finalize(stmt);
+ return count;
+ }
+ __dp_finalize(stmt);
+ return 0;
+}
+
+int dp_db_get_http_headers_list(int id, char **headers)
+{
+ int errorcode = SQLITE_OK;
+ int i = 0;
+ int headers_index = 0;
+ sqlite3_stmt *stmt = NULL;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("db_util_open is failed [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ errorcode =
+ sqlite3_prepare_v2(g_dp_db_handle,
+ "SELECT header_field, header_data FROM httpheaders WHERE id = ?",
+ -1, &stmt, NULL);
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_prepare_v2 is failed. [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_bind_int [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ while ((errorcode = sqlite3_step(stmt)) == SQLITE_ROW) {
+ int buffer_length = 0;
+ char *header_field = (char *)(sqlite3_column_text(stmt, 0));
+ char *header_data = (char *)(sqlite3_column_text(stmt, 1));
+ i++;
+ // REF : http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
+ buffer_length = strlen(header_field) + strlen(header_data) + 1;
+ char *headers_buffer = calloc(buffer_length + 1, sizeof(char));
+ if (headers_buffer == NULL) {
+ TRACE_ERROR("[CALLOC] headers_buffer");
+ continue;
+ }
+ int len = snprintf(headers_buffer, buffer_length + 1,
+ "%s:%s", header_field, header_data);
+ if (len <= 0) {
+ if (headers_buffer)
+ free(headers_buffer);
+ continue;
+ } else {
+ headers_buffer[len] = '\0';
+ }
+ headers[headers_index++] = headers_buffer;
+ }
+
+ __dp_finalize(stmt);
+ return headers_index;
+}
+
+static char *__merge_strings(char *dest, const char *src, char sep)
+{
+ int dest_length = 0;
+ int src_length = 0;
+ char *temp_dest = NULL;
+
+ if (dest == NULL || src == NULL)
+ return NULL;
+
+ dest_length = strlen(dest);
+ src_length = strlen(src);
+
+ temp_dest = sqlite3_realloc(dest, dest_length + src_length + 2);
+ if (temp_dest == NULL) {
+ free(dest);
+ return NULL;
+ }
+ temp_dest = strncat(temp_dest, &sep, 1);
+ temp_dest = strncat(temp_dest, src, src_length);
+ return temp_dest;
+}
+
+static char *__get_conds_query(int count, db_conds_list_fmt *conds, char *op)
+{
+ char *conditions = NULL;
+ int i = 0;
+
+ if (count > 0 && conds != NULL) {
+ conditions = sqlite3_mprintf("WHERE");
+ for (i = 0; i < count; i++) {
+ char *token =
+ sqlite3_mprintf("%s %s ?", conds[i].column,
+ (conds[i].is_like == 1 ? "LIKE" : "="));
+ if (token != NULL) {
+ conditions = __merge_strings(conditions, token, ' ');
+ sqlite3_free(token);
+ token = NULL;
+ }
+ if (i < count - 1 && op)
+ conditions = __merge_strings(conditions, op, ' ');
+ }
+ }
+ return conditions;
+}
+
+static int __bind_value(sqlite3_stmt *stmt,
+ db_column_data_type condtype, void *value, int index)
+{
+ int errorcode = SQLITE_ERROR;
+ int *cast_value = 0;
+
+ if (stmt == NULL)
+ return SQLITE_ERROR;
+
+ switch (condtype) {
+ case DP_DB_COL_TYPE_INT:
+ cast_value = value;
+ errorcode = sqlite3_bind_int(stmt, index, *cast_value);
+ break;
+ case DP_DB_COL_TYPE_INT64:
+#ifdef SQLITE_INT64_TYPE
+ sqlite3_int64 *cast_value = value;
+ errorcode = sqlite3_bind_int64(stmt, index, *cast_value);
+#else
+ cast_value = value;
+ errorcode = sqlite3_bind_int(stmt, index, *cast_value);
+#endif
+ break;
+ case DP_DB_COL_TYPE_TEXT:
+ errorcode =
+ sqlite3_bind_text(stmt, index, (char *)value, -1, SQLITE_STATIC);
+ break;
+ default:
+ errorcode = SQLITE_ERROR;
+ break;
+ }
+ return errorcode;
+}
+
+int dp_db_insert_columns(char *table, int column_count,
+ db_conds_list_fmt *columns)
+{
+ int errorcode = SQLITE_OK;
+ int ret = -1;
+ sqlite3_stmt *stmt = NULL;
+ char *query = NULL;
+ int i = 0;
+
+ if (table == NULL) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+ if (column_count <= 0) {
+ TRACE_ERROR("[CHECK db_conds_list_fmt count]");
+ return -1;
+ }
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[SQL HANDLE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ query =
+ sqlite3_mprintf("INSERT INTO %s ", table);
+ query = __merge_strings(query, columns[0].column, '(');
+ for (i = 1; i < column_count; i++) {
+ char *column_query = NULL;
+ column_query = sqlite3_mprintf(", %s", columns[i].column);
+ query = __merge_strings(query, column_query, ' ');
+ sqlite3_free(column_query);
+ }
+ query = __merge_strings(query, " VALUES ", ')');
+ query = __merge_strings(query, "?", '(');
+ for (i = 1; i < column_count; i++) {
+ query = __merge_strings(query, ", ?", ' ');
+ }
+ query = __merge_strings(query, ")", ' ');
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE]");
+ return -1;
+ }
+ TRACE_DEBUG("query:%s", query);
+
+ ret = sqlite3_prepare_v2(g_dp_db_handle, query, -1, &stmt, NULL);
+ sqlite3_free(query);
+ if ( ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ for (i = 0; i < column_count; i++) {
+ if (__bind_value
+ (stmt, columns[i].type, columns[i].value, (i + 1)) !=
+ SQLITE_OK) {
+ TRACE_ERROR("[BIND][%d][%s]", columns[i].type,
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ }
+
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ __dp_finalize(stmt);
+ return 0;
+ }
+ TRACE_ERROR("[SQL] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+}
+
+int dp_db_update_columns(int id, char *table, int column_count,
+ db_conds_list_fmt *columns)
+{
+ int errorcode = SQLITE_OK;
+ int ret = -1;
+ sqlite3_stmt *stmt = NULL;
+ char *query = NULL;
+ int i = 0;
+
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+ if (table == NULL) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+ if (column_count <= 0) {
+ TRACE_ERROR("[CHECK db_conds_list_fmt count]");
+ return -1;
+ }
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[SQL HANDLE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ query =
+ sqlite3_mprintf("UPDATE %s SET %s = ?", table, columns[0].column);
+ for (i = 1; i < column_count; i++) {
+ char *column_query = NULL;
+ column_query = sqlite3_mprintf("%s = ?", columns[i].column);
+ query = __merge_strings(query, column_query, ',');
+ sqlite3_free(column_query);
+ }
+ query = __merge_strings(query, "WHERE id = ?", ' ');
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE]");
+ return -1;
+ }
+ TRACE_DEBUG("query:%s", query);
+
+ ret = sqlite3_prepare_v2(g_dp_db_handle, query, -1, &stmt, NULL);
+ sqlite3_free(query);
+ if ( ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ for (i = 0; i < column_count; i++) {
+ if (__bind_value
+ (stmt, columns[i].type, columns[i].value, (i + 1)) !=
+ SQLITE_OK) {
+ TRACE_ERROR("[BIND][%d][%s]", columns[i].type,
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ }
+ if (sqlite3_bind_int(stmt, column_count + 1, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] ID [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ __dp_finalize(stmt);
+ return 0;
+ }
+ TRACE_ERROR("[SQL] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+}
+
+int dp_db_get_conds_rows_count(char *table,
+ char *getcolumn, char *op,
+ int conds_count, db_conds_list_fmt *conds)
+{
+ int errorcode = SQLITE_OK;
+ int ret = -1;
+ sqlite3_stmt *stmt = NULL;
+ char *query = NULL;
+ int i = 0;
+
+ if (table == NULL) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+ if (getcolumn == NULL) {
+ TRACE_ERROR("[CHECK RESULT COLUMN]");
+ return -1;
+ }
+ if (op == NULL) {
+ TRACE_ERROR("[CHECK OPERATOR] AND or OR");
+ return -1;
+ }
+ if (conds_count <= 0) {
+ TRACE_ERROR("[CHECK db_conds_list_fmt count]");
+ return -1;
+ }
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[SQL HANDLE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ query =
+ sqlite3_mprintf("SELECT count(%s) FROM %s", getcolumn, table);
+
+ char *conditions = __get_conds_query(conds_count, conds, op);
+ if (conditions != NULL) {
+ query = __merge_strings(query, conditions, ' ');
+ sqlite3_free(conditions);
+ }
+
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE]");
+ return -1;
+ }
+
+ ret = sqlite3_prepare_v2(g_dp_db_handle, query, -1, &stmt, NULL);
+ sqlite3_free(query);
+ if (ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ for (i = 0; i < conds_count; i++) {
+ if (__bind_value
+ (stmt, conds[i].type, conds[i].value, (i + 1)) !=
+ SQLITE_OK) {
+ TRACE_ERROR("[BIND][%d][%s]", conds[i].type,
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ }
+ errorcode = sqlite3_step(stmt);
+ if (errorcode == SQLITE_ROW) {
+ int count = sqlite3_column_int(stmt, 0);
+ __dp_finalize(stmt);
+ return count;
+ }
+ __dp_finalize(stmt);
+ return 0;
+}
+
+int dp_db_get_conds_list(char *table, char *getcolumn,
+ db_column_data_type gettype, void **list,
+ int rowslimit, int rowsoffset,
+ char *ordercolumn, char *ordering,
+ char *op, int conds_count,
+ db_conds_list_fmt *conds)
+{
+ int errorcode = SQLITE_OK;
+ int rows_count = 0;
+ sqlite3_stmt *stmt = NULL;
+ int i = 0;
+
+ if (table == NULL) {
+ TRACE_ERROR("[CHECK TABLE NAME]");
+ return -1;
+ }
+ if (op == NULL) {
+ TRACE_ERROR("[CHECK OPERATOR] AND or OR");
+ return -1;
+ }
+ if (getcolumn == NULL) {
+ TRACE_ERROR("[CHECK COLUMN NAME]");
+ return -1;
+ }
+ if (conds_count <= 0) {
+ TRACE_ERROR("[CHECK db_conds_list_fmt count]");
+ return -1;
+ }
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[SQL HANDLE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ char *limit = NULL;
+ char *order = NULL;
+ char *query = sqlite3_mprintf("SELECT %s FROM %s", getcolumn, table);
+ char *conditions = __get_conds_query(conds_count, conds, op);
+ if (conditions != NULL) {
+ query = __merge_strings(query, conditions, ' ');
+ sqlite3_free(conditions);
+ }
+
+ if (ordercolumn != NULL) {
+ order =
+ sqlite3_mprintf
+ ("ORDER BY %s %s", ordercolumn,
+ (ordering == NULL ? "ASC" : ordering));
+ if (order != NULL) {
+ query = __merge_strings(query, order, ' ');
+ sqlite3_free(order);
+ }
+ }
+ if (rowslimit > 0) { // 0 or negative : no limitation
+ if (rowsoffset >= 0)
+ limit =
+ sqlite3_mprintf("LIMIT %d OFFSET %d", rowslimit,
+ rowsoffset);
+ else
+ limit = sqlite3_mprintf("LIMIT %d", rowslimit);
+ if (limit != NULL) {
+ query = __merge_strings(query, limit, ' ');
+ sqlite3_free(limit);
+ }
+ }
+
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE]");
+ return -1;
+ }
+
+ errorcode =
+ sqlite3_prepare_v2(g_dp_db_handle, query, -1, &stmt, NULL);
+ sqlite3_free(query);
+ if (errorcode != SQLITE_OK) {
+ TRACE_ERROR("sqlite3_prepare_v2 is failed. [%s]",
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ for (i = 0; i < conds_count; i++) {
+ if (__bind_value
+ (stmt, conds[i].type, conds[i].value, (i + 1)) !=
+ SQLITE_OK) {
+ TRACE_ERROR
+ ("[BIND][%d][%s]", conds[i].type,
+ sqlite3_errmsg(g_dp_db_handle));
+ __dp_finalize(stmt);
+ return -1;
+ }
+ }
+ while ((errorcode = sqlite3_step(stmt)) == SQLITE_ROW) {
+ switch (gettype) {
+ case DP_DB_COL_TYPE_INT:
+ {
+ int **list_int_p = (int **)list;
+ *list_int_p[rows_count++] = sqlite3_column_int(stmt, 0);
+ break;
+ }
+ case DP_DB_COL_TYPE_INT64:
+ {
+#ifdef SQLITE_INT64_TYPE
+ long long **list_long_p = (long long **)list;
+ *list_long_p[rows_count++] = sqlite3_column_int64(stmt, 0);
+#else
+ int **list_int_p = (int **)list;
+ *list_int_p[rows_count++] = sqlite3_column_int(stmt, 0);
+#endif
+ break;
+ }
+ case DP_DB_COL_TYPE_TEXT:
+ {
+ int getbytes = sqlite3_column_bytes(stmt, 0);
+ if (getbytes > 0) {
+ char *getstr = (char *)calloc((getbytes + 1), sizeof(char));
+ if (getstr != NULL) {
+ memcpy(getstr, sqlite3_column_text(stmt, 0),
+ getbytes * sizeof(char));
+ getstr[getbytes] = '\0';
+ list[rows_count++] = getstr;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (rows_count >= rowslimit)
+ break;
+ }
+ __dp_finalize(stmt);
+ return rows_count;
+}
+
+static void __dp_db_reset(sqlite3_stmt *stmt)
+{
+ if (stmt != 0) {
+ sqlite3_clear_bindings(stmt);
+ if (sqlite3_reset(stmt) != SQLITE_OK) {
+ sqlite3 *handle = sqlite3_db_handle(stmt);
+ TRACE_ERROR("failed sqlite3_reset [%s]",
+ sqlite3_errmsg(handle));
+ }
+ }
+}
+
+int dp_db_request_new_logging(const int id, const int state, const char *pkgname)
+{
+ int errorcode = SQLITE_OK;
+ int ret = -1;
+ char *query = NULL;
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[SQL HANDLE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ if (g_dp_db_logging_new_stmt == NULL) {
+ query =
+ sqlite3_mprintf("INSERT INTO %s (%s, %s, %s, %s) VALUES (?, ?, ?, DATETIME('now'))",
+ DP_DB_TABLE_LOG, DP_DB_COL_ID, DP_DB_COL_STATE,
+ DP_DB_COL_PACKAGENAME, DP_DB_COL_CREATE_TIME);
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE]");
+ return -1;
+ }
+
+ TRACE_DEBUG("query:%s", query);
+
+ ret = sqlite3_prepare_v2(g_dp_db_handle, query, -1, &g_dp_db_logging_new_stmt, NULL);
+ sqlite3_free(query);
+ if (ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+ }
+ if (sqlite3_bind_int(g_dp_db_logging_new_stmt, 1, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_db_reset(g_dp_db_logging_new_stmt);
+ return -1;
+ }
+ if (sqlite3_bind_int(g_dp_db_logging_new_stmt, 2, state) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_db_reset(g_dp_db_logging_new_stmt);
+ return -1;
+ }
+ if (sqlite3_bind_text(g_dp_db_logging_new_stmt, 3, pkgname, -1, SQLITE_STATIC) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_db_reset(g_dp_db_logging_new_stmt);
+ return -1;
+ }
+
+ errorcode = sqlite3_step(g_dp_db_logging_new_stmt);
+ __dp_db_reset(g_dp_db_logging_new_stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ return 0;
+ }
+ return -1;
+}
+
+int dp_db_request_update_status(const int id, const int state, const int download_error)
+{
+ int errorcode = SQLITE_OK;
+ int ret = -1;
+ char *query = NULL;
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[SQL HANDLE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ if (g_dp_db_logging_status_stmt == NULL) {
+ query =
+ sqlite3_mprintf("UPDATE %s SET %s = ?, %s = ?, %s = DATETIME('now') WHERE %s = ?",
+ DP_DB_TABLE_LOG, DP_DB_COL_STATE, DP_DB_COL_ERRORCODE,
+ DP_DB_COL_ACCESS_TIME, DP_DB_COL_ID);
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE]");
+ return -1;
+ }
+
+ TRACE_DEBUG("query:%s", query);
+
+ ret = sqlite3_prepare_v2(g_dp_db_handle, query, -1, &g_dp_db_logging_status_stmt, NULL);
+ sqlite3_free(query);
+ if (ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+ }
+ if (sqlite3_bind_int(g_dp_db_logging_status_stmt, 1, state) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_db_reset(g_dp_db_logging_status_stmt);
+ return -1;
+ }
+ if (sqlite3_bind_int(g_dp_db_logging_status_stmt, 2, download_error) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_db_reset(g_dp_db_logging_status_stmt);
+ return -1;
+ }
+ if (sqlite3_bind_int(g_dp_db_logging_status_stmt, 3, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_db_reset(g_dp_db_logging_status_stmt);
+ return -1;
+ }
+
+ errorcode = sqlite3_step(g_dp_db_logging_status_stmt);
+ __dp_db_reset(g_dp_db_logging_status_stmt);
+ if (errorcode == SQLITE_OK || errorcode == SQLITE_DONE) {
+ return 0;
+ }
+ return -1;
+}
+
+int dp_db_get_state(int id)
+{
+ if (id <= 0) {
+ TRACE_ERROR("[CHECK ID]");
+ return -1;
+ }
+
+ if (__dp_sql_open() < 0) {
+ TRACE_ERROR("[OPEN] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+
+ if (g_dp_db_logging_get_state_stmt == NULL) {
+ char *query = sqlite3_mprintf("SELECT %s FROM %s WHERE %s = ?",
+ DP_DB_COL_STATE, DP_DB_TABLE_LOG, DP_DB_COL_ID);
+ if (query == NULL) {
+ TRACE_ERROR("[CHECK COMBINE]");
+ return -1;
+ }
+
+ TRACE_DEBUG("query:%s", query);
+
+ int ret = sqlite3_prepare_v2(g_dp_db_handle, query, -1, &g_dp_db_logging_get_state_stmt, NULL);
+ sqlite3_free(query);
+ if (ret != SQLITE_OK) {
+ TRACE_ERROR("[PREPARE] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ return -1;
+ }
+ }
+
+ if (sqlite3_bind_int(g_dp_db_logging_get_state_stmt, 1, id) != SQLITE_OK) {
+ TRACE_ERROR("[BIND] [%s]", sqlite3_errmsg(g_dp_db_handle));
+ __dp_db_reset(g_dp_db_logging_get_state_stmt);
+ return -1;
+ }
+
+ int state = DP_STATE_NONE;
+ if (sqlite3_step(g_dp_db_logging_get_state_stmt) == SQLITE_ROW) {
+ state = sqlite3_column_int(g_dp_db_logging_get_state_stmt, 0);
+ }
+ __dp_db_reset(g_dp_db_logging_get_state_stmt);
+ return state;
+}
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);
+}
diff --git a/provider/download-provider-network.c b/provider/download-provider-network.c
new file mode 100755
index 0000000..ac3fc5b
--- /dev/null
+++ b/provider/download-provider-network.c
@@ -0,0 +1,397 @@
+/*
+ * 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 "download-provider-log.h"
+#include "download-provider-config.h"
+#include "download-provider-pthread.h"
+#include "download-provider-network.h"
+
+#ifdef SUPPORT_WIFI_DIRECT
+#include <wifi-direct.h>
+#endif
+
+extern pthread_mutex_t g_dp_queue_mutex;
+extern pthread_cond_t g_dp_queue_cond;
+
+#if 0
+typedef enum
+{
+ CONNECTION_TYPE_DISCONNECTED = 0, /**< Disconnected */
+ CONNECTION_TYPE_WIFI = 1, /**< Wi-Fi type */
+ CONNECTION_TYPE_CELLULAR = 2, /**< Cellular type */
+ CONNECTION_TYPE_ETHERNET = 3, /**< Ethernet type */
+ CONNECTION_TYPE_BT = 4, /**< Bluetooth type */
+} connection_type_e;
+typedef enum
+{
+ CONNECTION_CELLULAR_STATE_OUT_OF_SERVICE = 0, /**< Out of service */
+ CONNECTION_CELLULAR_STATE_FLIGHT_MODE = 1, /**< Flight mode */
+ CONNECTION_CELLULAR_STATE_ROAMING_OFF = 2, /**< Roaming is turned off */
+ CONNECTION_CELLULAR_STATE_CALL_ONLY_AVAILABLE = 3, /**< Call is only available */
+ CONNECTION_CELLULAR_STATE_AVAILABLE = 4, /**< Available but not connected yet */
+ CONNECTION_CELLULAR_STATE_CONNECTED = 5, /**< Connected */
+} connection_cellular_state_e
+typedef enum
+{
+ CONNECTION_WIFI_STATE_DEACTIVATED = 0, /**< Deactivated state */
+ CONNECTION_WIFI_STATE_DISCONNECTED = 1, /**< disconnected state */
+ CONNECTION_WIFI_STATE_CONNECTED = 2, /**< Connected state */
+} connection_wifi_state_e;
+typedef enum
+{
+ CONNECTION_ETHERNET_STATE_DEACTIVATED = 0, /**< Deactivated state */
+ CONNECTION_ETHERNET_STATE_DISCONNECTED = 1, /**< disconnected state */
+ CONNECTION_ETHERNET_STATE_CONNECTED = 2, /**< Connected state */
+} connection_ethernet_state_e;
+typedef enum
+{
+ CONNECTION_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
+ CONNECTION_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+ CONNECTION_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory error */
+ CONNECTION_ERROR_INVALID_OPERATION = TIZEN_ERROR_INVALID_OPERATION, /**< Invalid Operation */
+ CONNECTION_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED = TIZEN_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED, /**< Address family not supported */
+ CONNECTION_ERROR_OPERATION_FAILED = TIZEN_ERROR_NETWORK_CLASS|0x0401, /**< Operation failed */
+ CONNECTION_ERROR_ITERATOR_END = TIZEN_ERROR_NETWORK_CLASS|0x0402, /**< End of iteration */
+ CONNECTION_ERROR_NO_CONNECTION = TIZEN_ERROR_NETWORK_CLASS|0x0403, /**< There is no connection */
+ CONNECTION_ERROR_NOW_IN_PROGRESS = TIZEN_ERROR_NOW_IN_PROGRESS, /** Now in progress */
+ CONNECTION_ERROR_ALREADY_EXISTS = TIZEN_ERROR_NETWORK_CLASS|0x0404, /**< Already exists */
+ CONNECTION_ERROR_OPERATION_ABORTED = TIZEN_ERROR_NETWORK_CLASS|0x0405, /**< Operation is aborted */
+ CONNECTION_ERROR_DHCP_FAILED = TIZEN_ERROR_NETWORK_CLASS|0x0406, /**< DHCP failed */
+ CONNECTION_ERROR_INVALID_KEY = TIZEN_ERROR_NETWORK_CLASS|0x0407, /**< Invalid key */
+ CONNECTION_ERROR_NO_REPLY = TIZEN_ERROR_NETWORK_CLASS|0x0408, /**< No reply */
+} connection_error_e;
+
+
+static void __print_connection_errorcode_to_string(connection_error_e errorcode)
+{
+ switch(errorcode)
+ {
+ case CONNECTION_ERROR_INVALID_PARAMETER :
+ TRACE_DEBUG("CONNECTION_ERROR_INVALID_PARAMETER");
+ break;
+ case CONNECTION_ERROR_OUT_OF_MEMORY :
+ TRACE_DEBUG("CONNECTION_ERROR_OUT_OF_MEMORY");
+ break;
+ case CONNECTION_ERROR_INVALID_OPERATION :
+ TRACE_DEBUG("CONNECTION_ERROR_INVALID_OPERATION");
+ break;
+ case CONNECTION_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED :
+ TRACE_DEBUG("CONNECTION_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED");
+ break;
+ case CONNECTION_ERROR_OPERATION_FAILED :
+ TRACE_DEBUG("CONNECTION_ERROR_OPERATION_FAILED");
+ break;
+ case CONNECTION_ERROR_ITERATOR_END :
+ TRACE_DEBUG("CONNECTION_ERROR_ITERATOR_END");
+ break;
+ case CONNECTION_ERROR_NO_CONNECTION :
+ TRACE_DEBUG("CONNECTION_ERROR_NO_CONNECTION");
+ break;
+ case CONNECTION_ERROR_NOW_IN_PROGRESS :
+ TRACE_DEBUG("CONNECTION_ERROR_NOW_IN_PROGRESS");
+ break;
+ case CONNECTION_ERROR_ALREADY_EXISTS :
+ TRACE_DEBUG("CONNECTION_ERROR_ALREADY_EXISTS");
+ break;
+ case CONNECTION_ERROR_OPERATION_ABORTED :
+ TRACE_DEBUG("CONNECTION_ERROR_OPERATION_ABORTED");
+ break;
+ case CONNECTION_ERROR_DHCP_FAILED :
+ TRACE_DEBUG("CONNECTION_ERROR_DHCP_FAILED");
+ break;
+ case CONNECTION_ERROR_INVALID_KEY :
+ TRACE_DEBUG("CONNECTION_ERROR_INVALID_KEY");
+ break;
+ case CONNECTION_ERROR_NO_REPLY :
+ TRACE_DEBUG("CONNECTION_ERROR_NO_REPLY");
+ break;
+ default :
+ TRACE_DEBUG("CONNECTION_ERROR_NONE");
+ break;
+ }
+}
+#endif
+
+
+#ifdef SUPPORT_WIFI_DIRECT
+// support WIFI-Direct
+static void __dp_network_wifi_direct_connection_state_changed_cb(wifi_direct_error_e error_code, wifi_direct_connection_state_e connection_state, const char *mac_address, void *data)
+{
+ dp_privates *privates = (dp_privates*)data;
+ if (privates == NULL) {
+ TRACE_ERROR("[CRITICAL] Invalid data");
+ return ;
+ }
+
+ if (connection_state == WIFI_DIRECT_CONNECTION_RSP) {
+ TRACE_DEBUG("WIFI_DIRECT_CONNECTION_RSP");
+ privates->is_connected_wifi_direct = 1;
+ return ;
+ }
+ privates->is_connected_wifi_direct = 0;
+}
+
+//return 0 : connected
+int dp_network_wifi_direct_is_connected()
+{
+ int is_connected = -1;
+ wifi_direct_state_e wifi_state = WIFI_DIRECT_STATE_DEACTIVATED;
+ if (wifi_direct_get_state(&wifi_state) == 0) {
+ switch (wifi_state)
+ {
+ case WIFI_DIRECT_STATE_DEACTIVATED :
+ TRACE_DEBUG("WIFI_DIRECT_STATE_DEACTIVATED");
+ break;
+ case WIFI_DIRECT_STATE_DEACTIVATING :
+ TRACE_DEBUG("WIFI_DIRECT_STATE_DEACTIVATING");
+ break;
+ case WIFI_DIRECT_STATE_ACTIVATING :
+ TRACE_DEBUG("WIFI_DIRECT_STATE_ACTIVATING");
+ break;
+ case WIFI_DIRECT_STATE_ACTIVATED :
+ TRACE_DEBUG("WIFI_DIRECT_STATE_ACTIVATED");
+ break;
+ case WIFI_DIRECT_STATE_DISCOVERING :
+ TRACE_DEBUG("WIFI_DIRECT_STATE_DISCOVERING");
+ break;
+ case WIFI_DIRECT_STATE_CONNECTING :
+ TRACE_DEBUG("WIFI_DIRECT_STATE_CONNECTING");
+ break;
+ case WIFI_DIRECT_STATE_DISCONNECTING :
+ TRACE_DEBUG("WIFI_DIRECT_STATE_DISCONNECTING");
+ break;
+ case WIFI_DIRECT_STATE_CONNECTED :
+ is_connected = 0;
+ TRACE_DEBUG("WIFI_DIRECT_STATE_CONNECTED");
+ break;
+ default :
+ break;
+ }
+ }
+ return is_connected;
+}
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief check the status in more detail by connection type
+/// @return dp_network_type
+static dp_network_type __dp_get_network_connection_status(connection_h connection, connection_type_e type)
+{
+ dp_network_type network_type = DP_NETWORK_TYPE_OFF;
+ if (type == CONNECTION_TYPE_WIFI) {
+ connection_wifi_state_e wifi_state;
+ wifi_state = CONNECTION_WIFI_STATE_DEACTIVATED;
+ if (connection_get_wifi_state
+ (connection, &wifi_state) != CONNECTION_ERROR_NONE)
+ TRACE_ERROR("Failed connection_get_wifi_state");
+ if (wifi_state == CONNECTION_WIFI_STATE_CONNECTED) {
+ TRACE_DEBUG("[CONNECTION_WIFI] CONNECTED");
+ network_type = DP_NETWORK_TYPE_WIFI;
+ } else {
+ TRACE_DEBUG("[CONNECTION_WIFI] [%d]", wifi_state);
+ }
+ } else if (type == CONNECTION_TYPE_CELLULAR) {
+ connection_cellular_state_e cellular_state;
+ cellular_state = CONNECTION_CELLULAR_STATE_OUT_OF_SERVICE;
+ if (connection_get_cellular_state
+ (connection, &cellular_state) != CONNECTION_ERROR_NONE)
+ TRACE_ERROR("Failed connection_get_cellular_state");
+ if (cellular_state == CONNECTION_CELLULAR_STATE_CONNECTED) {
+ TRACE_DEBUG("[CONNECTION_CELLULAR] DATA NETWORK CONNECTED");
+ network_type = DP_NETWORK_TYPE_DATA_NETWORK;
+ } else {
+ TRACE_DEBUG("[CONNECTION_CELLULAR] [%d]", cellular_state);
+ }
+ } else if (type == CONNECTION_TYPE_ETHERNET) {
+ connection_ethernet_state_e ethernet_state;
+ ethernet_state = CONNECTION_ETHERNET_STATE_DISCONNECTED;
+ if (connection_get_ethernet_state
+ (connection, &ethernet_state) != CONNECTION_ERROR_NONE)
+ TRACE_ERROR("Failed connection_get_ethernet_state");
+ if (ethernet_state == CONNECTION_ETHERNET_STATE_CONNECTED) {
+ TRACE_DEBUG("[CONNECTION_ETHERNET] ETHERNET CONNECTED");
+ network_type = DP_NETWORK_TYPE_ETHERNET;
+ } else {
+ TRACE_DEBUG("[CONNECTION_ETHERNET] [%d]", ethernet_state);
+ }
+ } else {
+ TRACE_DEBUG("[DISCONNECTED]");
+ network_type = DP_NETWORK_TYPE_OFF;
+ }
+ return network_type;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief [callback] called whenever changed network status
+/// @todo care requests by network status
+static void __dp_network_connection_type_changed_cb(connection_type_e type, void *data)
+{
+ dp_privates *privates = (dp_privates*)data;
+ if (privates == NULL) {
+ TRACE_ERROR("[CRITICAL] Invalid data");
+ return ;
+ }
+ CLIENT_MUTEX_LOCK(&(g_dp_queue_mutex));
+ #if 1 // this callback guarantee that already connectdd
+ if (type == CONNECTION_TYPE_WIFI) {
+ TRACE_DEBUG("[CONNECTION_WIFI] CONNECTED");
+ privates->network_status = DP_NETWORK_TYPE_WIFI;
+ } else if (type == CONNECTION_TYPE_CELLULAR) {
+ TRACE_DEBUG("[CONNECTION_CELLULAR] DATA NETWORK CONNECTED");
+ privates->network_status = DP_NETWORK_TYPE_DATA_NETWORK;
+ } else if (type == CONNECTION_TYPE_ETHERNET) {
+ TRACE_DEBUG("[CONNECTION_ETHERNET] ETHERNET CONNECTED");
+ privates->network_status = DP_NETWORK_TYPE_ETHERNET;
+ } else {
+ TRACE_DEBUG("[DISCONNECTED]");
+ privates->network_status = DP_NETWORK_TYPE_OFF;
+ }
+ if (privates->network_status != DP_NETWORK_TYPE_OFF)
+ pthread_cond_signal(&g_dp_queue_cond);
+ #else
+ privates->network_status =
+ __dp_get_network_connection_status(privates->connection, type);
+ #endif
+ CLIENT_MUTEX_UNLOCK(&(g_dp_queue_mutex));
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief [callback] called when changed network ip
+/// @todo auto resume feature
+static void __dp_network_connection_ip_changed_cb(const char *ip, const char *ipv6, void *data)
+{
+ dp_privates *privates = (dp_privates*)data;
+ if (privates == NULL) {
+ TRACE_ERROR("[CRITICAL] Invalid data");
+ return ;
+ }
+ if (privates->network_status != DP_NETWORK_TYPE_OFF) {
+ dp_request_slots *requests = privates->requests;
+ int i = 0;
+ for (i = 0; i < DP_MAX_REQUEST; i++) {
+ int locked = pthread_mutex_trylock(&requests[i].mutex);
+ // locking failure means it used by other thread.
+ if (locked == 0) {
+ if (requests[i].request != NULL) {
+ if (requests[i].request->state == DP_STATE_DOWNLOADING ||
+ (requests[i].request->state == DP_STATE_FAILED &&
+ requests[i].request->error == DP_ERROR_CONNECTION_FAILED)) {
+ requests[i].request->ip_changed = 1;
+ }
+ }
+ CLIENT_MUTEX_UNLOCK(&requests[i].mutex);
+ }
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief create connection handle & regist callback
+/// @return 0 : success -1 : failed
+int dp_network_connection_init(dp_privates *privates)
+{
+ int retcode = 0;
+
+ if (!privates) {
+ TRACE_ERROR("[CRITICAL] Invalid data");
+ return -1;
+ }
+
+#ifdef SUPPORT_WIFI_DIRECT
+ if (wifi_direct_initialize() == 0) {
+ wifi_direct_set_connection_state_changed_cb
+ (__dp_network_wifi_direct_connection_state_changed_cb, privates);
+ if (dp_network_wifi_direct_is_connected() == 0)
+ privates->is_connected_wifi_direct = 1;
+ }
+#endif
+
+ if ((retcode = connection_create(&privates->connection)) !=
+ CONNECTION_ERROR_NONE) {
+ TRACE_ERROR("Failed connection_create [%d]", retcode);
+ return -1;
+ }
+ if ((retcode = connection_set_type_changed_cb
+ (privates->connection, __dp_network_connection_type_changed_cb,
+ privates)) != CONNECTION_ERROR_NONE) {
+ TRACE_ERROR("Failed connection_set_type_changed_cb [%d]", retcode);
+ connection_destroy(privates->connection);
+ return -1;
+ }
+ if ((retcode = connection_set_ip_address_changed_cb
+ (privates->connection, __dp_network_connection_ip_changed_cb,
+ privates)) != CONNECTION_ERROR_NONE) {
+ TRACE_ERROR("Failed __dp_network_connection_ip_changed_cb [%d]", retcode);
+ connection_destroy(privates->connection);
+ return -1;
+ }
+ connection_type_e type = CONNECTION_TYPE_DISCONNECTED;
+ if ((retcode = connection_get_type(privates->connection, &type)) !=
+ CONNECTION_ERROR_NONE) {
+ TRACE_ERROR("Failed connection_get_type [%d]", retcode);
+ connection_destroy(privates->connection);
+ return -1;
+ }
+ privates->network_status =
+ __dp_get_network_connection_status(privates->connection, type);
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief destroy connection handle
+void dp_network_connection_destroy(connection_h connection)
+{
+#ifdef SUPPORT_WIFI_DIRECT
+ wifi_direct_unset_connection_state_changed_cb();
+ wifi_direct_deinitialize();
+#endif
+
+ connection_unset_type_changed_cb(connection);
+ connection_unset_ip_address_changed_cb(connection);
+ connection_destroy(connection);
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief check network status using connection API
+/// @todo the standard of enabled networking can be changed later
+/// @return Network type
+dp_network_type dp_get_network_connection_instant_status()
+{
+ int retcode = 0;
+ connection_h network_handle = NULL;
+ dp_network_type network_type = DP_NETWORK_TYPE_OFF;
+ if ((retcode = connection_create(&network_handle)) !=
+ CONNECTION_ERROR_NONE) {
+ TRACE_ERROR("Failed connection_create [%d]", retcode);
+ return DP_NETWORK_TYPE_OFF;
+ }
+
+ connection_type_e type = CONNECTION_TYPE_DISCONNECTED;
+ if ((retcode = connection_get_type(network_handle, &type)) !=
+ CONNECTION_ERROR_NONE) {
+ TRACE_ERROR("Failed connection_get_type [%d]", retcode);
+ connection_destroy(network_handle);
+ return DP_NETWORK_TYPE_OFF;
+ }
+ network_type =
+ __dp_get_network_connection_status(network_handle, type);
+
+ if (connection_destroy(network_handle) != CONNECTION_ERROR_NONE)
+ TRACE_ERROR("Failed connection_destroy");
+
+ return network_type;
+}
diff --git a/provider/download-provider-notification.c b/provider/download-provider-notification.c
new file mode 100755
index 0000000..f6e2f8b
--- /dev/null
+++ b/provider/download-provider-notification.c
@@ -0,0 +1,616 @@
+/*
+ * 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 <time.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "bundle.h"
+#include "notification.h"
+#include "appsvc.h"
+
+#include "download-provider-defs.h"
+
+#include "download-provider-notification.h"
+#include "download-provider-request.h"
+#include "download-provider-db.h"
+#include "download-provider-log.h"
+
+#include <libintl.h>
+#define S_(s) dgettext("sys_string", s)
+#define __(s) dgettext(PKG_NAME, s)
+
+#define DP_NOTIFICATION_ICON_PATH IMAGE_DIR"/Q02_Notification_download_complete.png"
+#define DP_NOTIFICATION_ONGOING_ICON_PATH IMAGE_DIR"/Notification_download_animation.gif"
+#define DP_NOTIFICATION_DOWNLOADING_ICON_PATH "reserved://indicator/ani/downloading"
+#define DP_NOTIFICATION_FAILED_ICON_PATH IMAGE_DIR"/Q02_Notification_download_failed.png"
+
+static const char *__noti_error_str(
+ notification_error_e err)
+{
+ switch (err) {
+ case NOTIFICATION_ERROR_INVALID_DATA:
+ return "NOTIFICATION_ERROR_INVALID_DATA";
+ case NOTIFICATION_ERROR_NO_MEMORY:
+ return "NOTIFICATION_ERROR_NO_MEMORY";
+ case NOTIFICATION_ERROR_FROM_DB:
+ return "NOTIFICATION_ERROR_FROM_DB";
+ case NOTIFICATION_ERROR_ALREADY_EXIST_ID:
+ return "NOTIFICATION_ERROR_ALREADY_EXIST_ID";
+ case NOTIFICATION_ERROR_FROM_DBUS:
+ return "NOTIFICATION_ERROR_FROM_DBUS";
+ case NOTIFICATION_ERROR_NOT_EXIST_ID:
+ return "NOTIFICATION_ERROR_NOT_EXIST_ID";
+ default:
+ break;
+ }
+ return "Unknown error";
+}
+
+static char *__get_string_sender(char *url)
+{
+ char *temp = NULL;
+ char *found = NULL;
+ char *found1 = NULL;
+ char *sender = NULL;
+ char *credential_sender = NULL;
+
+ if (url == NULL)
+ return NULL;
+
+ found = strstr(url, "://");
+ if (found) {
+ temp = found + 3;
+ } else {
+ temp = url;
+ }
+ found = strchr(temp, '/');
+ if (found) {
+ int len = 0;
+ len = found - temp;
+ sender = calloc(len + 1, sizeof(char));
+ if (sender == NULL)
+ return NULL;
+ snprintf(sender, len + 1, "%s", temp);
+ } else {
+ sender = dp_strdup(temp);
+ }
+
+ // For credential URL
+ found = strchr(sender, '@');
+ found1 = strchr(sender, ':');
+ if (found && found1 && found1 < found) {
+ int len = 0;
+ found = found + 1;
+ len = strlen(found);
+ credential_sender = calloc(len + 1, sizeof(char));
+ if (credential_sender == NULL) {
+ free(sender);
+ return NULL;
+ }
+ snprintf(credential_sender, len + 1, "%s", found);
+ free(sender);
+ return credential_sender;
+ } else {
+ return sender;
+ }
+}
+
+static char *__get_string_size(long long file_size)
+{
+ const char *unitStr[4] = {"B", "KB", "MB", "GB"};
+ double doubleTypeBytes = 0.0;
+ int unit = 0;
+ long long bytes = file_size;
+ long long unitBytes = bytes;
+ char *temp = NULL;
+
+ /* using bit operation to avoid floating point arithmetic */
+ for (unit = 0; (unitBytes > 1024 && unit < 4); unit++) {
+ unitBytes = unitBytes >> 10;
+ }
+ unitBytes = 1 << (10 * unit);
+
+ if (unit > 3)
+ unit = 3;
+
+ char str[64] = {0};
+ if (unit == 0) {
+ snprintf(str, sizeof(str), "%lld %s", bytes, unitStr[unit]);
+ } else {
+ doubleTypeBytes = ((double)bytes / (double)unitBytes);
+ snprintf(str, sizeof(str), "%.2f %s", doubleTypeBytes, unitStr[unit]);
+ }
+
+ str[63] = '\0';
+ temp = dp_strdup(str);
+ return temp;
+}
+
+static char *__get_string_status(dp_state_type state)
+{
+ char *message = NULL;
+ switch (state) {
+ case DP_STATE_COMPLETED:
+ message = __("IDS_DM_HEADER_DOWNLOAD_COMPLETE");
+ break;
+ case DP_STATE_CANCELED:
+ case DP_STATE_FAILED:
+ message = S_("IDS_COM_POP_DOWNLOAD_FAILED");
+ break;
+ default:
+ break;
+ }
+ return message;
+}
+
+int dp_set_downloadinginfo_notification(int id, char *packagename)
+{
+ notification_h noti_handle = NULL;
+ notification_error_e err = NOTIFICATION_ERROR_NONE;
+ int privId = 0;
+ bundle *b = NULL;
+ void *blob_data = NULL;
+ bundle_raw* b_raw = NULL;
+ int length;
+
+ noti_handle = notification_create(NOTIFICATION_TYPE_ONGOING);
+ if (!noti_handle) {
+ TRACE_ERROR("[FAIL] create notification handle");
+ return -1;
+ }
+
+ char *title = dp_db_get_text_column(id,
+ DP_DB_TABLE_NOTIFICATION, DP_DB_COL_TITLE);
+ if(title != NULL) {
+ err = notification_set_text(noti_handle, NOTIFICATION_TEXT_TYPE_TITLE,
+ title, NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+ free(title);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set title [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+ } else {
+ char *content_name =
+ dp_db_get_text_column
+ (id, DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_CONTENT_NAME);
+
+ if (content_name == NULL)
+ content_name = strdup("No Name");
+
+ err = notification_set_text(noti_handle,
+ NOTIFICATION_TEXT_TYPE_TITLE, content_name, NULL,
+ NOTIFICATION_VARIABLE_TYPE_NONE);
+ if (content_name)
+ free(content_name);
+ }
+
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set title [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ err = notification_set_image(noti_handle,
+ NOTIFICATION_IMAGE_TYPE_ICON, DP_NOTIFICATION_ONGOING_ICON_PATH);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set icon [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ blob_data = dp_db_get_blob_column
+ (id, DP_DB_TABLE_NOTIFICATION, DP_DB_COL_RAW_BUNDLE_ONGOING, &length);
+ if (blob_data != NULL) {
+ b_raw = (bundle_raw*)blob_data;
+ if (b_raw != NULL) {
+ b = bundle_decode_raw(b_raw, length);
+ if (b != NULL) {
+ err = notification_set_execute_option(noti_handle,
+ NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH, "View", NULL, b);
+
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set execute option [%s]", __noti_error_str(err));
+ bundle_free_encoded_rawdata(&b_raw);
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+ }
+ bundle_free_encoded_rawdata(&b_raw);
+ bundle_free(b);
+ }
+ }
+ } else {
+ b = bundle_create();
+ if (!b) {
+ TRACE_ERROR("[FAIL] create bundle");
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ if (packagename &&
+ appsvc_set_pkgname(b, packagename) != APPSVC_RET_OK) {
+ TRACE_ERROR("[FAIL] set pkg name");
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+ }
+ err = notification_set_execute_option(noti_handle,
+ NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH, "View", NULL, b);
+
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set execute option [%s]", __noti_error_str(err));
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+ }
+ bundle_free(b);
+ }
+ err = notification_set_property(noti_handle,
+ NOTIFICATION_PROP_DISABLE_TICKERNOTI);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set property [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ err = notification_set_image(noti_handle,
+ NOTIFICATION_IMAGE_TYPE_ICON_FOR_INDICATOR, DP_NOTIFICATION_DOWNLOADING_ICON_PATH);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set icon indicator [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ err = notification_set_display_applist(noti_handle, NOTIFICATION_DISPLAY_APP_ALL);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set disable icon [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ err = notification_insert(noti_handle, &privId);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set insert [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ TRACE_DEBUG("m_noti_id [%d]", privId);
+ notification_free(noti_handle);
+ return privId;
+}
+
+int dp_set_downloadedinfo_notification(int priv_id, int id, char *packagename, dp_state_type state)
+{
+ notification_h noti_handle = NULL;
+ notification_error_e err = NOTIFICATION_ERROR_NONE;
+ int privId = 0;
+ bundle *b = NULL;
+ void *blob_data = NULL;
+ bundle_raw* b_raw = NULL;
+ int length = 0;
+
+ if (priv_id >= 0) {
+ err = notification_delete_by_priv_id(NULL, NOTIFICATION_TYPE_ONGOING,
+ priv_id);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] delete notification handle [%s]",
+ __noti_error_str(err));
+ }
+ }
+
+ noti_handle = notification_create(NOTIFICATION_TYPE_NOTI);
+
+ if (!noti_handle) {
+ TRACE_ERROR("[FAIL] create notification handle");
+ return -1;
+ }
+
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set title [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ err = notification_set_text(noti_handle, NOTIFICATION_TEXT_TYPE_TITLE,
+ __get_string_status(state), NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set title [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ char *description =
+ dp_db_get_text_column
+ (id, DP_DB_TABLE_NOTIFICATION, DP_DB_COL_DESCRIPTION);
+ if(description != NULL) {
+ err = notification_set_text(noti_handle,
+ NOTIFICATION_TEXT_TYPE_INFO_2, description,
+ NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+ free(description);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set description [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+ } else {
+ char *url = NULL;
+ url = dp_db_get_text_column
+ (id, DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_URL);
+ if (url) {
+ char *sender_str = __get_string_sender(url);
+ err = notification_set_text(noti_handle, NOTIFICATION_TEXT_TYPE_INFO_2,
+ sender_str, NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set title [%s]", __noti_error_str(err));
+ free(sender_str);
+ free(url);
+ notification_free(noti_handle);
+ return -1;
+ }
+ free(sender_str);
+ free(url);
+ }
+ }
+
+ char *title = dp_db_get_text_column(id,
+ DP_DB_TABLE_NOTIFICATION, DP_DB_COL_TITLE);
+ if(title != NULL) {
+ err = notification_set_text(noti_handle, NOTIFICATION_TEXT_TYPE_CONTENT,
+ title, NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+ free(title);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set title [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+ } else {
+ char *content_name =
+ dp_db_get_text_column
+ (id, DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_CONTENT_NAME);
+ if (content_name == NULL)
+ content_name = strdup("No Name");
+
+ err = notification_set_text(noti_handle,
+ NOTIFICATION_TEXT_TYPE_CONTENT, content_name,
+ NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+ free(content_name);
+ }
+
+ time_t tt = time(NULL);
+ err = notification_set_time_to_text(noti_handle,
+ NOTIFICATION_TEXT_TYPE_INFO_SUB_1, tt);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set time [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+ if (state == DP_STATE_COMPLETED) {
+ blob_data = dp_db_get_blob_column
+ (id, DP_DB_TABLE_NOTIFICATION, DP_DB_COL_RAW_BUNDLE_COMPLETE, &length);
+ if (blob_data != NULL) {
+ b_raw = (bundle_raw*)blob_data;
+ if (b_raw != NULL) {
+ b = bundle_decode_raw(b_raw, length);
+ if (b != NULL) {
+ err = notification_set_execute_option(noti_handle,
+ NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH, "View", NULL, b);
+
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set execute option [%s]", __noti_error_str(err));
+ bundle_free_encoded_rawdata(&b_raw);
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+ }
+ bundle_free_encoded_rawdata(&b_raw);
+ }
+ }
+ } else {
+ char *file_path = NULL;
+ b = bundle_create();
+ if (!b) {
+ TRACE_ERROR("[FAIL] create bundle");
+ notification_free(noti_handle);
+ return -1;
+ }
+ if (appsvc_set_operation(b, APPSVC_OPERATION_VIEW) != APPSVC_RET_OK) {
+ TRACE_ERROR("[FAIL] appsvc set operation");
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+ }
+ file_path = dp_db_get_text_column
+ (id, DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_SAVED_PATH);
+ if (file_path == NULL) {
+ TRACE_ERROR("[FAIL] get file path");
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+
+ }
+ if (appsvc_set_uri(b, file_path) != APPSVC_RET_OK) {
+ TRACE_ERROR("[FAIL] appsvc set uri");
+ bundle_free(b);
+ notification_free(noti_handle);
+ free(file_path);
+ return -1;
+ }
+ free(file_path);
+ err = notification_set_execute_option(noti_handle,
+ NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH, "View", NULL, b);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set execute option[%s]", __noti_error_str(err));
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+ }
+ }
+ long long file_size = dp_db_get_int64_column(id,
+ DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_CONTENT_SIZE);
+ char *size_str = __get_string_size(file_size);
+
+ err = notification_set_text(noti_handle, NOTIFICATION_TEXT_TYPE_INFO_1,
+ size_str, NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
+
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set title [%s]", __noti_error_str(err));
+ free(size_str);
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+ }
+ free(size_str);
+
+ err = notification_set_image(noti_handle, NOTIFICATION_IMAGE_TYPE_ICON,
+ DP_NOTIFICATION_ICON_PATH);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set icon [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+ } else if (state == DP_STATE_CANCELED || state == DP_STATE_FAILED) {
+ blob_data = dp_db_get_blob_column
+ (id, DP_DB_TABLE_NOTIFICATION, DP_DB_COL_RAW_BUNDLE_FAIL, &length);
+ if (blob_data != NULL) {
+ b_raw = (bundle_raw *)blob_data;
+ if (b_raw != NULL) {
+ b = bundle_decode_raw(b_raw, length);
+ if (b != NULL) {
+ err = notification_set_execute_option(noti_handle,
+ NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH, "View", NULL, b);
+
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set execute option [%s]", __noti_error_str(err));
+ bundle_free_encoded_rawdata(&b_raw);
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+ }
+ bundle_free_encoded_rawdata(&b_raw);
+ }
+ }
+ } else {
+ b = bundle_create();
+ if (!b) {
+ TRACE_ERROR("[FAIL] create bundle");
+ notification_free(noti_handle);
+ return -1;
+ }
+ if (packagename &&
+ appsvc_set_pkgname(b, packagename) !=
+ APPSVC_RET_OK) {
+ TRACE_ERROR("[FAIL] set pkg name");
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+ }
+ err = notification_set_execute_option(noti_handle,
+ NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH, "View", NULL, b);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set execute option[%s]", __noti_error_str(err));
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+ }
+ }
+ err = notification_set_image(noti_handle, NOTIFICATION_IMAGE_TYPE_ICON,
+ DP_NOTIFICATION_FAILED_ICON_PATH);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set icon [%s]", __noti_error_str(err));
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+ }
+ } else {
+ TRACE_ERROR("[CRITICAL] invalid state");
+ bundle_free(b);
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set time [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ bundle_free(b);
+ return -1;
+ }
+
+ bundle_free(b);
+
+ err = notification_set_property(noti_handle,
+ NOTIFICATION_PROP_DISABLE_TICKERNOTI);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set property [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ err = notification_set_display_applist(noti_handle,
+ NOTIFICATION_DISPLAY_APP_ALL ^ NOTIFICATION_DISPLAY_APP_INDICATOR);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set disable icon [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ err = notification_insert(noti_handle, &privId);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] set insert [%s]", __noti_error_str(err));
+ notification_free(noti_handle);
+ return -1;
+ }
+
+ TRACE_DEBUG("m_noti_id [%d]", privId);
+ notification_free(noti_handle);
+ return privId;
+}
+
+void dp_update_downloadinginfo_notification(int priv_id, double received_size, double file_size)
+{
+ notification_error_e err = NOTIFICATION_ERROR_NONE;
+ if (priv_id < 0) {
+ TRACE_ERROR("[FAIL] Invalid priv_id[%d]", priv_id);
+ return;
+ }
+
+ if (file_size > 0) {
+ double progress;
+ progress = received_size / file_size;
+ err = notification_update_progress(NULL, priv_id, progress);
+ if (err != NOTIFICATION_ERROR_NONE)
+ TRACE_ERROR("[FAIL] update noti progress[%s]",
+ __noti_error_str(err));
+ } else {
+ err = notification_update_size(NULL, priv_id, received_size);
+ if (err != NOTIFICATION_ERROR_NONE)
+ TRACE_ERROR("[FAIL] update noti progress[%s]",
+ __noti_error_str(err));
+ }
+}
+
+void dp_clear_downloadinginfo_notification()
+{
+ notification_error_e err = NOTIFICATION_ERROR_NONE;
+ err = notification_delete_all_by_type(NULL, NOTIFICATION_TYPE_ONGOING);
+ if (err != NOTIFICATION_ERROR_NONE) {
+ TRACE_ERROR("[FAIL] clear noti [%s]", __noti_error_str(err));
+ }
+ return;
+}
diff --git a/provider/download-provider-pid.c b/provider/download-provider-pid.c
new file mode 100755
index 0000000..bd1a223
--- /dev/null
+++ b/provider/download-provider-pid.c
@@ -0,0 +1,34 @@
+/*
+ * 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 <unistd.h>
+#include <fcntl.h>
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief check whether daemon is alive
+/// @warning lockfd should be managed without close()
+/// @param the patch for locking the file
+int dp_lock_pid(char *path)
+{
+ int lockfd = -1;
+ if ((lockfd = open(path, O_WRONLY | O_CREAT, (0666 & (~000)))) < 0) {
+ return -1;
+ } else if (lockf(lockfd, F_TLOCK, 0) < 0) {
+ close(lockfd);
+ return -1;
+ }
+ return lockfd;
+}
diff --git a/provider/download-provider-request.c b/provider/download-provider-request.c
new file mode 100755
index 0000000..cbd4af6
--- /dev/null
+++ b/provider/download-provider-request.c
@@ -0,0 +1,930 @@
+/*
+ * 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 <sys/time.h>
+#include <sys/statfs.h>
+#include <sys/smack.h>
+#include "download-provider.h"
+#include "download-provider-log.h"
+
+#include "download-provider-slots.h"
+#include "download-provider-socket.h"
+#include "download-provider-db.h"
+#include "download-provider-pthread.h"
+
+#include "download-provider-notification.h"
+
+///////// below functions are called by main thread of thread-request.c
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief create unique id as integer type
+/// @return unique id combined local time and the special calculation
+static int __get_download_request_id(void)
+{
+ static int last_uniquetime = 0;
+ int uniquetime = 0;
+
+ do {
+ struct timeval tval;
+ int cipher = 1;
+ int c = 0;
+
+ gettimeofday(&tval, NULL);
+
+ int usec = tval.tv_usec;
+ for (c = 0; ; c++, cipher++) {
+ if ((usec /= 10) <= 0)
+ break;
+ }
+ if (tval.tv_usec == 0)
+ tval.tv_usec = (tval.tv_sec & 0x0fff);
+ int disit_unit = 10;
+ for (c = 0; c < cipher - 3; c++)
+ disit_unit = disit_unit * 10;
+ uniquetime = tval.tv_sec + ((tval.tv_usec << 2) * 100) +
+ ((tval.tv_usec >> (cipher - 1)) * disit_unit) +
+ ((tval.tv_usec + (tval.tv_usec % 10)) & 0x0fff);
+ } while (last_uniquetime == uniquetime);
+ last_uniquetime = uniquetime;
+ return uniquetime;
+}
+
+char *dp_print_state(dp_state_type state)
+{
+ switch(state)
+ {
+ case DP_STATE_NONE :
+ return "NONE";
+ case DP_STATE_READY :
+ return "READY";
+ case DP_STATE_QUEUED :
+ return "QUEUED";
+ case DP_STATE_CONNECTING :
+ return "CONNECTING";
+ case DP_STATE_DOWNLOADING :
+ return "DOWNLOADING";
+ case DP_STATE_PAUSE_REQUESTED :
+ return "PAUSE_REQUESTED";
+ case DP_STATE_PAUSED :
+ return "PAUSED";
+ case DP_STATE_COMPLETED :
+ return "COMPLETED";
+ case DP_STATE_CANCELED :
+ return "CANCELED";
+ case DP_STATE_FAILED :
+ return "FAILED";
+ default :
+ break;
+ }
+ return "UNKNOWN";
+}
+
+char *dp_print_errorcode(dp_error_type errorcode)
+{
+ switch(errorcode)
+ {
+ case DP_ERROR_NONE :
+ return "NONE";
+ case DP_ERROR_INVALID_PARAMETER :
+ return "INVALID_PARAMETER";
+ case DP_ERROR_OUT_OF_MEMORY :
+ return "OUT_OF_MEMORY";
+ case DP_ERROR_IO_ERROR :
+ return "IO_ERROR";
+ case DP_ERROR_NETWORK_UNREACHABLE :
+ return "NETWORK_UNREACHABLE";
+ case DP_ERROR_CONNECTION_TIMED_OUT :
+ return "CONNECTION_TIMED_OUT";
+ case DP_ERROR_NO_SPACE :
+ return "NO_SPACE";
+ case DP_ERROR_FIELD_NOT_FOUND :
+ return "FIELD_NOT_FOUND";
+ case DP_ERROR_INVALID_STATE :
+ return "INVALID_STATE";
+ case DP_ERROR_CONNECTION_FAILED :
+ return "CONNECTION_FAILED";
+ case DP_ERROR_INVALID_URL :
+ return "INVALID_URL";
+ case DP_ERROR_INVALID_DESTINATION :
+ return "INVALID_DESTINATION";
+ case DP_ERROR_QUEUE_FULL :
+ return "QUEUE_FULL";
+ case DP_ERROR_ALREADY_COMPLETED :
+ return "ALREADY_COMPLETED";
+ case DP_ERROR_FILE_ALREADY_EXISTS :
+ return "FILE_ALREADY_EXISTS";
+ case DP_ERROR_TOO_MANY_DOWNLOADS :
+ return "TOO_MANY_DOWNLOADS";
+ case DP_ERROR_NO_DATA :
+ return "NO_DATA";
+ case DP_ERROR_UNHANDLED_HTTP_CODE :
+ return "UNHANDLED_HTTP_CODE";
+ case DP_ERROR_CANNOT_RESUME :
+ return "CANNOT_RESUME";
+ case DP_ERROR_PERMISSION_DENIED :
+ return "PERMISSION_DENIED";
+ case DP_ERROR_RESPONSE_TIMEOUT :
+ return "RESPONSE_TIMEOUT";
+ case DP_ERROR_REQUEST_TIMEOUT :
+ return "REQUEST_TIMEOUT";
+ case DP_ERROR_SYSTEM_DOWN :
+ return "SYSTEM_DOWN";
+ case DP_ERROR_CLIENT_DOWN :
+ return "CLIENT_DOWN";
+ case DP_ERROR_ID_NOT_FOUND :
+ return "ID_NOT_FOUND";
+ default :
+ break;
+ }
+ return "UNKNOWN";
+}
+
+int dp_is_smackfs_mounted()
+{
+ if(smack_smackfs_path() != NULL)
+ return 1;
+ TRACE_ERROR("[SMACK DISABLE]");
+ return 0;
+}
+
+char *dp_strdup(char *src)
+{
+ char *dest = NULL;
+ size_t src_len = 0;
+
+ if (src == NULL) {
+ TRACE_ERROR("[CHECK PARAM]");
+ return NULL;
+ }
+
+ src_len = strlen(src);
+ if (src_len <= 0) {
+ TRACE_ERROR("[CHECK PARAM] len[%d]", src_len);
+ return NULL;
+ }
+
+ dest = (char *)calloc(src_len + 1, sizeof(char));
+ if (dest == NULL) {
+ TRACE_STRERROR("[CHECK] allocation");
+ return NULL;
+ }
+ memcpy(dest, src, src_len * sizeof(char));
+ dest[src_len] = '\0';
+
+ return dest;
+}
+
+// check param
+// create new slot
+// fill info to new slot
+// make new id
+// save info to QUEUE(DB)
+dp_error_type dp_request_create(int id, dp_client_group *group, dp_request **empty_slot)
+{
+ if (id != -1) {
+ TRACE_ERROR("[CHECK PROTOCOL] ID not -1");
+ return DP_ERROR_INVALID_STATE;
+ }
+ if (group == NULL || empty_slot == NULL) {
+ TRACE_ERROR("[CHECK INTERNAL][%d]", id);
+ return DP_ERROR_INVALID_PARAMETER;
+ }
+ // New allocation Slot
+ dp_request *new_request = dp_request_new();
+ if (new_request == NULL) {
+ TRACE_STRERROR("[CHECK MEMORY][%d]", id);
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+
+ int check_id = -1;
+ do {
+ new_request->id = __get_download_request_id();
+ check_id = dp_db_get_int_column(new_request->id,
+ DP_DB_TABLE_LOG, DP_DB_COL_ID);
+ } while (check_id == new_request->id); // means duplicated id
+
+ new_request->group = group;
+ if (group->pkgname != NULL && strlen(group->pkgname) > 1)
+ new_request->packagename = dp_strdup(group->pkgname);
+ if (new_request->packagename == NULL) {
+ dp_request_free(new_request);
+ TRACE_ERROR("[ERROR][%d] OUT_OF_MEMORY [PACKAGENAME]", id);
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+ new_request->state = DP_STATE_READY;
+ new_request->error = DP_ERROR_NONE;
+ new_request->create_time = (int)time(NULL);
+
+ if (dp_db_request_new_logging(new_request->id, new_request->state,
+ new_request->packagename) < 0) {
+ dp_request_free(new_request);
+ if (dp_db_is_full_error() == 0) {
+ TRACE_ERROR("[SQLITE_FULL]");
+ return DP_ERROR_NO_SPACE;
+ }
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+ *empty_slot = new_request;
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_request_set_url(int id, dp_request *request, char *url)
+{
+ int length = 0;
+ if (url == NULL || (length = strlen(url)) <= 1)
+ return DP_ERROR_INVALID_URL;
+
+ if (request != NULL) {
+ if (request->state == DP_STATE_CONNECTING ||
+ request->state == DP_STATE_DOWNLOADING ||
+ request->state == DP_STATE_COMPLETED) {
+ TRACE_ERROR
+ ("[ERROR][%d] now[%s]", id, dp_print_state(request->state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ } else {
+ // check id in logging table.
+ dp_state_type state = dp_db_get_state(id);
+ // check again from logging table
+ if (state == DP_STATE_CONNECTING ||
+ state == DP_STATE_DOWNLOADING ||
+ state == DP_STATE_COMPLETED) {
+ TRACE_ERROR("[ERROR][%d] now[%s]", id, dp_print_state(state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ }
+
+ if (dp_db_replace_column
+ (id, DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_URL,
+ DP_DB_COL_TYPE_TEXT, url) < 0) {
+ TRACE_ERROR("[CHECK SQL][%d]", id);
+ if (dp_db_is_full_error() == 0) {
+ TRACE_ERROR("[SQLITE_FULL][%d]", id);
+ return DP_ERROR_NO_SPACE;
+ }
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_request_set_destination(int id, dp_request *request, char *dest)
+{
+ int length = 0;
+ if (!dest || (length = strlen(dest)) <= 1)
+ return DP_ERROR_INVALID_DESTINATION;
+
+ if (request != NULL) {
+ if (request->state == DP_STATE_CONNECTING ||
+ request->state == DP_STATE_DOWNLOADING ||
+ request->state == DP_STATE_COMPLETED) {
+ TRACE_ERROR
+ ("[ERROR][%d] now[%s]", id, dp_print_state(request->state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ } else {
+ // check id in logging table.
+ dp_state_type state = dp_db_get_state(id);
+ // check again from logging table
+ if (state == DP_STATE_CONNECTING ||
+ state == DP_STATE_DOWNLOADING ||
+ state == DP_STATE_COMPLETED) {
+ TRACE_ERROR("[ERROR][%d] now[%s]", id, dp_print_state(state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ }
+
+ if (dp_db_replace_column
+ (id, DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_DESTINATION,
+ DP_DB_COL_TYPE_TEXT, dest) < 0) {
+ TRACE_ERROR("[CHECK SQL][%d]", id);
+ if (dp_db_is_full_error() == 0) {
+ TRACE_ERROR("[SQLITE_FULL][%d]", id);
+ return DP_ERROR_NO_SPACE;
+ }
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_request_set_filename(int id, dp_request *request, char *filename)
+{
+ int length = 0;
+ if (!filename || (length = strlen(filename)) <= 1)
+ return DP_ERROR_INVALID_PARAMETER;
+
+ if (request != NULL) {
+ if (request->state == DP_STATE_CONNECTING ||
+ request->state == DP_STATE_DOWNLOADING ||
+ request->state == DP_STATE_COMPLETED) {
+ TRACE_ERROR
+ ("[ERROR][%d] now[%s]", id, dp_print_state(request->state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ } else {
+ // check id in logging table.
+ dp_state_type state = dp_db_get_state(id);
+ // check again from logging table
+ if (state == DP_STATE_CONNECTING ||
+ state == DP_STATE_DOWNLOADING ||
+ state == DP_STATE_COMPLETED) {
+ TRACE_ERROR("[ERROR][%d] now[%s]", id, dp_print_state(state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ }
+
+ if (dp_db_replace_column
+ (id, DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_FILENAME,
+ DP_DB_COL_TYPE_TEXT, filename) < 0) {
+ TRACE_ERROR("[CHECK SQL][%d]", id);
+ if (dp_db_is_full_error() == 0) {
+ TRACE_ERROR("[SQLITE_FULL][%d]", id);
+ return DP_ERROR_NO_SPACE;
+ }
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+
+ TRACE_SECURE_DEBUG("ID [%d] Filename[%s]", id, filename);
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_request_set_title(int id, dp_request *request, char *title)
+{
+ int length = 0;
+ if (!title || (length = strlen(title)) <= 1)
+ return DP_ERROR_INVALID_PARAMETER;
+
+ if (request != NULL) {
+ if (request->state == DP_STATE_COMPLETED) {
+ TRACE_ERROR
+ ("[ERROR][%d] now[%s]", id, dp_print_state(request->state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ } else {
+ // check id in logging table.
+ dp_state_type state = dp_db_get_state(id);
+ // check again from logging table
+ if (state == DP_STATE_COMPLETED) {
+ TRACE_ERROR("[ERROR][%d] now[%s]", id, dp_print_state(state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ }
+
+ if (dp_db_replace_column
+ (id, DP_DB_TABLE_NOTIFICATION, DP_DB_COL_TITLE,
+ DP_DB_COL_TYPE_TEXT, title) < 0) {
+ TRACE_ERROR("[CHECK SQL][%d]", id);
+ if (dp_db_is_full_error() == 0) {
+ TRACE_ERROR("[SQLITE_FULL][%d]", id);
+ return DP_ERROR_NO_SPACE;
+ }
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+
+ TRACE_SECURE_DEBUG("ID [%d] title[%s]", id, title);
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_request_set_bundle(int id, dp_request *request, int type, bundle_raw *b, unsigned length)
+{
+ char *column = NULL;
+ if (b == NULL || (length < 1))
+ return DP_ERROR_INVALID_PARAMETER;
+
+ if (request != NULL) {
+ if (request->state == DP_STATE_COMPLETED) {
+ TRACE_ERROR
+ ("[ERROR][%d] now[%s]", id, dp_print_state(request->state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ } else {
+ // check id in logging table.
+ dp_state_type state = dp_db_get_state(id);
+ // check again from logging table
+ if (state == DP_STATE_COMPLETED) {
+ TRACE_ERROR("[ERROR][%d] now[%s]", id, dp_print_state(state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ }
+
+ switch(type) {
+ case DP_NOTIFICATION_BUNDLE_TYPE_ONGOING:
+ column = DP_DB_COL_RAW_BUNDLE_ONGOING;
+ break;
+ case DP_NOTIFICATION_BUNDLE_TYPE_COMPLETE:
+ column = DP_DB_COL_RAW_BUNDLE_COMPLETE;
+ break;
+ case DP_NOTIFICATION_BUNDLE_TYPE_FAILED:
+ column = DP_DB_COL_RAW_BUNDLE_FAIL;
+ break;
+ default:
+ TRACE_ERROR("[CHECK TYPE][%d]", type);
+ return DP_ERROR_INVALID_PARAMETER;
+ }
+ if (dp_db_replace_blob_column
+ (id, DP_DB_TABLE_NOTIFICATION, column, b, length) < 0) {
+ TRACE_ERROR("[CHECK SQL][%d]", id);
+ if (dp_db_is_full_error() == 0) {
+ TRACE_ERROR("[SQLITE_FULL][%d]", id);
+ return DP_ERROR_NO_SPACE;
+ }
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+
+ //TRACE_SECURE_DEBUG("ID [%d] title[%s]", id, title);
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_request_set_description(int id, dp_request *request, char *description)
+{
+ int length = 0;
+ if (!description || (length = strlen(description)) <= 1)
+ return DP_ERROR_INVALID_PARAMETER;
+
+ if (request != NULL) {
+ if (request->state == DP_STATE_COMPLETED) {
+ TRACE_ERROR
+ ("[ERROR][%d] now[%s]", id, dp_print_state(request->state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ } else {
+ // check id in logging table.
+ dp_state_type state = dp_db_get_state(id);
+ // check again from logging table
+ if (state == DP_STATE_COMPLETED) {
+ TRACE_ERROR("[ERROR][%d] now[%s]", id, dp_print_state(state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ }
+
+ if (dp_db_replace_column
+ (id, DP_DB_TABLE_NOTIFICATION, DP_DB_COL_DESCRIPTION,
+ DP_DB_COL_TYPE_TEXT, description) < 0) {
+ TRACE_ERROR("[CHECK SQL][%d]", id);
+ if (dp_db_is_full_error() == 0) {
+ TRACE_ERROR("[SQLITE_FULL][%d]", id);
+ return DP_ERROR_NO_SPACE;
+ }
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+
+ TRACE_SECURE_DEBUG("ID [%d] description[%s]", id, description);
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_request_set_noti_type(int id, dp_request *request, unsigned type)
+{
+ if (request != NULL) {
+ if (request->state == DP_STATE_COMPLETED) {
+ TRACE_ERROR
+ ("[ERROR][%d] now[%s]", id, dp_print_state(request->state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ } else {
+ // check id in logging table.
+ dp_state_type state = dp_db_get_state(id);
+ // check again from logging table
+ if (state == DP_STATE_COMPLETED) {
+ TRACE_ERROR("[ERROR][%d] now[%s]", id, dp_print_state(state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ }
+
+ if (dp_db_replace_column
+ (id, DP_DB_TABLE_NOTIFICATION, DP_DB_COL_NOTI_TYPE,
+ DP_DB_COL_TYPE_INT, &type) < 0) {
+ TRACE_ERROR("[CHECK SQL][%d]", id);
+ if (dp_db_is_full_error() == 0) {
+ TRACE_ERROR("[SQLITE_FULL][%d]", id);
+ return DP_ERROR_NO_SPACE;
+ }
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+ if (request)
+ {
+ if(!type)
+ request->auto_notification = 0;
+ else
+ request->auto_notification = 1;
+ }
+ TRACE_SECURE_DEBUG("ID [%d] enable[%d]", id, type);
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_request_set_notification(int id, dp_request *request, unsigned enable)
+{
+ if (request != NULL) {
+ if (request->state == DP_STATE_COMPLETED) {
+ TRACE_ERROR
+ ("[ERROR][%d] now[%s]", id, dp_print_state(request->state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ } else {
+ // check id in logging table.
+ dp_state_type state = dp_db_get_state(id);
+ // check again from logging table
+ if (state == DP_STATE_COMPLETED) {
+ TRACE_ERROR("[ERROR][%d] now[%s]", id, dp_print_state(state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ }
+
+ // update queue DB
+ if (dp_db_replace_column
+ (id, DP_DB_TABLE_REQUEST_INFO,
+ DP_DB_COL_NOTIFICATION_ENABLE, DP_DB_COL_TYPE_INT,
+ &enable) < 0) {
+ TRACE_ERROR("[CHECK SQL][%d]", id);
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+ // update memory
+ if (request)
+ request->auto_notification = enable;
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_request_set_auto_download(int id, dp_request *request, unsigned enable)
+{
+ if (request != NULL) {
+ if (request->state == DP_STATE_COMPLETED) {
+ TRACE_ERROR
+ ("[ERROR][%d] now[%s]", id, dp_print_state(request->state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ } else {
+ // check id in logging table.
+ dp_state_type state = dp_db_get_state(id);
+ // check again from logging table
+ if (state == DP_STATE_COMPLETED) {
+ TRACE_ERROR("[ERROR][%d] now[%s]", id, dp_print_state(state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ }
+
+ // update queue DB
+ if (dp_db_replace_column
+ (id, DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_AUTO_DOWNLOAD,
+ DP_DB_COL_TYPE_INT, &enable) < 0) {
+ TRACE_ERROR("[CHECK SQL][%d]", id);
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_request_set_state_event(int id, dp_request *request, unsigned enable)
+{
+ if (request == NULL) {
+ // check id in logging table.
+ dp_state_type state = dp_db_get_state(id);
+
+ if (state == DP_STATE_DOWNLOADING ||
+ state == DP_STATE_COMPLETED) {
+ TRACE_ERROR("[ERROR][%d] now[%s]", id, dp_print_state(state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ }
+
+ // update queue DB
+ if (dp_db_replace_column
+ (id, DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_STATE_EVENT,
+ DP_DB_COL_TYPE_INT, &enable) < 0) {
+ TRACE_ERROR("[CHECK SQL][%d]", id);
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+ // update memory
+ if (request != NULL)
+ request->state_cb = enable;
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_request_set_progress_event(int id, dp_request *request, unsigned enable)
+{
+ if (request == NULL) {
+ // check id in logging table.
+ dp_state_type state = dp_db_get_state(id);
+
+ if (state == DP_STATE_DOWNLOADING ||
+ state == DP_STATE_COMPLETED) {
+ TRACE_ERROR("[ERROR][%d] now[%s]", id, dp_print_state(state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ }
+
+ // update queue DB
+ if (dp_db_replace_column
+ (id, DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_PROGRESS_EVENT,
+ DP_DB_COL_TYPE_INT, &enable) < 0) {
+ TRACE_ERROR("[CHECK SQL][%d]", id);
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+ // update memory
+ if (request)
+ request->progress_cb = enable;
+ return DP_ERROR_NONE;
+}
+
+dp_error_type dp_request_set_network_type(int id, dp_request *request, int type)
+{
+ if (request != NULL) {
+ if (request->state == DP_STATE_CONNECTING ||
+ request->state == DP_STATE_DOWNLOADING ||
+ request->state == DP_STATE_COMPLETED) {
+ TRACE_ERROR
+ ("[ERROR][%d] now[%s]", id, dp_print_state(request->state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ } else {
+ // check id in logging table.
+ dp_state_type state = dp_db_get_state(id);
+ // check again from logging table
+ if (state == DP_STATE_CONNECTING ||
+ state == DP_STATE_DOWNLOADING ||
+ state == DP_STATE_COMPLETED) {
+ TRACE_ERROR("[ERROR][%d] now[%s]", id, dp_print_state(state));
+ return DP_ERROR_INVALID_STATE;
+ }
+ }
+
+ // update queue DB
+ if (dp_db_replace_column
+ (id, DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_NETWORK_TYPE,
+ DP_DB_COL_TYPE_INT, &type) < 0) {
+ TRACE_ERROR("[CHECK SQL][%d]", id);
+ return DP_ERROR_OUT_OF_MEMORY;
+ }
+ // update memory
+ if (request)
+ request->network_type = type;
+ return DP_ERROR_NONE;
+}
+
+char *dp_request_get_url(int id, dp_error_type *errorcode)
+{
+ char *url = NULL;
+ url = dp_db_get_text_column
+ (id, DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_URL);
+ if (url == NULL) {
+ *errorcode = DP_ERROR_NO_DATA;
+ return NULL;
+ }
+ return url;
+}
+
+char *dp_request_get_destination(int id, dp_request *request, dp_error_type *errorcode)
+{
+ char *dest = NULL;
+ dest = dp_db_get_text_column
+ (id, DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_DESTINATION);
+ if (dest == NULL) {
+ *errorcode = DP_ERROR_NO_DATA;
+ return NULL;
+ }
+ return dest;
+}
+
+char *dp_request_get_filename(int id, dp_request *request, dp_error_type *errorcode)
+{
+ char *filename = NULL;
+ filename = dp_db_get_text_column
+ (id, DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_FILENAME);
+ if (filename == NULL) {
+ *errorcode = DP_ERROR_NO_DATA;
+ return NULL;
+ }
+ return filename;
+}
+
+char *dp_request_get_title(int id, dp_request *request, dp_error_type *errorcode)
+{
+ char *title = NULL;
+ title = dp_db_get_text_column
+ (id, DP_DB_TABLE_NOTIFICATION, DP_DB_COL_TITLE);
+ if (title == NULL) {
+ *errorcode = DP_ERROR_NO_DATA;
+ return NULL;
+ }
+ return title;
+}
+
+bundle_raw *dp_request_get_bundle(int id, dp_request *request, dp_error_type *errorcode, char* column, int *length)
+{
+ void *blob_data = NULL;
+ blob_data = dp_db_get_blob_column
+ (id, DP_DB_TABLE_NOTIFICATION, column, length);
+ if (blob_data == NULL) {
+ *errorcode = DP_ERROR_NO_DATA;
+ return NULL;
+ }
+ return (bundle_raw*)blob_data;
+}
+
+
+char *dp_request_get_description(int id, dp_request *request, dp_error_type *errorcode)
+{
+ char *description = NULL;
+ description = dp_db_get_text_column
+ (id, DP_DB_TABLE_NOTIFICATION, DP_DB_COL_DESCRIPTION);
+ if (description == NULL) {
+ *errorcode = DP_ERROR_NO_DATA;
+ return NULL;
+ }
+ return description;
+}
+
+int dp_request_get_noti_type(int id, dp_request *request, dp_error_type *errorcode)
+{
+ int type = -1;
+ type = dp_db_get_int_column
+ (id, DP_DB_TABLE_NOTIFICATION, DP_DB_COL_NOTI_TYPE);
+ if (type == -1)
+ *errorcode = DP_ERROR_NO_DATA;
+ return type;
+}
+
+
+
+char *dp_request_get_contentname(int id, dp_request *request, dp_error_type *errorcode)
+{
+ char *content = NULL;
+ content = dp_db_get_text_column
+ (id, DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_CONTENT_NAME);
+ if (content == NULL) {
+ *errorcode = DP_ERROR_NO_DATA;
+ return NULL;
+ }
+ return content;
+}
+
+char *dp_request_get_etag(int id, dp_request *request, dp_error_type *errorcode)
+{
+ char *etag = NULL;
+ etag = dp_db_get_text_column
+ (id, DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_ETAG);
+ if (etag == NULL) {
+ *errorcode = DP_ERROR_NO_DATA;
+ return NULL;
+ }
+ return etag;
+}
+
+char *dp_request_get_savedpath(int id, dp_request *request, dp_error_type *errorcode)
+{
+ char *savedpath = NULL;
+ savedpath = dp_db_get_text_column
+ (id, DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_SAVED_PATH);
+ if (savedpath == NULL) {
+ *errorcode = DP_ERROR_NO_DATA;
+ return NULL;
+ }
+ return savedpath;
+}
+
+char *dp_request_get_tmpsavedpath(int id, dp_request *request, dp_error_type *errorcode)
+{
+ char *tmppath = NULL;
+ tmppath = dp_db_get_text_column
+ (id, DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_TMP_SAVED_PATH);
+ if (tmppath == NULL) {
+ *errorcode = DP_ERROR_NO_DATA;
+ return NULL;
+ }
+ return tmppath;
+}
+
+char *dp_request_get_mimetype(int id, dp_request *request, dp_error_type *errorcode)
+{
+ char *mimetype = NULL;
+ mimetype = dp_db_get_text_column
+ (id, DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_MIMETYPE);
+ if (mimetype == NULL) {
+ *errorcode = DP_ERROR_NO_DATA;
+ return NULL;
+ }
+ return mimetype;
+}
+
+char *dp_request_get_pkg_name(int id, dp_request *request, dp_error_type *errorcode)
+{
+ char *pkg_name = NULL;
+ pkg_name = dp_db_get_text_column
+ (id, DP_DB_TABLE_LOG, DP_DB_COL_PACKAGENAME);
+ if (pkg_name == NULL) {
+ *errorcode = DP_ERROR_NO_DATA;
+ return NULL;
+ }
+ return pkg_name;
+}
+
+dp_request *dp_request_load_from_log(int id, dp_error_type *errorcode)
+{
+ dp_request *request = NULL;
+
+ request = dp_db_load_logging_request(id);
+ if (request == NULL) {
+ *errorcode = DP_ERROR_ID_NOT_FOUND;
+ return NULL;
+ }
+ if (request->state == DP_STATE_COMPLETED) {
+ TRACE_ERROR
+ ("[ERROR][%d] now[%s]", id, dp_print_state(request->state));
+ *errorcode = DP_ERROR_INVALID_STATE;
+ dp_request_free(request);
+ return NULL;
+ }
+ return request;
+}
+
+
+void dp_request_state_response(dp_request *request)
+{
+ if (request == NULL) {
+ return ;
+ }
+
+ TRACE_INFO("[INFO][%d] state:%s error:%s", request->id,
+ dp_print_state(request->state),
+ dp_print_errorcode(request->error));
+
+ if (dp_db_request_update_status(request->id, request->state,
+ request->error) < 0)
+ TRACE_ERROR("[ERROR][%d][SQL]", request->id);
+
+ if (request->group != NULL && request->group->event_socket >= 0 &&
+ request->state_cb == 1) {
+ dp_ipc_send_event(request->group->event_socket, request->id,
+ request->state, request->error, 0);
+ }
+
+ if (request->state == DP_STATE_DOWNLOADING) {
+ if (request->auto_notification == 1 &&
+ request->packagename != NULL) {
+ if (request->noti_priv_id != -1) {
+ dp_update_downloadinginfo_notification
+ (request->noti_priv_id,
+ (double)request->received_size,
+ (double)request->file_size);
+ } else {
+ request->noti_priv_id = dp_set_downloadinginfo_notification
+ (request->id, request->packagename);
+ }
+ } else {
+ int noti_type = dp_db_get_int_column(request->id,
+ DP_DB_TABLE_NOTIFICATION, DP_DB_COL_NOTI_TYPE);
+ if (noti_type == DP_NOTIFICATION_TYPE_ALL &&
+ request->packagename != NULL) {
+ if (request->noti_priv_id != -1) {
+ dp_update_downloadinginfo_notification
+ (request->noti_priv_id,
+ (double)request->received_size,
+ (double)request->file_size);
+ } else {
+ request->noti_priv_id = dp_set_downloadinginfo_notification
+ (request->id, request->packagename);
+ }
+ }
+ }
+ request->start_time = (int)time(NULL);
+ request->pause_time = 0;
+ request->stop_time = 0;
+ } else if (request->state == DP_STATE_PAUSED) {
+ if (request->group != NULL)
+ request->group->queued_count--;
+ request->pause_time = (int)time(NULL);
+ } else {
+ if (request->group != NULL )
+ request->group->queued_count--;
+
+ if (request->auto_notification == 1 &&
+ request->packagename != NULL) {
+ request->noti_priv_id = dp_set_downloadedinfo_notification
+ (request->noti_priv_id, request->id,
+ request->packagename, request->state);
+
+ } else {
+ int noti_type = dp_db_get_int_column(request->id,
+ DP_DB_TABLE_NOTIFICATION, DP_DB_COL_NOTI_TYPE);
+ if (noti_type > DP_NOTIFICATION_TYPE_NONE &&
+ request->packagename != NULL)
+ request->noti_priv_id = dp_set_downloadedinfo_notification
+ (request->noti_priv_id, request->id,
+ request->packagename, request->state);
+ }
+
+ request->stop_time = (int)time(NULL);
+ }
+}
diff --git a/provider/download-provider-slots.c b/provider/download-provider-slots.c
new file mode 100755
index 0000000..ad39ee8
--- /dev/null
+++ b/provider/download-provider-slots.c
@@ -0,0 +1,174 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+#include <time.h>
+#include <sys/time.h>
+
+#include "download-provider.h"
+#include "download-provider-log.h"
+#include "download-provider-pthread.h"
+
+#include "download-provider-slots.h"
+#include "download-provider-socket.h"
+
+dp_group_slots *dp_client_group_slots_new(int size)
+{
+ dp_group_slots *slots = NULL;
+ if (size <= 0)
+ return NULL;
+ slots = (dp_group_slots *) calloc(size,
+ sizeof(dp_group_slots));
+ return slots;
+}
+
+dp_request_slots *dp_request_slots_new(int size)
+{
+ int i = 0;
+ dp_request_slots *slots = NULL;
+ if (size <= 0)
+ return NULL;
+ slots = (dp_request_slots *) calloc(size,
+ sizeof(dp_request_slots));
+ for (; i < size; i++)
+ CLIENT_MUTEX_INIT(&slots[i].mutex, NULL);
+ return slots;
+}
+
+void dp_request_init(dp_request *request)
+{
+ if (request == NULL)
+ return ;
+
+ request->id = -1;
+ request->agent_id = -1;
+ request->create_time = 0;
+ request->start_time = 0;
+ request->pause_time = 0;
+ request->stop_time = 0;
+ request->state = DP_STATE_NONE;
+ request->error = DP_ERROR_NONE;
+ request->state_cb = 0;
+ request->progress_cb = 0;
+ request->progress_lasttime = 0;
+ request->received_size = 0;
+ request->file_size = 0;
+ request->network_type = DP_NETWORK_TYPE_ALL;
+ request->startcount = 0;
+ request->auto_notification = 0;
+ request->noti_priv_id = -1;
+ request->packagename = NULL;
+ request->group = NULL;
+}
+
+dp_request *dp_request_new()
+{
+ dp_request *request = NULL;
+ request = (dp_request *) calloc(1,
+ sizeof(dp_request));
+ if (!request)
+ return NULL;
+ dp_request_init(request);
+ return request;
+}
+
+int dp_request_slot_free(dp_request_slots *request_slot)
+{
+ if (request_slot == NULL)
+ return -1;
+ CLIENT_MUTEX_LOCK(&request_slot->mutex);
+ dp_request_free(request_slot->request);
+ request_slot->request = NULL;
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ return 0;
+}
+
+int dp_request_free(dp_request *request)
+{
+ if (request == NULL)
+ return -1;
+ free(request->packagename);
+ dp_request_init(request);
+ free(request);
+ return 0;
+}
+
+int dp_client_group_free(dp_client_group *group)
+{
+ if (group != NULL) {
+ if (group->cmd_socket > 0)
+ dp_socket_free(group->cmd_socket);
+ group->cmd_socket = -1;
+ if (group->event_socket > 0)
+ dp_socket_free(group->event_socket);
+ group->event_socket = -1;
+ group->queued_count = 0;
+ free(group->pkgname);
+ free(group->smack_label);
+ free(group);
+ }
+ return 0;
+}
+
+int dp_client_group_slots_free(dp_group_slots *slots, int size)
+{
+ int i = 0;
+ if (slots) {
+ for (; i < size; i++) {
+ if (slots->group)
+ dp_client_group_free(slots->group);
+ slots->group = NULL;
+ }
+ free(slots);
+ }
+ slots = NULL;
+ return 0;
+}
+
+int dp_request_slots_free(dp_request_slots *slots, int size)
+{
+ int i = 0;
+ if (slots != NULL) {
+ for (; i < size; i++) {
+ dp_request_free(slots[i].request);
+ slots[i].request = NULL;
+ CLIENT_MUTEX_DESTROY(&slots[i].mutex);
+ }
+ free(slots);
+ }
+ slots = NULL;
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief return count of requests in slot
+int dp_get_request_count(dp_request_slots *slots)
+{
+ int i = 0;
+ int count = 0;
+
+ if (!slots)
+ return -1;
+
+ for (i = 0; i < DP_MAX_REQUEST; i++) {
+ if (slots[i].request != NULL)
+ count++;
+ }
+ return count;
+}
diff --git a/provider/download-provider-socket.c b/provider/download-provider-socket.c
new file mode 100755
index 0000000..7feabf8
--- /dev/null
+++ b/provider/download-provider-socket.c
@@ -0,0 +1,351 @@
+/*
+ * 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 <pthread.h>
+
+#include <time.h>
+#include <sys/time.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <systemd/sd-daemon.h>
+#include <signal.h>
+
+#include "download-provider.h"
+#include "download-provider-log.h"
+#include "download-provider-socket.h"
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief write the error to socket
+/// @return if success, return 0
+int dp_ipc_send_errorcode(int fd, dp_error_type errorcode)
+{
+ if (fd < 0) {
+ TRACE_ERROR("[ERROR] CHECK FD[%d]", fd);
+ return -1;
+ }
+
+ if (fd >= 0 && write(fd, &errorcode, sizeof(dp_error_type)) <= 0) {
+ TRACE_STRERROR("[ERROR] write FD[%d]", fd);
+ return -1;
+ }
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief write the progressinfo to socket
+/// @return if success, return 0
+int dp_ipc_send_event(int fd, int id, dp_state_type state,
+ dp_error_type errorcode, unsigned long long received_size)
+{
+ if (fd < 0) {
+ TRACE_ERROR("[ERROR][%d] CHECK FD[%d]", id, fd);
+ return -1;
+ }
+
+ dp_event_info eventinfo;
+ eventinfo.id = id;
+ eventinfo.state = state;
+ eventinfo.err = errorcode;
+ eventinfo.received_size = received_size;
+
+ // write
+ if (fd >= 0 && write(fd, &eventinfo, sizeof(dp_event_info)) <= 0) {
+ TRACE_STRERROR("[ERROR][%d] write FD[%d]", id, fd);
+ return -1;
+ }
+ return 0;
+}
+
+// keep the order/ unsigned , str
+char *dp_ipc_read_string(int fd)
+{
+ unsigned length = 0;
+ size_t recv_size = 0;
+ unsigned remain_size = 0;
+ size_t buffer_size = 0;
+ char *str = NULL;
+
+ if (fd < 0) {
+ TRACE_ERROR("[ERROR] CHECK FD[%d]", fd);
+ return NULL;
+ }
+
+ // read flexible URL from client.
+ ssize_t recv_bytes = read(fd, &length, sizeof(unsigned));
+ if (recv_bytes < 0) {
+ TRACE_STRERROR("[ERROR] read FD[%d] length[%d]", fd, length);
+ return NULL;
+ }
+ if (length < 1 || length > DP_MAX_URL_LEN) {
+ TRACE_ERROR("[STRING LEGNTH] [%d]", length);
+ return NULL;
+ }
+ str = (char *)calloc((length + 1), sizeof(char));
+ if (str == NULL) {
+ TRACE_STRERROR("[ERROR] calloc length:%d FD[%d]", length, fd);
+ return NULL;
+ }
+ remain_size = length;
+ do {
+ buffer_size = 0;
+ if (remain_size > DP_DEFAULT_BUFFER_SIZE)
+ buffer_size = DP_DEFAULT_BUFFER_SIZE;
+ else
+ buffer_size = remain_size;
+ recv_size = (size_t)read(fd, str + (int)(length - remain_size),
+ buffer_size * sizeof(char));
+ if (recv_size > DP_DEFAULT_BUFFER_SIZE) {
+ recv_size = -1;
+ break;
+ }
+ if (recv_size > 0)
+ remain_size = remain_size - (unsigned)recv_size;
+ } while (recv_size > 0 && remain_size > 0);
+
+ if (recv_size == 0) {
+ TRACE_STRERROR("[ERROR] closed peer:%d", fd);
+ free(str);
+ return NULL;
+ }
+ str[length] = '\0';
+ return str;
+}
+
+
+// 0 : Socket Error
+// -1 : Invalid type
+unsigned dp_ipc_read_bundle(int fd, int *type, bundle_raw **b)
+{
+ unsigned length = 0;
+ size_t recv_size = 0;
+ unsigned remain_size = 0;
+ size_t buffer_size = 0;
+ bundle_raw *b_raw = NULL;
+
+ if (fd < 0) {
+ TRACE_ERROR("[ERROR] CHECK FD[%d]", fd);
+ return 0;
+ }
+
+ // read flexible URL from client.
+ ssize_t recv_bytes = read(fd, type, sizeof(int));
+ if (recv_bytes < 0) {
+ TRACE_STRERROR("[ERROR] read FD[%d] type[%d]", fd, type);
+ return 0;
+ }
+ if ((*type) != DP_NOTIFICATION_BUNDLE_TYPE_ONGOING &&
+ (*type) != DP_NOTIFICATION_BUNDLE_TYPE_COMPLETE &&
+ (*type) != DP_NOTIFICATION_BUNDLE_TYPE_FAILED) {
+ TRACE_ERROR("[NOTI TYPE] [%d]", *type);
+ return -1;
+ }
+ // read flexible URL from client.
+ recv_bytes = read(fd, &length, sizeof(unsigned));
+ if (recv_bytes < 0) {
+ TRACE_STRERROR("[ERROR] read FD[%d] length[%d]", fd, length);
+ return 0;
+ }
+ if (length < 1 || length > DP_MAX_URL_LEN) {
+ TRACE_ERROR("[STRING LEGNTH] [%d]", length);
+ return 0;
+ }
+ b_raw = (bundle_raw *)calloc(length, 1);
+ if (b_raw == NULL) {
+ TRACE_STRERROR("[ERROR] calloc length:%d FD[%d]", length, fd);
+ return 0;
+ }
+ remain_size = length;
+ do {
+ buffer_size = 0;
+ if (remain_size > DP_DEFAULT_BUFFER_SIZE)
+ buffer_size = DP_DEFAULT_BUFFER_SIZE;
+ else
+ buffer_size = remain_size;
+ recv_size = (size_t)read(fd, b_raw + (int)(length - remain_size),
+ buffer_size * sizeof(char));
+ if (recv_size > DP_DEFAULT_BUFFER_SIZE) {
+ recv_size = -1;
+ break;
+ }
+ if (recv_size > 0)
+ remain_size = remain_size - (unsigned)recv_size;
+ } while (recv_size > 0 && remain_size > 0);
+
+ if (recv_size <= 0) {
+ TRACE_STRERROR("[ERROR] closed peer:%d", fd);
+ bundle_free_encoded_rawdata(&b_raw);
+ return 0;
+ }
+ *b = b_raw;
+ return length;
+}
+
+// keep the order/ unsigned , str
+int dp_ipc_send_string(int fd, const char *str)
+{
+ unsigned length = 0;
+
+ if (fd < 0) {
+ TRACE_ERROR("[ERROR] CHECK FD[%d]", fd);
+ return -1;
+ }
+ if (str == NULL) {
+ TRACE_ERROR("[ERROR] CHECK STRING FD[%d]", fd);
+ return -1;
+ }
+
+ length = strlen(str);
+ if (length < 1) {
+ TRACE_ERROR("[ERROR] CHECK LENGTH FD[%d]", fd);
+ return -1;
+ }
+ if (fd >= 0 && write(fd, &length, sizeof(unsigned)) <= 0) {
+ TRACE_STRERROR("[ERROR] read FD[%d] length[%d]", fd, length);
+ return -1;
+ }
+ if (fd >= 0 && write(fd, str, length * sizeof(char)) <= 0) {
+ TRACE_STRERROR("[ERROR] write FD[%d]", fd);
+ return -1;
+ }
+ return 0;
+}
+
+int dp_ipc_send_bundle(int fd, bundle_raw *b, unsigned length)
+{
+ if (fd < 0) {
+ TRACE_ERROR("[ERROR] CHECK FD[%d]", fd);
+ return -1;
+ }
+ if (b == NULL) {
+ TRACE_ERROR("[ERROR] CHECK STRING FD[%d]", fd);
+ return -1;
+ }
+
+ if (length < 1) {
+ TRACE_ERROR("[ERROR] CHECK LENGTH FD[%d]", fd);
+ return -1;
+ }
+ if (fd >= 0 && write(fd, &length, sizeof(unsigned)) <= 0) {
+ TRACE_STRERROR("[ERROR] read FD[%d] length[%d]", fd, length);
+ return -1;
+ }
+ if (fd >= 0 && write(fd, b, length) <= 0) {
+ TRACE_STRERROR("[ERROR] write FD[%d]", fd);
+ return -1;
+ }
+ return 0;
+}
+
+int dp_ipc_send_custom_type(int fd, void *value, size_t type_size)
+{
+ if (fd < 0) {
+ TRACE_ERROR("[ERROR] CHECK FD[%d]", fd);
+ return -1;
+ }
+ if (value == NULL) {
+ TRACE_ERROR("[ERROR] CHECK VALUE FD[%d]", fd);
+ return -1;
+ }
+ if (fd >= 0 && write(fd, value, type_size) <= 0) {
+ TRACE_STRERROR("[ERROR] write FD[%d]", fd);
+ return -1;
+ }
+ return 0;
+}
+
+int dp_ipc_read_custom_type(int fd, void *value, size_t type_size)
+{
+ if (fd < 0) {
+ TRACE_ERROR("[ERROR] CHECK FD[%d]", fd);
+ return -1;
+ }
+ if (value == NULL) {
+ TRACE_ERROR("[ERROR] CHECK VALUE FD[%d]", fd);
+ return -1;
+ }
+
+ ssize_t recv_bytes = read(fd, value, type_size);
+ if (recv_bytes < 0) {
+ TRACE_STRERROR("[ERROR] read FD[%d]", fd);
+ return -1;
+ }
+ return 0;
+}
+
+int dp_accept_socket_new()
+{
+ int sockfd = -1;
+ struct sockaddr_un listenaddr;
+
+ int n = sd_listen_fds(1);
+ if (n > 1) {
+ TRACE_STRERROR("too many file descriptors received");
+ return -1;
+ } else if (n == 1) {
+ int r;
+ if ((r = sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_STREAM, 1, DP_IPC, 0)) <= 0) {
+ TRACE_STRERROR("passed systemd file descriptor is of wrong type");
+ return -1;
+ }
+ sockfd = SD_LISTEN_FDS_START + 0;
+ } else {
+ if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ TRACE_STRERROR("failed to create socket");
+ return -1;
+ }
+
+ bzero(&listenaddr, sizeof(listenaddr));
+ listenaddr.sun_family = AF_UNIX;
+ strcpy(listenaddr.sun_path, DP_IPC);
+
+ if (bind(sockfd, (struct sockaddr *)&listenaddr, sizeof listenaddr) !=
+ 0) {
+ TRACE_STRERROR("[CRITICAL] bind");
+ close(sockfd);
+ return -1;
+ }
+
+ if (chmod(listenaddr.sun_path, 0777) < 0) {
+ TRACE_STRERROR("[CRITICAL] chmod");
+ close(sockfd);
+ return -1;
+ }
+
+ // need 3 socket per a group
+ if (listen(sockfd, DP_MAX_GROUP * 3) != 0) {
+ TRACE_STRERROR("[CRITICAL] listen");
+ close(sockfd);
+ return -1;
+ }
+ }
+ return sockfd;
+}
+
+int dp_socket_free(int sockfd)
+{
+ TRACE_DEBUG("[%d]", sockfd);
+ if (sockfd < 0)
+ return -1;
+ shutdown(sockfd, 0);
+ close(sockfd);
+ return 0;
+}
diff --git a/provider/download-provider-thread-queue.c b/provider/download-provider-thread-queue.c
new file mode 100755
index 0000000..b82618d
--- /dev/null
+++ b/provider/download-provider-thread-queue.c
@@ -0,0 +1,398 @@
+/*
+ * 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 <time.h>
+#include <sys/time.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <signal.h>
+
+#include <pthread.h>
+
+#include "download-provider.h"
+#include "download-provider-log.h"
+#include "download-provider-config.h"
+#include "download-provider-slots.h"
+#include "download-provider-socket.h"
+#include "download-provider-pthread.h"
+#include "download-provider-db.h"
+#include "download-provider-queue.h"
+#include "download-provider-network.h"
+#include "download-provider-da-interface.h"
+
+void dp_terminate(int signo);
+
+pthread_mutex_t g_dp_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t g_dp_queue_cond = PTHREAD_COND_INITIALIZER;
+
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief check network status is matched with the type setted by user
+/// @return matched : 0 mispatch : -1
+static int __is_matched_network(dp_network_type now_state, dp_network_type setted_state)
+{
+ if (now_state == setted_state
+ || now_state == DP_NETWORK_TYPE_ETHERNET
+ || setted_state == DP_NETWORK_TYPE_ALL)
+ return 0;
+ #if 0
+ if (setted_state == DP_NETWORK_TYPE_ALL
+ || setted_state == DP_NETWORK_TYPE_DATA_NETWORK
+ || now_state == DP_NETWORK_TYPE_WIFI
+ || now_state == DP_NETWORK_TYPE_ETHERNET
+ || (setted_state == DP_NETWORK_TYPE_WIFI
+ && (now_state == DP_NETWORK_TYPE_WIFI
+ || now_state == DP_NETWORK_TYPE_ETHERNET))
+ )
+ return 0;
+ #endif
+ return -1;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief the count of slot downloading currently
+static unsigned __get_active_count(dp_request_slots *requests)
+{
+ unsigned count = 0;
+ unsigned i = 0;
+
+ if (requests == NULL)
+ return 0;
+
+ for (i = 0; i < DP_MAX_REQUEST; i++) {
+ int locked = pthread_mutex_trylock(&requests[i].mutex);
+ // locking failure means it used by other thread.
+ if (locked == 0) {
+ if (requests[i].request != NULL) {
+ if (requests[i].request->state == DP_STATE_CONNECTING ||
+ requests[i].request->state == DP_STATE_DOWNLOADING)
+ count++;
+ }
+ CLIENT_MUTEX_UNLOCK(&requests[i].mutex);
+ }
+ }
+ return count;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief index of slot which last time is oldest
+static int __get_oldest_request_with_network(dp_request_slots *requests, dp_state_type state, dp_network_type now_state)
+{
+ int i = 0;
+ int oldest_time = (int)time(NULL);
+ oldest_time++; // most last time
+ int oldest_index = -1;
+
+ if (requests == NULL)
+ return -1;
+
+ for (i = 0; i < DP_MAX_REQUEST; i++) {
+ int locked = pthread_mutex_trylock(&requests[i].mutex);
+ // locking failure means it used by other thread.
+ if (locked == 0) {
+ if (requests[i].request != NULL) {
+ if (requests[i].request->state == state &&
+ requests[i].request->start_time > 0 &&
+ requests[i].request->start_time < oldest_time &&
+ __is_matched_network(now_state,
+ requests[i].request->network_type) == 0) {
+ oldest_time = requests[i].request->start_time;
+ oldest_index = i;
+ }
+ }
+ CLIENT_MUTEX_UNLOCK(&requests[i].mutex);
+ }
+ }
+ return oldest_index;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief THREAD function for calling da_start_download_with_extension.
+/// @warning da_start_download_with_extension can take long time
+/// @param the pointer of memory slot allocated for this request.
+/// @todo simplify da_start_download_with_extension
+static void *__request_download_start_agent(void *args)
+{
+ dp_error_type errcode = DP_ERROR_NONE;
+
+ dp_request_slots *request_slot = (dp_request_slots *) args;
+ if (request_slot == NULL) {
+ TRACE_ERROR("[NULL-CHECK] request_slot");
+ pthread_exit(NULL);
+ return 0;
+ }
+
+ CLIENT_MUTEX_LOCK(&request_slot->mutex);
+
+ if (request_slot->request == NULL) {
+ TRACE_ERROR("[NULL-CHECK] request");
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ pthread_exit(NULL);
+ return 0;
+ }
+
+ dp_request *request = request_slot->request;
+
+ if (dp_is_alive_download(request->agent_id)) {
+ errcode = dp_resume_agent_download(request->agent_id);
+ } else {
+ // call agent start function
+ errcode = dp_start_agent_download(request_slot);
+ }
+ // send to state callback.
+ if (errcode == DP_ERROR_NONE) {
+ // CONNECTING
+ request->state = DP_STATE_CONNECTING;
+ request->error = DP_ERROR_NONE;
+ request->startcount++;
+ if (dp_db_set_column
+ (request->id, DP_DB_TABLE_LOG, DP_DB_COL_STARTCOUNT,
+ DP_DB_COL_TYPE_INT, &request->startcount) < 0)
+ TRACE_ERROR("[ERROR][%d][SQL]", request->id);
+ } else if (errcode == DP_ERROR_TOO_MANY_DOWNLOADS) {
+ // PENDED
+ request->state = DP_STATE_QUEUED;
+ request->error = DP_ERROR_TOO_MANY_DOWNLOADS;
+ } else if (errcode == DP_ERROR_CONNECTION_FAILED) {
+ // FAILED
+ request->state = DP_STATE_FAILED;
+ request->error = DP_ERROR_CONNECTION_FAILED;
+ if (request->group != NULL &&
+ request->group->event_socket >= 0) {
+ dp_ipc_send_event(request->group->event_socket,
+ request->id, request->state, request->error, 0);
+ }
+ } else if (errcode == DP_ERROR_INVALID_STATE) {
+ // API FAILED
+ request->error = DP_ERROR_INVALID_STATE;
+ if (request->group != NULL &&
+ request->group->event_socket >= 0) {
+ dp_ipc_send_event(request->group->event_socket,
+ request->id, request->state, request->error, 0);
+ }
+ } else {
+ request->state = DP_STATE_FAILED;
+ request->error = errcode;
+ if (request->group != NULL &&
+ request->group->event_socket >= 0) {
+ dp_ipc_send_event(request->group->event_socket,
+ request->id, request->state, request->error, 0);
+ }
+ }
+ if (dp_db_request_update_status(request->id, request->state, request->error) < 0) {
+ TRACE_ERROR("[ERROR][%d][SQL]", request->id);
+ }
+
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+
+ if (errcode == DP_ERROR_NONE) {
+ TRACE_DEBUG("try other requests -----------------");
+ dp_thread_queue_manager_wake_up();
+ }
+
+ pthread_exit(NULL);
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief create thread.
+/// @warning if failed to create thread, change to PENED.
+/// @param the pointer of memory slot allocated for this request.
+static int __request_download_start_thread(dp_request_slots *request_slot)
+{
+ // declare all resources
+ pthread_t thread_pid;
+ pthread_attr_t thread_attr;
+
+ if (request_slot == NULL || request_slot->request == NULL) {
+ TRACE_ERROR("[CRITICAL] Invalid Address");
+ return -1;
+ }
+ dp_request *request = request_slot->request;
+
+ // initialize
+ if (pthread_attr_init(&thread_attr) != 0) {
+ TRACE_STRERROR("[ERROR][%d] pthread_attr_init", request->id);
+ return -1;
+ }
+ if (pthread_attr_setdetachstate(&thread_attr,
+ PTHREAD_CREATE_DETACHED) != 0) {
+ TRACE_STRERROR
+ ("[ERROR][%d] pthread_attr_setdetachstate", request->id);
+ return -1;
+ }
+
+ request->state = DP_STATE_CONNECTING;
+ if (pthread_create(&thread_pid, &thread_attr,
+ __request_download_start_agent, request_slot) != 0) {
+ TRACE_STRERROR("[ERROR][%d] pthread_create", request->id);
+ pthread_attr_destroy(&thread_attr);
+ request->state = DP_STATE_QUEUED;
+ return -1;
+ }
+ pthread_attr_destroy(&thread_attr);
+ return 0;
+}
+
+
+void dp_thread_queue_manager_wake_up()
+{
+ CLIENT_MUTEX_LOCK(&(g_dp_queue_mutex));
+ pthread_cond_signal(&g_dp_queue_cond);
+ CLIENT_MUTEX_UNLOCK(&(g_dp_queue_mutex));
+}
+
+
+// Main role : start download, check status of queue.
+// No timeout. Wake up by Signal be sent from other thread
+void *dp_thread_queue_manager(void *arg)
+{
+ int i;
+ int active_count;
+ dp_client_group *group = NULL;
+ dp_request *request = NULL;
+
+ dp_privates *privates = (dp_privates*)arg;
+ if (!privates) {
+ TRACE_ERROR("[CRITICAL] Invalid Address");
+ dp_terminate(SIGTERM);
+ pthread_exit(NULL);
+ return 0;
+ }
+
+ pthread_cond_init(&g_dp_queue_cond, NULL);
+ while (privates != NULL && privates->listen_fd >= 0) {
+
+ CLIENT_MUTEX_LOCK(&(g_dp_queue_mutex));
+ pthread_cond_wait(&g_dp_queue_cond, &g_dp_queue_mutex);
+
+ // request thread response instantly
+ CLIENT_MUTEX_UNLOCK(&(g_dp_queue_mutex));
+
+ if (privates == NULL || privates->requests == NULL ||
+ privates->listen_fd < 0) {
+ TRACE_DEBUG("Terminate Thread");
+ break;
+ }
+
+ // if failed to initialize the callback for checking connection
+ if (!privates->connection)
+ privates->network_status =
+ dp_get_network_connection_instant_status();
+
+#ifdef SUPPORT_WIFI_DIRECT
+ if (privates->is_connected_wifi_direct == 0) {
+ if (dp_network_wifi_direct_is_connected() == 0) {
+ // wifi-direct activated. pass.
+ privates->is_connected_wifi_direct = 1;
+ }
+ }
+#endif
+
+ if (privates->network_status == DP_NETWORK_TYPE_OFF &&
+ privates->is_connected_wifi_direct == 0) {
+ TRACE_DEBUG("[CHECK NETWORK STATE]");
+ continue;
+ }
+
+ active_count = __get_active_count(privates->requests);
+
+ TRACE_DEBUG("Status Queue: now active[%d] max[%d]",
+ active_count, DP_MAX_DOWNLOAD_AT_ONCE);
+
+ // Start Conditions
+ // 1. state is QUEUED
+ // 2. 1 QUEUED per 1 Group : need not to check max limitation.!!
+ // if no group, it will be started later.
+ // 3. most old last time : below conditions need max limitation.
+ // 4. match network connection type
+ // 5. wifi-direct on
+
+ // search group having 1 queued_count
+ // guarantee 1 instant download per 1 group
+ if (active_count >= DP_MAX_DOWNLOAD_AT_ONCE) {
+ for (i = 0; i < DP_MAX_REQUEST; i++) {
+ CLIENT_MUTEX_LOCK(&privates->requests[i].mutex);
+ request = privates->requests[i].request;
+ if (request != NULL && request->state == DP_STATE_QUEUED) {
+ group = privates->requests[i].request->group;
+ if (group && group->queued_count == 1) {
+ if (__is_matched_network
+ (privates->network_status,
+ request->network_type) == 0 ||
+ (privates->is_connected_wifi_direct == 1 &&
+ request->network_type ==
+ DP_NETWORK_TYPE_WIFI_DIRECT)) {
+ if (__request_download_start_thread(&privates->requests[i]) == 0) {
+ TRACE_DEBUG
+ ("[Guarantee Intant Download] Group [%s]", group->pkgname);
+ active_count++;
+ }
+ }
+ }
+ }
+ CLIENT_MUTEX_UNLOCK(&privates->requests[i].mutex);
+ }
+ }
+
+ if (active_count >= DP_MAX_DOWNLOAD_AT_ONCE) {
+ TRACE_DEBUG("[BUSY] Active[%d] Max[%d]",
+ active_count, DP_MAX_DOWNLOAD_AT_ONCE);
+ continue;
+ }
+
+ // can start download more.
+ // search oldest request
+ while(active_count < DP_MAX_DOWNLOAD_AT_ONCE) {
+
+#ifdef SUPPORT_WIFI_DIRECT
+ // WIFI-Direct first
+ if (privates->is_connected_wifi_direct == 1) {
+ i = __get_oldest_request_with_network(privates->requests,
+ DP_STATE_QUEUED, DP_NETWORK_TYPE_WIFI_DIRECT);
+ if (i >= 0) {
+ TRACE_DEBUG("Found WIFI-Direct request %d", i);
+ if (__request_download_start_thread(&privates->requests[i]) == 0)
+ active_count++;
+ continue;
+ }
+ }
+#endif
+
+ i = __get_oldest_request_with_network(privates->requests,
+ DP_STATE_QUEUED, privates->network_status);
+ if (i < 0) {
+ TRACE_DEBUG
+ ("No Request now active[%d] max[%d]",
+ active_count, DP_MAX_DOWNLOAD_AT_ONCE);
+ break;
+ }
+ TRACE_DEBUG("QUEUE Status now %d active %d/%d", i,
+ active_count, DP_MAX_DOWNLOAD_AT_ONCE);
+ __request_download_start_thread(&privates->requests[i]);
+ active_count++;
+ }
+ }
+ pthread_cond_destroy(&g_dp_queue_cond);
+ pthread_exit(NULL);
+ return 0;
+}
diff --git a/provider/download-provider-thread-request.c b/provider/download-provider-thread-request.c
new file mode 100755
index 0000000..6b03c08
--- /dev/null
+++ b/provider/download-provider-thread-request.c
@@ -0,0 +1,2158 @@
+/*
+ * 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 <time.h>
+#include <sys/time.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <signal.h>
+
+#include <app_manager.h>
+#include <sys/smack.h>
+#include <bundle.h>
+
+#include "download-provider.h"
+#include "download-provider-log.h"
+#include "download-provider-config.h"
+#include "download-provider-slots.h"
+#include "download-provider-socket.h"
+#include "download-provider-pthread.h"
+#include "download-provider-db.h"
+#include "download-provider-queue.h"
+#include "download-provider-request.h"
+#include "download-provider-network.h"
+#include "download-provider-da-interface.h"
+#include "download-provider-notification.h"
+
+void dp_terminate(int signo);
+
+static char *__print_command(dp_command_type cmd)
+{
+ switch(cmd)
+ {
+ case DP_CMD_CREATE :
+ return "CREATE";
+ case DP_CMD_START :
+ return "START";
+ case DP_CMD_PAUSE :
+ return "PAUSE";
+ case DP_CMD_CANCEL :
+ return "CANCEL";
+ case DP_CMD_DESTROY :
+ return "DESTROY";
+ case DP_CMD_FREE :
+ return "FREE";
+ case DP_CMD_ECHO :
+ return "ECHO";
+ case DP_CMD_SET_URL :
+ return "SET_URL";
+ case DP_CMD_SET_DESTINATION :
+ return "SET_DESTINATION";
+ case DP_CMD_SET_FILENAME :
+ return "SET_FILENAME";
+ case DP_CMD_SET_NOTIFICATION :
+ return "SET_NOTIFICATION";
+ case DP_CMD_SET_STATE_CALLBACK :
+ return "SET_STATE_CALLBACK";
+ case DP_CMD_SET_PROGRESS_CALLBACK :
+ return "SET_PROGRESS_CALLBACK";
+ case DP_CMD_SET_AUTO_DOWNLOAD :
+ return "SET_AUTO_DOWNLOAD";
+ case DP_CMD_SET_NETWORK_TYPE :
+ return "SET_NETWORK_TYPE";
+ case DP_CMD_SET_HTTP_HEADER :
+ return "SET_HTTP_HEADER";
+ case DP_CMD_DEL_HTTP_HEADER :
+ return "DEL_HTTP_HEADER";
+ case DP_CMD_GET_HTTP_HEADER :
+ return "GET_HTTP_HEADER";
+ case DP_CMD_GET_URL :
+ return "GET_URL";
+ case DP_CMD_GET_DESTINATION :
+ return "GET_DESTINATION";
+ case DP_CMD_GET_FILENAME :
+ return "GET_FILENAME";
+ case DP_CMD_GET_NOTIFICATION :
+ return "GET_NOTIFICATION";
+ case DP_CMD_GET_STATE_CALLBACK :
+ return "GET_STATE_CALLBACK";
+ case DP_CMD_GET_PROGRESS_CALLBACK :
+ return "GET_PROGRESS_CALLBACK";
+ case DP_CMD_GET_HTTP_HEADERS :
+ return "GET_HTTP_HEADERS";
+ case DP_CMD_GET_HTTP_HEADER_LIST:
+ return "GET_HTTP_HEADER_LIST";
+ case DP_CMD_ADD_EXTRA_PARAM :
+ return "ADD_EXTRA_PARAM";
+ case DP_CMD_GET_EXTRA_PARAM :
+ return "GET_EXTRA_PARAM";
+ case DP_CMD_REMOVE_EXTRA_PARAM :
+ return "REMOVE_EXTRA_PARAM";
+ case DP_CMD_GET_AUTO_DOWNLOAD :
+ return "GET_AUTO_DOWNLOAD";
+ case DP_CMD_GET_NETWORK_TYPE :
+ return "GET_NETWORK_TYPE";
+ case DP_CMD_GET_SAVED_PATH :
+ return "GET_SAVED_PATH";
+ case DP_CMD_GET_TEMP_SAVED_PATH :
+ return "GET_TEMP_SAVED_PATH";
+ case DP_CMD_GET_MIME_TYPE :
+ return "GET_MIME_TYPE";
+ case DP_CMD_GET_RECEIVED_SIZE :
+ return "GET_RECEIVED_SIZE";
+ case DP_CMD_GET_TOTAL_FILE_SIZE :
+ return "GET_TOTAL_FILE_SIZE";
+ case DP_CMD_GET_CONTENT_NAME :
+ return "GET_CONTENT_NAME";
+ case DP_CMD_GET_HTTP_STATUS :
+ return "GET_HTTP_STATUS";
+ case DP_CMD_GET_ETAG :
+ return "DP_CMD_GET_ETAG";
+ case DP_CMD_GET_STATE :
+ return "GET_STATE";
+ case DP_CMD_GET_ERROR :
+ return "ERROR";
+ case DP_CMD_SET_COMMAND_SOCKET :
+ return "SET_COMMAND_SOCKET";
+ case DP_CMD_SET_EVENT_SOCKET :
+ return "SET_EVENT_SOCKET";
+ case DP_CMD_SET_NOTIFICATION_BUNDLE:
+ return "SET_NOTIFICATION_BUNDLE";
+ case DP_CMD_SET_NOTIFICATION_TITLE:
+ return "SET_NOTIFICATION_TITLE";
+ case DP_CMD_SET_NOTIFICATION_DESCRIPTION:
+ return "SET_NOTIFICATION_DESCRIPTION";
+ case DP_CMD_SET_NOTIFICATION_TYPE:
+ return "SET_NOTIFICATION_TYPE";
+ case DP_CMD_GET_NOTIFICATION_BUNDLE:
+ return "GET_NOTIFICATION_BUNDLE";
+ case DP_CMD_GET_NOTIFICATION_TITLE:
+ return "GET_NOTIFICATION_TITLE";
+ case DP_CMD_GET_NOTIFICATION_DESCRIPTION:
+ return "GET_NOTIFICATION_DESCRIPTION";
+ case DP_CMD_GET_NOTIFICATION_TYPE:
+ return "GET_NOTIFICATION_TYPE";
+ default :
+ break;
+ }
+ return "UNKNOWN COMMAND";
+}
+
+/* compare two string */
+static int __cmp_string(char *s1, char *s2)
+{
+ size_t s1_len = 0;
+ size_t s2_len = 0;
+
+ if (s1 == NULL || s2 == NULL) {
+ TRACE_ERROR("[CHECK PARAM]");
+ return -1;
+ }
+
+ s1_len = strlen(s1);
+ if (s1_len <= 0) {
+ TRACE_ERROR("[CHECK PARAM] len[%d]", s1_len);
+ return -1;
+ }
+
+ s2_len = strlen(s2);
+ if (s2_len <= 0) {
+ TRACE_ERROR("[CHECK PARAM] len[%d]", s2_len);
+ return -1;
+ }
+
+ if (s1_len != s2_len) {
+ TRACE_ERROR("[DIFF] len[%d:%d]", s1_len, s2_len);
+ return -1;
+ }
+
+ if (strncmp(s1, s2, s1_len) != 0) {
+ TRACE_ERROR("[DIFF] cmp");
+ return -1;
+ }
+
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief return index of empty slot
+static int __get_empty_request_index(dp_request_slots *slots)
+{
+ int i = 0;
+
+ if (slots == NULL)
+ return -1;
+
+ for (i = 0; i < DP_MAX_REQUEST; i++) {
+ if (slots[i].request == NULL)
+ return i;
+ }
+ return -1;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief return index of slot having same ID
+/// @param ID want to search
+static int __get_same_request_index(dp_request_slots *slots, int id)
+{
+ int i = 0;
+
+ if (!slots || id < 0)
+ return -1;
+
+ for (i = 0; i < DP_MAX_REQUEST; i++) {
+ if (slots[i].request != NULL) {
+ if (slots[i].request->id == id)
+ return i;
+ }
+ }
+ return -1;
+}
+
+//////////////////////////////////////////////////////////////////////////
+/// @brief return custom value via IPC
+static void __send_return_custom_type(int fd, dp_error_type errcode, void *value, size_t type_size)
+{
+ dp_ipc_send_errorcode(fd, errcode);
+ dp_ipc_send_custom_type(fd, value, type_size);
+}
+
+static int __is_downloading(dp_state_type state)
+{
+ if (state == DP_STATE_CONNECTING || state == DP_STATE_DOWNLOADING)
+ return 0;
+ return -1;
+}
+
+static int __is_started(dp_state_type state)
+{
+ if (state == DP_STATE_QUEUED || __is_downloading(state) == 0)
+ return 0;
+ return -1;
+}
+
+static int __is_stopped(dp_state_type state)
+{
+ if (state == DP_STATE_COMPLETED || state == DP_STATE_FAILED ||
+ state == DP_STATE_CANCELED)
+ return 0;
+ return -1;
+}
+
+// cancel the downloading if no auto-download, then clear group
+static void __clear_group(dp_privates *privates, dp_client_group *group)
+{
+ dp_request *request = NULL;
+ int i = 0;
+
+ for (i = 0; i < DP_MAX_REQUEST; i++) {
+
+ CLIENT_MUTEX_LOCK(&privates->requests[i].mutex);
+
+ if (privates->requests[i].request == NULL) {
+ CLIENT_MUTEX_UNLOCK(&privates->requests[i].mutex);
+ continue;
+ }
+
+ request = privates->requests[i].request;
+
+ if (request->group == NULL || request->id <= 0 ||
+ request->group != group) {
+ CLIENT_MUTEX_UNLOCK(&privates->requests[i].mutex);
+ continue;
+ }
+
+ // if stopped, paused or not started yet, clear request
+ if (__is_started(request->state) < 0) {
+ TRACE_DEBUG("[FREE][%d] state[%s]", request->id,
+ dp_print_state(request->state));
+ CLIENT_MUTEX_UNLOCK(&privates->requests[i].mutex);
+ dp_request_slot_free(&privates->requests[i]);
+ continue;
+ }
+
+ // disconnect the request from group.
+ TRACE_SECURE_DEBUG("[DISCONNECT][%d] state:%s pkg:%s sock:%d",
+ request->id, dp_print_state(request->state),
+ request->group->pkgname, request->group->cmd_socket);
+ request->group = NULL;
+ request->state_cb = 0;
+ request->progress_cb = 0;
+
+ CLIENT_MUTEX_UNLOCK(&privates->requests[i].mutex);
+
+ }
+ // clear this group
+ dp_client_group_free(group);
+}
+
+static void __dp_remove_tmpfile(int id, dp_request *request)
+{
+ dp_error_type errorcode = DP_ERROR_NONE;
+ char *path =
+ dp_request_get_tmpsavedpath(id, request, &errorcode);
+ if (errorcode == DP_ERROR_NONE &&
+ (path != NULL && strlen(path) > 0) &&
+ dp_is_file_exist(path) == 0) {
+ TRACE_SECURE_DEBUG("[REMOVE][%d] TEMP FILE [%s]", id, path);
+ if (unlink(path) != 0)
+ TRACE_STRERROR("[ERROR][%d] remove file", id);
+ }
+ free(path);
+}
+
+static int __dp_check_valid_directory(dp_request *request, char *dir)
+{
+ int ret = -1;
+ int ret_val = 0;
+ char *dir_label = NULL;
+ struct stat dir_state;
+
+ ret_val = stat(dir, &dir_state);
+ if (ret_val == 0) {
+ dp_credential cred;
+ if (request->group == NULL) {
+ cred.uid = dp_db_cond_get_int(DP_DB_TABLE_GROUPS,
+ DP_DB_GROUPS_COL_UID,
+ DP_DB_GROUPS_COL_PKG,
+ DP_DB_COL_TYPE_TEXT, request->packagename);
+ cred.gid = dp_db_cond_get_int(DP_DB_TABLE_GROUPS,
+ DP_DB_GROUPS_COL_GID,
+ DP_DB_GROUPS_COL_PKG,
+ DP_DB_COL_TYPE_TEXT, request->packagename);
+ } else {
+ cred = request->group->credential;
+ }
+ if (dir_state.st_uid == cred.uid
+ && (dir_state.st_mode & (S_IRUSR | S_IWUSR))
+ == (S_IRUSR | S_IWUSR)) {
+ ret = 0;
+ } else if (dir_state.st_gid == cred.gid
+ && (dir_state.st_mode & (S_IRGRP | S_IWGRP))
+ == (S_IRGRP | S_IWGRP)) {
+ ret = 0;
+ } else if ((dir_state.st_mode & (S_IROTH | S_IWOTH))
+ == (S_IROTH | S_IWOTH)) {
+ ret = 0;
+ }
+ }
+
+ if (ret != 0)
+ return ret;
+
+ ret_val = smack_getlabel(dir, &dir_label, SMACK_LABEL_ACCESS);
+ if (ret_val != 0) {
+ TRACE_SECURE_ERROR("[ERROR][%d][SMACK ERROR]", request->id);
+ free(dir_label);
+ return -1;
+ }
+
+ char *smack_label = NULL;
+ if (request->group == NULL) {
+ // get smack_label from sql
+ smack_label = dp_db_cond_get_text(DP_DB_TABLE_GROUPS,
+ DP_DB_GROUPS_COL_SMACK_LABEL, DP_DB_GROUPS_COL_PKG,
+ DP_DB_COL_TYPE_TEXT, request->packagename);
+ if (smack_label != NULL) {
+ ret_val = smack_have_access(smack_label, dir_label, "rw");
+ free(smack_label);
+ }
+ } else {
+ if (request->group->smack_label != NULL) {
+ ret_val = smack_have_access(request->group->smack_label, dir_label, "rw");
+ }
+ }
+ if (ret_val == 0) {
+ TRACE_SECURE_ERROR("[ERROR][%d][SMACK NO RULE]", request->id);
+ ret = -1;
+ } else if (ret_val < 0){
+ TRACE_SECURE_ERROR("[ERROR][%d][SMACK ERROR]", request->id);
+ ret = -1;
+ }
+ free(dir_label);
+ return ret;
+}
+
+static int __dp_call_cancel_agent(dp_request *request)
+{
+ int ret = -1;
+ if (request != NULL) {
+ if (request->agent_id >= 0) {
+ TRACE_INFO("[%d]cancel_agent(%d) state:%s", request->id,
+ request->agent_id, dp_print_state(request->state));
+ if (dp_cancel_agent_download(request->agent_id) == 0)
+ ret = 0;
+ } else {
+ TRACE_DEBUG("[CHECK] agent-id");
+ }
+ }
+ return ret;
+}
+
+static int __dp_add_extra_param(int fd, int id)
+{
+ dp_error_type ret = DP_ERROR_NONE;
+ int length = 0;
+ int i = 0;
+ unsigned values_length = 0;
+ char *key = NULL;
+ char **values = NULL;
+
+ if (fd < 0) {
+ TRACE_ERROR("[CHECK] socket");
+ return DP_ERROR_IO_ERROR;
+ }
+ if (id < 0) {
+ TRACE_ERROR("[CHECK] ID");
+ return DP_ERROR_INVALID_PARAMETER;
+ }
+
+ if (dp_ipc_read_custom_type(fd, &length, sizeof(int)) < 0) {
+ TRACE_ERROR("[ERROR][%d] [DP_ERROR_IO_ERROR]", id);
+ ret = DP_ERROR_IO_ERROR;
+ } else {
+ TRACE_DEBUG("[RECV] length %d", length);
+ if (length <= 0) {
+ ret = DP_ERROR_INVALID_PARAMETER;
+ } else {
+ key = dp_ipc_read_string(fd);
+ if (key == NULL) {
+ TRACE_ERROR("[ERROR][%d][IO_ERROR] key", id);
+ ret = DP_ERROR_IO_ERROR;
+ } else {
+ if (length > 1) {
+ TRACE_SECURE_DEBUG("[RECV] key : %s", key);
+ // get values
+ values = (char **)calloc((length - 1), sizeof(char *));
+ if (values == NULL) {
+ ret = DP_ERROR_OUT_OF_MEMORY;
+ } else {
+ for (i = 0; i < length - 1; i++) {
+ values[i] = dp_ipc_read_string(fd);
+ if (values[i] == NULL) {
+ ret = DP_ERROR_IO_ERROR;
+ break;
+ }
+ values_length++;
+ }
+ }
+ } else {
+ TRACE_ERROR("[ERROR][%d] length [%d]", id, length);
+ ret = DP_ERROR_INVALID_PARAMETER;
+ }
+ }
+ }
+ }
+ if (ret == DP_ERROR_NONE) {
+ // store to DB
+ for (i = 0; i < length - 1; i++) {
+ int conds_count = 3;
+ db_conds_list_fmt conds_p[conds_count]; // id + key + value
+ memset(&conds_p, 0x00, conds_count * sizeof(db_conds_list_fmt));
+ conds_p[0].column = DP_DB_COL_ID;
+ conds_p[0].type = DP_DB_COL_TYPE_INT;
+ conds_p[0].value = &id;
+ conds_p[1].column = DP_DB_COL_EXTRA_KEY;
+ conds_p[1].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[1].value = key;
+ conds_p[2].column = DP_DB_COL_EXTRA_VALUE;
+ conds_p[2].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[2].value = values[i];
+ int check_key =
+ dp_db_get_conds_rows_count(DP_DB_TABLE_NOTIFICATION,
+ DP_DB_COL_ID, "AND", conds_count, conds_p);
+ if (check_key <= 0) { // create newly
+ // insert
+ if (dp_db_insert_columns(DP_DB_TABLE_NOTIFICATION,
+ conds_count, conds_p) < 0) {
+ if (dp_db_is_full_error() == 0) {
+ TRACE_ERROR("[SQLITE_FULL][%d]", id);
+ ret = DP_ERROR_NO_SPACE;
+ } else {
+ ret = DP_ERROR_OUT_OF_MEMORY;
+ }
+ break;
+ }
+ } // else skip. already exist
+ }
+ }
+ free(key);
+ for (i = 0; i < values_length; i++) {
+ free(values[i]);
+ }
+ free(values);
+ return ret;
+}
+
+static int __dp_get_extra_param_values(int fd, int id, char ***values,
+ unsigned *count)
+{
+ dp_error_type ret = DP_ERROR_NONE;
+ int length = 0;
+ char *key = NULL;
+ char **rows_array = NULL;
+
+ if (fd < 0) {
+ TRACE_ERROR("[CHECK] socket");
+ return DP_ERROR_IO_ERROR;
+ }
+ if (id < 0) {
+ TRACE_ERROR("[CHECK] ID");
+ return DP_ERROR_INVALID_PARAMETER;
+ }
+
+ if (dp_ipc_read_custom_type(fd, &length, sizeof(int)) < 0) {
+ TRACE_ERROR("[ERROR][%d] [DP_ERROR_IO_ERROR]", id);
+ ret = DP_ERROR_IO_ERROR;
+ } else {
+ TRACE_DEBUG("[RECV] length %d", length);
+ if (length != 1) { // only a key
+ ret = DP_ERROR_INVALID_PARAMETER;
+ } else {
+ if ((key = dp_ipc_read_string(fd)) == NULL) {
+ TRACE_ERROR("[ERROR][%d][IO_ERROR] key", id);
+ ret = DP_ERROR_IO_ERROR;
+ }
+ }
+ }
+ if (ret == DP_ERROR_NONE) {
+ int conds_count = 2;
+ db_conds_list_fmt conds_p[conds_count]; // id + key + value
+ memset(&conds_p, 0x00, conds_count * sizeof(db_conds_list_fmt));
+ conds_p[0].column = DP_DB_COL_ID;
+ conds_p[0].type = DP_DB_COL_TYPE_INT;
+ conds_p[0].value = &id;
+ conds_p[1].column = DP_DB_COL_EXTRA_KEY;
+ conds_p[1].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[1].value = key;
+ int check_rows = dp_db_get_conds_rows_count
+ (DP_DB_TABLE_NOTIFICATION, DP_DB_COL_EXTRA_VALUE, "AND",
+ conds_count, conds_p);
+ if (check_rows <= 0) {
+ // NO_DATA
+ ret = DP_ERROR_NO_DATA;
+ } else {
+ rows_array = (char **)calloc(check_rows, sizeof(char *));
+ if (rows_array == NULL) {
+ ret = DP_ERROR_OUT_OF_MEMORY;
+ } else {
+ // getting the array from DB with key condition
+ int rows_count =
+ dp_db_get_conds_list(DP_DB_TABLE_NOTIFICATION,
+ DP_DB_COL_EXTRA_VALUE, DP_DB_COL_TYPE_TEXT,
+ (void **)rows_array, check_rows, -1, NULL, NULL,
+ "AND", conds_count, conds_p);
+ if (rows_count <= 0) {
+ // NO_DATA
+ ret = DP_ERROR_NO_DATA;
+ free(rows_array);
+ } else {
+ *count = rows_count;
+ *values = rows_array;
+ }
+ }
+ free(key);
+ }
+ }
+ return ret;
+}
+
+static int __dp_remove_extra_param(int fd, int id)
+{
+ dp_error_type ret = DP_ERROR_NONE;
+ char *key = NULL;
+
+ if (fd < 0) {
+ TRACE_ERROR("[CHECK] socket");
+ return DP_ERROR_IO_ERROR;
+ }
+ if (id < 0) {
+ TRACE_ERROR("[CHECK] ID");
+ return DP_ERROR_INVALID_PARAMETER;
+ }
+
+ if ((key = dp_ipc_read_string(fd)) == NULL) {
+ TRACE_ERROR("[ERROR][%d] INVALID_PARAMETER", id);
+ ret = DP_ERROR_IO_ERROR;
+ }
+ if (ret == DP_ERROR_NONE) {
+ if (dp_db_cond_remove(id, DP_DB_TABLE_NOTIFICATION,
+ DP_DB_COL_EXTRA_KEY, DP_DB_COL_TYPE_TEXT, key) < 0) {
+ TRACE_ERROR("[fail][%d][sql]", id);
+ TRACE_SECURE_ERROR("[fail]key:%s", key);
+ ret = DP_ERROR_OUT_OF_MEMORY;
+ }
+ }
+ TRACE_DEBUG("[ERROR][%d][%s]", id, dp_print_errorcode(ret));
+ TRACE_SECURE_DEBUG("key:%s", key);
+ free(key);
+ return ret;
+}
+
+static int __dp_get_http_header_fields(int fd, int id, char ***values,
+ unsigned *count)
+{
+ dp_error_type ret = DP_ERROR_NONE;
+ char **rows_array = NULL;
+
+ if (fd < 0) {
+ TRACE_ERROR("[CHECK] socket");
+ return DP_ERROR_IO_ERROR;
+ }
+ if (id < 0) {
+ TRACE_ERROR("[CHECK] ID");
+ return DP_ERROR_INVALID_PARAMETER;
+ }
+
+ db_conds_list_fmt conds_p;
+ conds_p.column = DP_DB_COL_ID;
+ conds_p.type = DP_DB_COL_TYPE_INT;
+ conds_p.value = &id;
+ conds_p.is_like = 0;
+ int check_rows = dp_db_get_conds_rows_count
+ (DP_DB_TABLE_HTTP_HEADERS, DP_DB_COL_HEADER_FIELD, "AND",
+ 1, &conds_p);
+ if (check_rows <= 0) {
+ // NO_DATA
+ ret = DP_ERROR_NO_DATA;
+ } else {
+ rows_array = (char **)calloc(check_rows, sizeof(char *));
+ if (rows_array == NULL) {
+ ret = DP_ERROR_OUT_OF_MEMORY;
+ } else {
+ int rows_count =
+ dp_db_get_conds_list(DP_DB_TABLE_HTTP_HEADERS,
+ DP_DB_COL_HEADER_FIELD, DP_DB_COL_TYPE_TEXT,
+ (void **)rows_array, check_rows, -1, NULL, NULL,
+ "AND", 1, &conds_p);
+ if (rows_count <= 0) {
+ // NO_DATA
+ ret = DP_ERROR_NO_DATA;
+ free(rows_array);
+ } else {
+ *count = rows_count;
+ *values = rows_array;
+ }
+ }
+ }
+ return ret;
+}
+
+static int __dp_set_group_new(int clientfd, dp_group_slots *groups,
+ dp_credential credential, fd_set *listen_fdset)
+{
+ // search in groups.
+ // if same group. update it.
+ // search same pkg or pid in groups
+ int pkg_len = 0;
+ int i = 0;
+ struct timeval tv_timeo; // 2.5 sec
+ char *pkgname = NULL;
+ char *smack_label = NULL;
+ int ret = 0;
+
+ tv_timeo.tv_sec = 2;
+ tv_timeo.tv_usec = 500000;
+ if (setsockopt(clientfd, SOL_SOCKET, SO_RCVTIMEO, &tv_timeo,
+ sizeof(tv_timeo)) < 0) {
+ TRACE_STRERROR("[CRITICAL] setsockopt SO_RCVTIMEO");
+ return -1;
+ }
+
+ // getting the package name via pid
+ if (app_manager_get_package(credential.pid, &pkgname) ==
+ APP_MANAGER_ERROR_NONE) {
+ TRACE_SECURE_DEBUG("package : %s", pkgname);
+ } else
+ TRACE_ERROR("[CRITICAL] app_manager_get_package");
+
+ //// TEST CODE ... to allow sample client ( no package name ).
+ if (pkgname == NULL) {
+ pkgname = dp_strdup("unknown_app");
+ TRACE_DEBUG("default package naming : %s", pkgname);
+ }
+
+ if (pkgname == NULL) {
+ TRACE_ERROR("[CRITICAL] app_manager_get_package");
+ return -1;
+ }
+ if ((pkg_len = strlen(pkgname)) <= 0) {
+ TRACE_ERROR("[CRITICAL] pkgname:%s", pkgname);
+ free(pkgname);
+ return -1;
+ }
+
+ for (i = 0; i < DP_MAX_GROUP; i++) {
+ if (groups[i].group != NULL) {
+ // clean garbage slot
+ if (groups[i].group->cmd_socket <= 0 ||
+ groups[i].group->pkgname == NULL) {
+ dp_client_group_free(groups[i].group);
+ groups[i].group = NULL;
+ continue;
+ }
+ if (strlen(groups[i].group->pkgname) == pkg_len &&
+ strncmp(groups[i].group->pkgname, pkgname,
+ pkg_len) == 0 ) {
+ // Found Same Group
+ TRACE_SECURE_INFO("UPDATE Group: slot:%d pid:%d sock:%d [%s]",
+ i, credential.pid, clientfd, pkgname);
+ if (groups[i].group->cmd_socket > 0 &&
+ groups[i].group->cmd_socket != clientfd) {
+ FD_CLR(groups[i].group->cmd_socket, listen_fdset);
+ dp_socket_free(groups[i].group->cmd_socket);
+ }
+ groups[i].group->cmd_socket = clientfd;
+ free(pkgname);
+ return 0;
+ }
+ }
+ }
+
+ // new client
+ // search emtpy slot in groups
+ for (i = 0; i < DP_MAX_GROUP; i++)
+ if (groups[i].group == NULL)
+ break;
+ if (i >= DP_MAX_GROUP) {
+ TRACE_ERROR("[CRITICAL] No space in groups");
+ free(pkgname);
+ return -1;
+ }
+ // allocation
+ groups[i].group =
+ (dp_client_group *)calloc(1, sizeof(dp_client_group));
+ if (groups[i].group == NULL) {
+ TRACE_ERROR("[CRITICAL] calloc, ignore this client");
+ free(pkgname);
+ return -1;
+ }
+
+ // fill info
+ groups[i].group->cmd_socket = clientfd;
+ groups[i].group->event_socket = -1;
+ groups[i].group->queued_count = 0;
+ groups[i].group->pkgname = dp_strdup(pkgname);
+ groups[i].group->credential.pid = credential.pid;
+ groups[i].group->credential.uid = credential.uid;
+ groups[i].group->credential.gid = credential.gid;
+
+ int conds_count = 4;
+ db_conds_list_fmt conds_p[conds_count];
+ memset(&conds_p, 0x00, conds_count * sizeof(db_conds_list_fmt));
+ conds_p[0].column = DP_DB_GROUPS_COL_UID;
+ conds_p[0].type = DP_DB_COL_TYPE_INT;
+ conds_p[0].value = &credential.uid;
+ conds_p[1].column = DP_DB_GROUPS_COL_GID;
+ conds_p[1].type = DP_DB_COL_TYPE_INT;
+ conds_p[1].value = &credential.gid;
+ conds_p[2].column = DP_DB_GROUPS_COL_PKG;
+ conds_p[2].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[2].value = pkgname;
+
+ if (dp_is_smackfs_mounted() == 1) {
+ ret = smack_new_label_from_socket(clientfd, &smack_label);
+ if (ret < 0) {
+ TRACE_ERROR("[CRITICAL] cannot get smack label");
+ free(pkgname);
+ free(smack_label);
+ return -1;
+ }
+ TRACE_SECURE_INFO("credential label:[%s]", smack_label);
+ groups[i].group->smack_label = smack_label;
+
+ conds_p[3].column = DP_DB_GROUPS_COL_SMACK_LABEL;
+ conds_p[3].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[3].value = smack_label;
+ } else {
+ conds_count = 3; // ignore smack label
+ groups[i].group->smack_label = NULL;
+ }
+
+ if (dp_db_insert_columns(DP_DB_TABLE_GROUPS, conds_count, conds_p) < 0) {
+ free(pkgname);
+ free(smack_label);
+ if (dp_db_is_full_error() == 0)
+ TRACE_ERROR("[SQLITE_FULL]");
+ return -1;
+ }
+
+ TRACE_SECURE_INFO("New Group: slot:%d pid:%d sock:%d [%s]", i,
+ credential.pid, clientfd, pkgname);
+ free(pkgname);
+ return 0;
+}
+
+
+static int __dp_set_group_event_sock(int clientfd,
+ dp_group_slots *groups, dp_credential credential)
+{
+ int i = 0;
+
+ TRACE_DEBUG("Check event pid:%d sock:%d", credential.pid, clientfd);
+ // search same pid in groups
+ for (i = 0; i < DP_MAX_GROUP; i++) {
+ if (groups[i].group != NULL &&
+ groups[i].group->credential.pid == credential.pid) {
+ if (groups[i].group->event_socket > 0 &&
+ groups[i].group->event_socket != clientfd)
+ dp_socket_free(groups[i].group->event_socket);
+ groups[i].group->event_socket = clientfd;
+ TRACE_SECURE_INFO
+ ("Found Group : slot:%d pid:%d csock:%d esock:%d [%s]",
+ i, credential.pid, groups[i].group->cmd_socket,
+ clientfd, groups[i].group->pkgname);
+ break;
+ }
+ }
+ if (i >= DP_MAX_GROUP) {
+ TRACE_ERROR
+ ("[CRITICAL] Not found group for PID [%d]", credential.pid);
+ return -1;
+ }
+ return 0;
+}
+
+static dp_error_type __dp_do_get_command(int sock, dp_command* cmd, dp_request *request)
+{
+ unsigned is_checked = 1;
+ dp_error_type errorcode = DP_ERROR_NONE;
+
+ char *read_str = NULL;
+ // No read(), write a string
+ switch(cmd->cmd) {
+ case DP_CMD_GET_URL:
+ read_str = dp_request_get_url(cmd->id, &errorcode);
+ break;
+ case DP_CMD_GET_DESTINATION:
+ read_str = dp_request_get_destination(cmd->id, request, &errorcode);
+ break;
+ case DP_CMD_GET_FILENAME:
+ read_str = dp_request_get_filename(cmd->id, request, &errorcode);
+ break;
+ case DP_CMD_GET_SAVED_PATH:
+ read_str = dp_request_get_savedpath(cmd->id, request, &errorcode);
+ break;
+ case DP_CMD_GET_TEMP_SAVED_PATH:
+ read_str = dp_request_get_tmpsavedpath(cmd->id, request, &errorcode);
+ break;
+ case DP_CMD_GET_MIME_TYPE:
+ read_str = dp_request_get_mimetype(cmd->id, request, &errorcode);
+ break;
+ case DP_CMD_GET_CONTENT_NAME:
+ read_str = dp_request_get_contentname(cmd->id, request, &errorcode);
+ break;
+ case DP_CMD_GET_ETAG:
+ read_str = dp_request_get_etag(cmd->id, request, &errorcode);
+ break;
+ case DP_CMD_GET_NOTIFICATION_TITLE:
+ read_str = dp_request_get_title(cmd->id, request, &errorcode);
+ break;
+ case DP_CMD_GET_NOTIFICATION_DESCRIPTION:
+ read_str = dp_request_get_description(cmd->id, request, &errorcode);
+ break;
+ default:
+ is_checked = 0;
+ break;
+ }
+ if (is_checked == 1) {
+ if (read_str == NULL || strlen(read_str) < 1)
+ errorcode = DP_ERROR_NO_DATA;
+ dp_ipc_send_errorcode(sock, errorcode);
+ if (errorcode == DP_ERROR_NONE) {
+ dp_ipc_send_string(sock, read_str);
+ } else {
+ TRACE_ERROR("[ERROR][%d][%s][%s]", cmd->id,
+ __print_command(cmd->cmd), dp_print_errorcode(errorcode));
+ }
+ free(read_str);
+ return errorcode;
+ }
+
+ // No read(), write a integer variable
+ int read_int = 0;
+ errorcode = DP_ERROR_NONE;
+ is_checked = 1;
+ switch(cmd->cmd) {
+ case DP_CMD_GET_NOTIFICATION:
+ read_int = dp_db_get_int_column(cmd->id, DP_DB_TABLE_REQUEST_INFO,
+ DP_DB_COL_NOTIFICATION_ENABLE);
+ break;
+ case DP_CMD_GET_AUTO_DOWNLOAD:
+ read_int = dp_db_get_int_column(cmd->id, DP_DB_TABLE_REQUEST_INFO,
+ DP_DB_COL_AUTO_DOWNLOAD);
+ break;
+ case DP_CMD_GET_NETWORK_TYPE:
+ read_int = dp_db_get_int_column(cmd->id, DP_DB_TABLE_REQUEST_INFO,
+ DP_DB_COL_NETWORK_TYPE);
+ break;
+ case DP_CMD_GET_HTTP_STATUS:
+ read_int = dp_db_get_int_column(cmd->id, DP_DB_TABLE_DOWNLOAD_INFO,
+ DP_DB_COL_HTTP_STATUS);
+ break;
+ case DP_CMD_GET_STATE:
+ if (request == NULL) {
+ read_int = dp_db_get_state(cmd->id);
+ } else {
+ read_int = request->state;
+ }
+ break;
+ case DP_CMD_GET_NOTIFICATION_TYPE:
+ TRACE_DEBUG("DP_CMD_GET_NOTIFICATION_TYPE");
+ read_int = dp_request_get_noti_type(cmd->id, request, &errorcode);
+ break;
+ case DP_CMD_GET_ERROR:
+ if (request == NULL) {
+ read_int = dp_db_get_int_column(cmd->id,
+ DP_DB_TABLE_LOG, DP_DB_COL_ERRORCODE);
+ } else {
+ read_int = request->error;
+ }
+ break;
+ default:
+ is_checked = 0;
+ break;
+ }
+ if (is_checked == 1) {
+ if (read_int < 0)
+ errorcode = DP_ERROR_NO_DATA;
+ dp_ipc_send_errorcode(sock, errorcode);
+ if (errorcode == DP_ERROR_NONE) {
+ dp_ipc_send_custom_type(sock, &read_int, sizeof(int));
+ } else {
+ TRACE_ERROR("[ERROR][%d][%s][%s]", cmd->id,
+ __print_command(cmd->cmd), dp_print_errorcode(errorcode));
+ }
+ return errorcode;
+ }
+
+ // No read(), write a long long variable
+ unsigned long long recv_long = 0;
+ errorcode = DP_ERROR_NONE;
+ is_checked = 1;
+ switch(cmd->cmd) {
+ case DP_CMD_GET_RECEIVED_SIZE:
+ if (request == NULL)
+ errorcode = DP_ERROR_NO_DATA;
+ else
+ recv_long = request->received_size;
+ break;
+ case DP_CMD_GET_TOTAL_FILE_SIZE:
+ if (request != NULL) {
+ recv_long = request->file_size;
+ } else {
+ long long file_size =
+ dp_db_get_int64_column(cmd->id,
+ DP_DB_TABLE_DOWNLOAD_INFO, DP_DB_COL_CONTENT_SIZE);
+ if (file_size < 0)
+ errorcode = DP_ERROR_NO_DATA;
+ else // casting
+ recv_long = file_size;
+ }
+ break;
+ default:
+ is_checked = 0;
+ break;
+ }
+ if (is_checked == 1) {
+ dp_ipc_send_errorcode(sock, errorcode);
+ if (errorcode == DP_ERROR_NONE) {
+ dp_ipc_send_custom_type(sock, &recv_long,
+ sizeof(unsigned long long));
+ } else {
+ TRACE_ERROR("[ERROR][%d][%s][%s]", cmd->id,
+ __print_command(cmd->cmd), dp_print_errorcode(errorcode));
+ }
+ return errorcode;
+ }
+
+ // No read(), write a bundle variable
+ bundle_raw *b_raw = NULL;
+ int length = -1;
+ char *column = NULL;
+ errorcode = DP_ERROR_NONE;
+ is_checked = 1;
+ switch(cmd->cmd) {
+ case DP_CMD_GET_NOTIFICATION_BUNDLE:
+ TRACE_DEBUG("DP_CMD_GET_NOTIFICATION_BUNDLE");
+ dp_ipc_send_errorcode(sock, DP_ERROR_NONE);
+ if ((dp_ipc_read_custom_type(sock, &read_int, sizeof(int)) < 0)) {
+ TRACE_ERROR("DP_CMD_GET_NOTIFICATION_BUNDLE read fail");
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ switch(read_int) {
+ case DP_NOTIFICATION_BUNDLE_TYPE_ONGOING:
+ column = DP_DB_COL_RAW_BUNDLE_ONGOING;
+ break;
+ case DP_NOTIFICATION_BUNDLE_TYPE_COMPLETE:
+ column = DP_DB_COL_RAW_BUNDLE_COMPLETE;
+ break;
+ case DP_NOTIFICATION_BUNDLE_TYPE_FAILED:
+ column = DP_DB_COL_RAW_BUNDLE_FAIL;
+ break;
+ default:
+ TRACE_ERROR("[CHECK TYPE][%d]", read_int);
+ errorcode = DP_ERROR_INVALID_PARAMETER;
+ break;
+ }
+ b_raw = dp_request_get_bundle(cmd->id, request,
+ &errorcode, column, &length);
+ break;
+ default:
+ is_checked = 0;
+ break;
+ }
+ if (is_checked == 1) {
+ dp_ipc_send_errorcode(sock, errorcode);
+ if (errorcode == DP_ERROR_NONE) {
+ dp_ipc_send_bundle(sock, b_raw, length);
+ } else {
+ TRACE_ERROR("[ERROR][%d][%s][%s]", cmd->id,
+ __print_command(cmd->cmd), dp_print_errorcode(errorcode));
+ }
+ bundle_free_encoded_rawdata(&b_raw);
+ return errorcode;
+ }
+
+ dp_ipc_send_errorcode(sock, DP_ERROR_NONE);
+ // complex read() and write().
+ char *read_str2 = NULL;
+ errorcode = DP_ERROR_NONE;
+ read_str = NULL;
+ is_checked = 1;
+ switch(cmd->cmd) {
+ case DP_CMD_GET_HTTP_HEADER:
+ if ((read_str = dp_ipc_read_string(sock)) == NULL) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ read_str2 = dp_db_cond_get_text_column(cmd->id,
+ DP_DB_TABLE_HTTP_HEADERS, DP_DB_COL_HEADER_DATA,
+ DP_DB_COL_HEADER_FIELD, DP_DB_COL_TYPE_TEXT, read_str);
+ if (read_str2 == NULL)
+ errorcode = DP_ERROR_NO_DATA;
+ dp_ipc_send_errorcode(sock, errorcode);
+ if (errorcode == DP_ERROR_NONE)
+ dp_ipc_send_string(sock, read_str2);
+ break;
+ case DP_CMD_GET_HTTP_HEADER_LIST:
+ {
+ char **values = NULL;
+ unsigned rows_count = 0;
+ errorcode = __dp_get_http_header_fields(sock,
+ cmd->id, &values, &rows_count);
+ if (errorcode == DP_ERROR_NONE) {
+ __send_return_custom_type(sock, DP_ERROR_NONE,
+ &rows_count, sizeof(int));
+ // sending strings
+ int i = 0;
+ for (i = 0; i < rows_count; i++) {
+ if (dp_ipc_send_string(sock, values[i]) < 0)
+ break;
+ }
+ for (i = 0; i < rows_count; i++)
+ free(values[i]);
+ } else {
+ if (errorcode != DP_ERROR_IO_ERROR)
+ dp_ipc_send_errorcode(sock, errorcode);
+ }
+ free(values);
+ break;
+ }
+ case DP_CMD_GET_EXTRA_PARAM:
+ {
+ char **values = NULL;
+ unsigned rows_count = 0;
+ errorcode = __dp_get_extra_param_values(sock,
+ cmd->id, &values, &rows_count);
+ if (errorcode == DP_ERROR_NONE) {
+ __send_return_custom_type(sock, DP_ERROR_NONE,
+ &rows_count, sizeof(int));
+ // sending strings
+ int i = 0;
+ for (i = 0; i < rows_count; i++) {
+ if (dp_ipc_send_string(sock, values[i]) < 0)
+ break;
+ }
+ for (i = 0; i < rows_count; i++)
+ free(values[i]);
+ } else {
+ if (errorcode != DP_ERROR_IO_ERROR)
+ dp_ipc_send_errorcode(sock, errorcode);
+ }
+ free(values);
+ break;
+ }
+ default:
+ is_checked = 0;
+ break;
+ }
+ if (is_checked == 1) {
+ if (errorcode != DP_ERROR_NONE) {
+ TRACE_ERROR("[ERROR][%d][%s][%s]", cmd->id,
+ __print_command(cmd->cmd), dp_print_errorcode(errorcode));
+ }
+ free(read_str);
+ free(read_str2);
+ return errorcode;
+ }
+ return DP_ERROR_UNKNOWN;
+}
+
+static dp_error_type __dp_do_set_command(int sock, dp_command *cmd, dp_request *request)
+{
+ unsigned is_checked = 1;
+ int read_int = 0;
+ dp_error_type errorcode = DP_ERROR_NONE;
+ char *read_str = NULL;
+ bundle_raw *b_raw = NULL;
+ unsigned bundle_length = 0;
+ int noti_bundle_type = 0;
+
+ dp_ipc_send_errorcode(sock, DP_ERROR_NONE);
+ // read a interger or a string, return errorcode.
+ errorcode = DP_ERROR_NONE;
+ switch(cmd->cmd) {
+ case DP_CMD_SET_STATE_CALLBACK:
+ if (dp_ipc_read_custom_type(sock, &read_int, sizeof(int)) < 0) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ errorcode = dp_request_set_state_event(cmd->id, request, read_int);
+ break;
+ case DP_CMD_SET_PROGRESS_CALLBACK:
+ if (dp_ipc_read_custom_type(sock, &read_int, sizeof(int)) < 0) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ errorcode = dp_request_set_progress_event(cmd->id, request, read_int);
+ break;
+ case DP_CMD_SET_NETWORK_TYPE:
+ if (dp_ipc_read_custom_type(sock, &read_int, sizeof(int)) < 0) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ if (read_int == DP_NETWORK_TYPE_ALL ||
+ read_int == DP_NETWORK_TYPE_WIFI ||
+ read_int == DP_NETWORK_TYPE_DATA_NETWORK ||
+ read_int == DP_NETWORK_TYPE_ETHERNET ||
+ read_int == DP_NETWORK_TYPE_WIFI_DIRECT)
+ errorcode = dp_request_set_network_type(cmd->id, request, read_int);
+ else
+ errorcode = DP_ERROR_INVALID_PARAMETER;
+ break;
+ case DP_CMD_SET_AUTO_DOWNLOAD:
+ if (dp_ipc_read_custom_type(sock, &read_int, sizeof(int)) < 0) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ errorcode = dp_request_set_auto_download(cmd->id, request, read_int);
+ break;
+ case DP_CMD_SET_NOTIFICATION:
+ if (dp_ipc_read_custom_type(sock, &read_int, sizeof(int)) < 0) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ errorcode = dp_request_set_notification(cmd->id, request, read_int);
+ break;
+ case DP_CMD_SET_URL:
+ if ((read_str = dp_ipc_read_string(sock)) == NULL) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ errorcode = dp_request_set_url(cmd->id, request, read_str);
+ break;
+ case DP_CMD_SET_DESTINATION:
+ if ((read_str = dp_ipc_read_string(sock)) == NULL) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ if (dp_is_smackfs_mounted() == 1 &&
+ __dp_check_valid_directory(request, read_str) != 0){
+ errorcode = DP_ERROR_PERMISSION_DENIED;
+ break;
+ }
+ errorcode = dp_request_set_destination(cmd->id, request, read_str);
+ break;
+ case DP_CMD_SET_FILENAME:
+ if ((read_str = dp_ipc_read_string(sock)) == NULL) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ errorcode = dp_request_set_filename(cmd->id, request, read_str);
+ break;
+ case DP_CMD_SET_NOTIFICATION_BUNDLE:
+ bundle_length = dp_ipc_read_bundle(sock, &noti_bundle_type, &b_raw);
+ if (bundle_length == 0) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ } else if (bundle_length == -1) {
+ errorcode = DP_ERROR_INVALID_PARAMETER;
+ break;
+ }
+ errorcode = dp_request_set_bundle(cmd->id, request,
+ noti_bundle_type, b_raw, bundle_length);
+ break;
+ case DP_CMD_SET_NOTIFICATION_TITLE:
+ if ((read_str = dp_ipc_read_string(sock)) == NULL) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ errorcode = dp_request_set_title(cmd->id, request, read_str);
+ break;
+ case DP_CMD_SET_NOTIFICATION_DESCRIPTION:
+ if ((read_str = dp_ipc_read_string(sock)) == NULL) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ errorcode = dp_request_set_description(cmd->id, request, read_str);
+ break;
+ case DP_CMD_SET_NOTIFICATION_TYPE:
+ if ((dp_ipc_read_custom_type(sock, &read_int, sizeof(int)) < 0)) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ if (read_int == DP_NOTIFICATION_TYPE_NONE ||
+ read_int == DP_NOTIFICATION_TYPE_COMPLETE_ONLY ||
+ read_int == DP_NOTIFICATION_TYPE_ALL)
+ errorcode = dp_request_set_noti_type(cmd->id, request, read_int);
+ else
+ errorcode = DP_ERROR_INVALID_PARAMETER;
+ break;
+ default:
+ is_checked = 0;
+ break;
+ }
+ if (is_checked == 1) {
+ free(read_str);
+ bundle_free_encoded_rawdata(&b_raw);
+ if (errorcode != DP_ERROR_NONE) {
+ TRACE_ERROR("[ERROR][%d][%s][%s]", cmd->id,
+ __print_command(cmd->cmd), dp_print_errorcode(errorcode));
+ }
+ if (errorcode == DP_ERROR_IO_ERROR)
+ return errorcode;
+ dp_ipc_send_errorcode(sock, errorcode);
+ return errorcode;
+ }
+
+ // complex read() and write().
+ char *read_str2 = NULL;
+ errorcode = DP_ERROR_NONE;
+ read_str = NULL;
+ is_checked = 1;
+ switch(cmd->cmd) {
+ case DP_CMD_SET_HTTP_HEADER:
+ {
+ if ((read_str = dp_ipc_read_string(sock)) == NULL) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ if ((read_str2 = dp_ipc_read_string(sock)) == NULL) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ int conds_count = 3; // id + field + data
+ db_conds_list_fmt conds_p[conds_count];
+ memset(&conds_p, 0x00,
+ conds_count * sizeof(db_conds_list_fmt));
+ conds_p[0].column = DP_DB_COL_ID;
+ conds_p[0].type = DP_DB_COL_TYPE_INT;
+ conds_p[0].value = &cmd->id;
+ conds_p[1].column = DP_DB_COL_HEADER_FIELD;
+ conds_p[1].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[1].value = read_str;
+ conds_p[2].column = DP_DB_COL_HEADER_DATA;
+ conds_p[2].type = DP_DB_COL_TYPE_TEXT;
+ conds_p[2].value = read_str2;
+ if (dp_db_get_conds_rows_count(DP_DB_TABLE_HTTP_HEADERS,
+ DP_DB_COL_ID, "AND", 2, conds_p) <= 0) { // insert
+ if (dp_db_insert_columns(DP_DB_TABLE_HTTP_HEADERS,
+ conds_count, conds_p) < 0) {
+ if (dp_db_is_full_error() == 0) {
+ TRACE_ERROR("[SQLITE_FULL][%d]", cmd->id);
+ errorcode = DP_ERROR_NO_SPACE;
+ } else {
+ errorcode = DP_ERROR_OUT_OF_MEMORY;
+ }
+ }
+ } else { // update data by field
+ if (dp_db_cond_set_column(cmd->id, DP_DB_TABLE_HTTP_HEADERS,
+ DP_DB_COL_HEADER_DATA, DP_DB_COL_TYPE_TEXT, read_str2,
+ DP_DB_COL_HEADER_FIELD, DP_DB_COL_TYPE_TEXT, read_str) < 0) {
+ if (dp_db_is_full_error() == 0) {
+ TRACE_ERROR("[SQLITE_FULL][%d]", cmd->id);
+ errorcode = DP_ERROR_NO_SPACE;
+ } else {
+ errorcode = DP_ERROR_OUT_OF_MEMORY;
+ }
+ }
+ }
+ dp_ipc_send_errorcode(sock, errorcode);
+ break;
+ }
+ case DP_CMD_DEL_HTTP_HEADER:
+ if ((read_str = dp_ipc_read_string(sock)) == NULL) {
+ errorcode = DP_ERROR_IO_ERROR;
+ break;
+ }
+ if (dp_db_get_cond_rows_count(cmd->id, DP_DB_TABLE_HTTP_HEADERS,
+ DP_DB_COL_HEADER_FIELD, DP_DB_COL_TYPE_TEXT,
+ read_str) <= 0) {
+ errorcode = DP_ERROR_NO_DATA;
+ } else {
+ if (dp_db_cond_remove(cmd->id, DP_DB_TABLE_HTTP_HEADERS,
+ DP_DB_COL_HEADER_FIELD, DP_DB_COL_TYPE_TEXT, read_str) < 0)
+ errorcode = DP_ERROR_OUT_OF_MEMORY;
+ }
+ dp_ipc_send_errorcode(sock, errorcode);
+ break;
+ case DP_CMD_ADD_EXTRA_PARAM:
+ errorcode = __dp_add_extra_param(sock, cmd->id);
+ if (errorcode != DP_ERROR_IO_ERROR)
+ dp_ipc_send_errorcode(sock, errorcode);
+ break;
+ case DP_CMD_REMOVE_EXTRA_PARAM:
+ errorcode = __dp_remove_extra_param(sock, cmd->id);
+ if (errorcode != DP_ERROR_IO_ERROR)
+ dp_ipc_send_errorcode(sock, errorcode);
+ break;
+ default:
+ is_checked = 0;
+ break;
+ }
+ if (is_checked == 1) {
+ if (errorcode != DP_ERROR_NONE) {
+ TRACE_ERROR("[ERROR][%d][%s][%s]", cmd->id,
+ __print_command(cmd->cmd), dp_print_errorcode(errorcode));
+ }
+ free(read_str);
+ free(read_str2);
+ return errorcode;
+ }
+ return DP_ERROR_UNKNOWN;
+}
+
+static dp_error_type __dp_do_action_command(int sock, dp_command* cmd, dp_request *request)
+{
+ unsigned is_checked = 1;
+ int read_int = 0;
+ dp_error_type errorcode = DP_ERROR_NONE;
+
+ read_int = 0;
+ errorcode = DP_ERROR_NONE;
+ is_checked = 1;
+ switch(cmd->cmd) {
+ case DP_CMD_DESTROY:
+ if (request != NULL) {// just update the state
+ if (__is_started(request->state) == 0) {
+ read_int = DP_STATE_CANCELED;
+ if (dp_db_set_column(cmd->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
+ DP_DB_COL_TYPE_INT, &read_int) < 0) {
+ errorcode = DP_ERROR_OUT_OF_MEMORY;
+ } else {
+ if (__dp_call_cancel_agent(request) < 0)
+ TRACE_ERROR("[fail][%d]cancel_agent", cmd->id);
+ request->state = DP_STATE_CANCELED;
+ if (request->auto_notification == 1 &&
+ request->packagename != NULL) {
+ request->noti_priv_id = dp_set_downloadedinfo_notification
+ (request->noti_priv_id, request->id,
+ request->packagename, request->state);
+ } else {
+ int noti_type = dp_db_get_int_column(request->id,
+ DP_DB_TABLE_NOTIFICATION, DP_DB_COL_NOTI_TYPE);
+ if (noti_type > DP_NOTIFICATION_TYPE_NONE &&
+ request->packagename != NULL)
+ request->noti_priv_id = dp_set_downloadedinfo_notification
+ (request->noti_priv_id, request->id,
+ request->packagename, request->state);
+ }
+ }
+ }
+ }
+ break;
+ case DP_CMD_PAUSE:
+ {
+ // to check fastly, divide the case by request value
+ if (request == NULL) {
+ dp_state_type state = dp_db_get_state(cmd->id);
+ // already paused or stopped
+ if (state > DP_STATE_DOWNLOADING) {
+ errorcode = DP_ERROR_INVALID_STATE;
+ } else {
+ // change state to paused.
+ state = DP_STATE_PAUSED;
+ if (dp_db_set_column(cmd->id, DP_DB_TABLE_LOG,
+ DP_DB_COL_STATE, DP_DB_COL_TYPE_INT, &state) < 0)
+ errorcode = DP_ERROR_OUT_OF_MEMORY;
+ }
+ break;
+ }
+
+ if (request->state > DP_STATE_DOWNLOADING) {
+ errorcode = DP_ERROR_INVALID_STATE;
+ break;
+ }
+
+ // before downloading including QUEUED
+ if (__is_downloading(request->state) < 0) {
+ dp_state_type state = DP_STATE_PAUSED;
+ if (dp_db_set_column(cmd->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
+ DP_DB_COL_TYPE_INT, &state) < 0) {
+ errorcode = DP_ERROR_OUT_OF_MEMORY;
+ } else {
+ request->state = state;
+ }
+ break;
+ }
+ // only downloading.
+ dp_state_type state = DP_STATE_PAUSE_REQUESTED;
+ if (dp_db_set_column(cmd->id, DP_DB_TABLE_LOG,
+ DP_DB_COL_STATE, DP_DB_COL_TYPE_INT, &state) < 0) {
+ errorcode = DP_ERROR_OUT_OF_MEMORY;
+ } else {
+ TRACE_INFO("[%s][%d]pause_agent(%d) state:%s",
+ __print_command(cmd->cmd), cmd->id,
+ request->agent_id,
+ dp_print_state(request->state));
+ if (dp_pause_agent_download
+ (request->agent_id) < 0) {
+ TRACE_ERROR("[fail][%d]pause_agent(%d)",
+ cmd->id, request->agent_id);
+ }
+ request->state = state;
+ request->error = DP_ERROR_NONE;
+ request->pause_time = (int)time(NULL);
+ dp_db_update_date(cmd->id, DP_DB_TABLE_LOG,
+ DP_DB_COL_ACCESS_TIME);
+ }
+ break;
+ }
+ case DP_CMD_CANCEL:
+ {
+ // to check fastly, divide the case by request value
+ if (request == NULL) {
+ dp_state_type state = dp_db_get_state(cmd->id);
+ // already paused or stopped
+ if (__is_stopped(state) == 0) {
+ errorcode = DP_ERROR_INVALID_STATE;
+ } else {
+ // change state to canceled.
+ state = DP_STATE_CANCELED;
+ if (dp_db_set_column(cmd->id, DP_DB_TABLE_LOG,
+ DP_DB_COL_STATE, DP_DB_COL_TYPE_INT, &state) < 0)
+ errorcode = DP_ERROR_OUT_OF_MEMORY;
+ }
+ break;
+ }
+
+ if (__is_stopped(request->state) == 0) {
+ TRACE_ERROR("[%s][%d]__is_stopped agentid:%d state:%s",
+ __print_command(cmd->cmd), cmd->id,
+ request->agent_id, dp_print_state(request->state));
+ errorcode = DP_ERROR_INVALID_STATE;
+ } else {
+ // change state to canceled.
+ dp_state_type state = DP_STATE_CANCELED;
+ if (dp_db_set_column(cmd->id, DP_DB_TABLE_LOG, DP_DB_COL_STATE,
+ DP_DB_COL_TYPE_INT, &state) < 0)
+ errorcode = DP_ERROR_OUT_OF_MEMORY;
+ }
+ if (errorcode == DP_ERROR_NONE) {
+ if (__dp_call_cancel_agent(request) < 0)
+ TRACE_ERROR("[fail][%d]cancel_agent", cmd->id);
+ request->state = DP_STATE_CANCELED;
+ }
+ dp_db_update_date(cmd->id, DP_DB_TABLE_LOG, DP_DB_COL_ACCESS_TIME);
+ break;
+ }
+ default:
+ is_checked = 0;
+ break;
+ }
+ if (is_checked == 1) {
+ if (errorcode != DP_ERROR_NONE) {
+ TRACE_ERROR("[ERROR][%d][%s][%s]", cmd->id,
+ __print_command(cmd->cmd), dp_print_errorcode(errorcode));
+ }
+ dp_ipc_send_errorcode(sock, errorcode);
+ return errorcode;
+ }
+ return DP_ERROR_UNKNOWN;
+}
+
+static dp_error_type __do_dp_start_command(int sock, int id, dp_privates *privates,
+ dp_client_group *group, dp_request *request)
+{
+ dp_error_type errorcode = DP_ERROR_NONE;
+
+ // need URL at least
+ char *url = dp_request_get_url(id, &errorcode);
+ free(url);
+ if (errorcode == DP_ERROR_NO_DATA) {
+ errorcode = DP_ERROR_INVALID_URL;
+ dp_ipc_send_errorcode(sock, errorcode);
+ return errorcode;
+ }
+
+ if (request == NULL) { // Support Re-download
+ // Support Re-download
+ int index = __get_empty_request_index(privates->requests);
+ if (index < 0) { // Busy, No Space in slot
+ errorcode = DP_ERROR_QUEUE_FULL;
+ TRACE_SECURE_ERROR("[ERROR][%d][RESTORE][%s]", id,
+ dp_print_errorcode(errorcode));
+ } else {
+ CLIENT_MUTEX_LOCK(&privates->requests[index].mutex);
+ dp_request *tmp_request =
+ dp_request_load_from_log (id, &errorcode);
+ if (tmp_request != NULL) {
+ // restore callback info
+ tmp_request->state_cb = dp_db_get_int_column(id,
+ DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_STATE_EVENT);
+ tmp_request->progress_cb = dp_db_get_int_column(id,
+ DP_DB_TABLE_REQUEST_INFO, DP_DB_COL_PROGRESS_EVENT);
+ tmp_request->auto_notification =
+ dp_db_get_int_column(id, DP_DB_TABLE_REQUEST_INFO,
+ DP_DB_COL_NOTIFICATION_ENABLE);
+ if (group != NULL) // for send event to client
+ tmp_request->group = group;
+ privates->requests[index].request = tmp_request;
+ request = privates->requests[index].request;
+ } else {
+ TRACE_SECURE_ERROR("[ERROR][%d][RESTORE][%s]", id,
+ dp_print_errorcode(errorcode));
+ dp_ipc_send_errorcode(sock, errorcode);
+ CLIENT_MUTEX_UNLOCK(&privates->requests[index].mutex);
+ return errorcode;
+ }
+ CLIENT_MUTEX_UNLOCK(&privates->requests[index].mutex);
+ }
+ }
+
+ // check status
+ if (errorcode == DP_ERROR_NONE &&
+ (__is_started(request->state) == 0 ||
+ request->state == DP_STATE_COMPLETED))
+ errorcode = DP_ERROR_INVALID_STATE;
+
+ if (errorcode == DP_ERROR_NONE) {
+
+ dp_state_type state = DP_STATE_QUEUED;
+ if (dp_db_set_column(id, DP_DB_TABLE_LOG,
+ DP_DB_COL_STATE, DP_DB_COL_TYPE_INT, &state) < 0) {
+ errorcode = DP_ERROR_OUT_OF_MEMORY;
+ } else {
+ if (group != NULL)
+ group->queued_count++;
+ request->start_time = (int)time(NULL);
+ request->pause_time = 0;
+ request->stop_time = 0;
+ request->state = state;
+ request->error = DP_ERROR_NONE;
+ dp_db_update_date(id, DP_DB_TABLE_LOG, DP_DB_COL_ACCESS_TIME);
+ }
+
+ }
+
+ dp_ipc_send_errorcode(sock, errorcode);
+ if (errorcode != DP_ERROR_NONE) {
+ TRACE_SECURE_ERROR("[ERROR][%d][START][%s]", id,
+ dp_print_errorcode(errorcode));
+ }
+ return errorcode;
+}
+
+// in url-download, make 3 connection before send CREATE command.
+// after accepting, fill info to pacakgelist.
+// 3 socket per 1 package ( info/request/progress )
+void *dp_thread_requests_manager(void *arg)
+{
+ fd_set rset, eset, listen_fdset, except_fdset;
+ struct timeval timeout; // for timeout of select
+ long flexible_timeout = DP_CARE_CLIENT_MAX_INTERVAL;
+ int listenfd, clientfd, maxfd;
+ socklen_t clientlen;
+ struct sockaddr_un clientaddr;
+ dp_credential credential;
+ unsigned i, is_timeout;
+ int prev_timeout = 0;
+ dp_error_type errorcode = DP_ERROR_NONE;
+
+ dp_privates *privates = (dp_privates*)arg;
+ if (privates == NULL || privates->groups == NULL) {
+ TRACE_ERROR("[CRITICAL] Invalid Address");
+ dp_terminate(SIGTERM);
+ pthread_exit(NULL);
+ return 0;
+ }
+
+ listenfd = privates->listen_fd;
+ maxfd = listenfd;
+
+ TRACE_DEBUG("Ready to listen [%d][%s]", listenfd, DP_IPC);
+
+ FD_ZERO(&listen_fdset);
+ FD_ZERO(&except_fdset);
+ FD_SET(listenfd, &listen_fdset);
+ FD_SET(listenfd, &except_fdset);
+
+ while (privates != NULL && privates->listen_fd >= 0) {
+
+ // select with timeout
+ // initialize timeout structure for calling timeout exactly
+ memset(&timeout, 0x00, sizeof(struct timeval));
+ timeout.tv_sec = flexible_timeout;
+ clientfd = -1;
+ credential.pid = -1;
+ credential.uid = -1;
+ credential.gid = -1;
+ is_timeout = 1;
+
+ rset = listen_fdset;
+ eset = except_fdset;
+
+ if (select((maxfd + 1), &rset, 0, &eset, &timeout) < 0) {
+ TRACE_STRERROR("[CRITICAL] select");
+ break;
+ }
+
+ if (privates == NULL || privates->listen_fd < 0) {
+ TRACE_DEBUG("Terminate Thread");
+ break;
+ }
+
+ if (FD_ISSET(listenfd, &eset) > 0) {
+ TRACE_ERROR("[CRITICAL] listenfd Exception of socket");
+ break;
+ } else if (FD_ISSET(listenfd, &rset) > 0) {
+ // new client(package) called url_download_create API.
+ // update g_dp_request_max_fd & g_dp_info_max_fd
+ // add to socket to g_dp_request_rset & g_dp_info_rset
+
+ is_timeout = 0;
+
+ // Anyway accept client.
+ clientlen = sizeof(clientaddr);
+ clientfd = accept(listenfd,
+ (struct sockaddr*)&clientaddr,
+ &clientlen);
+ if (clientfd < 0) {
+ TRACE_ERROR("[CRITICAL] accept provider was crashed ?");
+ // provider need the time of refresh.
+ break;
+ }
+
+ dp_command_type connect_cmd = DP_CMD_NONE;
+ if (dp_ipc_read_custom_type(clientfd,
+ &connect_cmd, sizeof(dp_command_type)) < 0) {
+ TRACE_ERROR("[CRITICAL] CAPI not support CONNECT CMD");
+ close(clientfd);
+ continue;
+ }
+ if (connect_cmd <= 0) {
+ TRACE_ERROR("[CRITICAL] peer terminate ?");
+ close(clientfd);
+ continue;
+ }
+
+#ifdef SO_PEERCRED
+ // getting the info of client
+ socklen_t cr_len = sizeof(credential);
+ if (getsockopt(clientfd, SOL_SOCKET, SO_PEERCRED,
+ &credential, &cr_len) == 0) {
+ TRACE_DEBUG
+ ("credential : pid=%d, uid=%d, gid=%d",
+ credential.pid, credential.uid, credential.gid);
+ }
+#else // In case of not supported SO_PEERCRED
+ int client_pid = 0;
+ if (dp_ipc_read_custom_type(clientfd,
+ &client_pid, sizeof(int)) < 0) {
+ TRACE_ERROR("[CRITICAL] not support SO_PEERCRED");
+ close(clientfd);
+ continue;
+ }
+ if (client_pid <= 0) {
+ TRACE_ERROR("[CRITICAL] not support SO_PEERCRED");
+ close(clientfd);
+ continue;
+ }
+ credential.pid = client_pid;
+ if (dp_ipc_read_custom_type(clientfd,
+ &credential.uid, sizeof(int)) < 0) {
+ TRACE_ERROR("[CRITICAL] not support SO_PEERCRED");
+ close(clientfd);
+ continue;
+ }
+ if (dp_ipc_read_custom_type(clientfd,
+ &credential.gid, sizeof(int)) < 0) {
+ TRACE_ERROR("[CRITICAL] not support SO_PEERCRED");
+ close(clientfd);
+ continue;
+ }
+#endif
+
+ switch(connect_cmd) {
+ case DP_CMD_SET_COMMAND_SOCKET:
+ if (__dp_set_group_new(clientfd, privates->groups,
+ credential, &listen_fdset) == 0) {
+ FD_SET(clientfd, &listen_fdset);
+ if (clientfd > maxfd)
+ maxfd = clientfd;
+ } else {
+ close(clientfd);
+ }
+ break;
+ case DP_CMD_SET_EVENT_SOCKET:
+ if (__dp_set_group_event_sock(clientfd,
+ privates->groups, credential) < 0)
+ close(clientfd);
+ break;
+ default:
+ TRACE_ERROR("[CRITICAL] Bad access,ignore this client");
+ close(clientfd);
+ break;
+ }
+ } // New Connection
+
+ // listen cmd_socket of all group
+ for (i = 0; i < DP_MAX_GROUP; i++) {
+ dp_client_group *group = privates->groups[i].group;
+ if (group == NULL || group->cmd_socket < 0)
+ continue;
+ const int sock = group->cmd_socket;
+ int time_of_job = (int)time(NULL);
+ if (FD_ISSET(sock, &rset) > 0) {
+ int index = -1;
+ dp_command command;
+
+ is_timeout = 0;
+ command.cmd = DP_CMD_NONE;
+ command.id = -1;
+
+ if (dp_ipc_read_custom_type(sock, &command,
+ sizeof(dp_command)) < 0) {
+ TRACE_STRERROR("failed to read cmd");
+ //Resource temporarily unavailable
+ continue;
+ }
+
+ if (command.cmd == 0 || command.cmd >= DP_CMD_LAST_SECT) { // Client meet some Error.
+ TRACE_SECURE_INFO("[Closed Peer] pkg:%s sock:%d slot:%d",
+ group->pkgname, sock, i);
+ // check all request included to this group
+ FD_CLR(sock, &listen_fdset);
+ __clear_group(privates, group);
+ privates->groups[i].group = NULL;
+ continue;
+ }
+
+ // Echo .client can check whether provider is busy
+ if (command.cmd == DP_CMD_ECHO) {
+ // provider can clear read buffer here
+ TRACE_DEBUG("[ECHO] sock:%d", sock);
+ if (dp_ipc_send_errorcode(sock,
+ DP_ERROR_NONE) < 0) {
+ // disconnect this group, bad client
+ TRACE_ERROR("[ECHO] IO ERROR CLEAN sock:%d", sock);
+ FD_CLR(sock, &listen_fdset);
+ __clear_group(privates, group);
+ privates->groups[i].group = NULL;
+ }
+ continue;
+ }
+
+ if (command.cmd == DP_CMD_CREATE) {
+ TRACE_SECURE_INFO("[CREATE] id:%d sock:%d pid:%d gindex:%d pkg:%s",
+ command.id, sock,
+ group->credential.pid, i, group->pkgname);
+ // search empty slot in privates->requests
+ index =
+ __get_empty_request_index(privates->requests);
+ if (index < 0) {
+ TRACE_ERROR("[CHECK] [DP_ERROR_QUEUE_FULL]");
+ // Busy, No Space in slot
+ dp_ipc_send_errorcode(sock, DP_ERROR_QUEUE_FULL);
+ } else {
+ errorcode = DP_ERROR_NONE;
+ CLIENT_MUTEX_LOCK(&privates->requests[index].mutex);
+ errorcode = dp_request_create(command.id, group,
+ &privates->requests[index].request);
+ dp_ipc_send_errorcode(sock, errorcode);
+ if (errorcode == DP_ERROR_NONE) {
+ dp_ipc_send_custom_type(sock,
+ &privates->requests[index].request->id,
+ sizeof(int));
+ TRACE_DEBUG("[CREATE] GOOD id:%d slot:%d time:%d",
+ privates->requests[index].request->id,
+ index, ((int)time(NULL) - time_of_job));
+ } else {
+ TRACE_ERROR("[ERROR][%s]",
+ dp_print_errorcode(errorcode));
+ }
+ CLIENT_MUTEX_UNLOCK(&privates->requests[index].mutex);
+ }
+ continue;
+ }
+
+ // below commands must need ID
+ // check exception before searching slots.
+ if (command.id < 0) {
+ TRACE_ERROR("[CHECK PROTOCOL] ID should not be -1");
+ dp_ipc_send_errorcode(sock,
+ DP_ERROR_INVALID_PARAMETER);
+ // disconnect this group, bad client
+ FD_CLR(sock, &listen_fdset);
+ __clear_group(privates, group);
+ privates->groups[i].group = NULL;
+ continue;
+ }
+
+ // search id in requests slot
+ index = __get_same_request_index(privates->requests,
+ command.id);
+
+ dp_request_slots *request_slot = NULL;
+ unsigned is_loaded = 0;
+ errorcode = DP_ERROR_NONE;
+
+ if (index >= 0) {
+ CLIENT_MUTEX_LOCK(&privates->requests[index].mutex);
+ if (privates->requests[index].request != NULL)
+ is_loaded = 1;
+ else
+ CLIENT_MUTEX_UNLOCK(&privates->requests[index].mutex);
+ }
+
+ errorcode = DP_ERROR_UNKNOWN; // check matched command
+
+ // divide on memory or from DB
+ if (is_loaded == 1 && index >= 0) { // already locked
+
+ TRACE_SECURE_INFO("[%s] id:%d sock:%d pid:%d gindex:%d slot:%d pkg:%s",
+ __print_command(command.cmd), command.id, sock,
+ group->credential.pid, i, index, group->pkgname);
+
+ request_slot = &privates->requests[index];
+
+ // auth by pkgname
+ if (__cmp_string(group->pkgname, request_slot->request->packagename) < 0) {
+ TRACE_SECURE_ERROR("[ERROR][%d] Auth [%s]/[%s]",
+ command.id, group->pkgname, request_slot->request->packagename);
+ TRACE_ERROR("[ERROR][%d][INVALID_PARAMETER]", command.id);
+ dp_ipc_send_errorcode(sock, DP_ERROR_INVALID_PARAMETER);
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+ continue;
+ }
+
+ // if no group, update group.
+ if (request_slot->request->group == NULL)
+ request_slot->request->group = group;
+
+ if (command.cmd == DP_CMD_START)
+ errorcode = __do_dp_start_command(sock, command.id, privates, group, request_slot->request);
+ else if (command.cmd > DP_CMD_SET_SECT && command.cmd < DP_CMD_LAST_SECT)
+ errorcode = __dp_do_set_command(sock, &command, request_slot->request);
+ else if (command.cmd > DP_CMD_GET_SECT && command.cmd < DP_CMD_SET_SECT)
+ errorcode = __dp_do_get_command(sock, &command, request_slot->request);
+ else if (command.cmd > DP_CMD_ACTION_SECT && command.cmd < DP_CMD_GET_SECT)
+ errorcode = __dp_do_action_command(sock, &command, request_slot->request);
+
+ CLIENT_MUTEX_UNLOCK(&request_slot->mutex);
+
+ if (command.cmd == DP_CMD_START && errorcode == DP_ERROR_NONE) {
+ //send signal to queue thread
+ dp_thread_queue_manager_wake_up();
+ }
+ if (command.cmd == DP_CMD_FREE) {// enter after unlock
+ dp_request_slot_free(request_slot);
+ errorcode = DP_ERROR_NONE;
+ }
+
+ } else { // not found on the slots
+
+ TRACE_SECURE_INFO("[%s] id:%d sock:%d pid:%d gindex:%d slot:no pkg:%s",
+ __print_command(command.cmd), command.id, sock,
+ group->credential.pid, i, group->pkgname);
+
+ int check_id = dp_db_get_int_column(command.id,
+ DP_DB_TABLE_LOG, DP_DB_COL_ID);
+ if (check_id < 0 || check_id != command.id) {
+ errorcode = DP_ERROR_ID_NOT_FOUND;
+ TRACE_ERROR("[ERROR][%d][ID_NOT_FOUND]", command.id);
+ dp_ipc_send_errorcode(sock, DP_ERROR_ID_NOT_FOUND);
+ continue;
+ }
+ // auth by pkgname
+ char *auth_pkgname = dp_db_get_text_column(command.id,
+ DP_DB_TABLE_LOG, DP_DB_COL_PACKAGENAME);
+ if (auth_pkgname == NULL) {
+ TRACE_ERROR("[ERROR][%d][ID_NOT_FOUND]", command.id);
+ dp_ipc_send_errorcode(sock, DP_ERROR_ID_NOT_FOUND);
+ continue;
+ }
+ // auth by pkgname
+ if (__cmp_string(group->pkgname, auth_pkgname) < 0) {
+ TRACE_SECURE_ERROR("[ERROR][%d] Auth [%s]/[%s]",
+ command.id, group->pkgname, auth_pkgname);
+ TRACE_ERROR("[ERROR][%d][INVALID_PARAMETER]", command.id);
+ dp_ipc_send_errorcode(sock, DP_ERROR_INVALID_PARAMETER);
+ free(auth_pkgname);
+ continue;
+ }
+ free(auth_pkgname);
+
+ if (command.cmd == DP_CMD_START)
+ errorcode = __do_dp_start_command(sock, command.id, privates, group, NULL);
+ else if (command.cmd == DP_CMD_FREE)
+ errorcode = DP_ERROR_NONE;
+ else if (command.cmd > DP_CMD_SET_SECT && command.cmd < DP_CMD_LAST_SECT)
+ errorcode = __dp_do_set_command(sock, &command, NULL);
+ else if (command.cmd > DP_CMD_GET_SECT && command.cmd < DP_CMD_SET_SECT)
+ errorcode = __dp_do_get_command(sock, &command, NULL);
+ else if (command.cmd > DP_CMD_ACTION_SECT && command.cmd < DP_CMD_GET_SECT)
+ errorcode = __dp_do_action_command(sock, &command, NULL);
+
+ if (command.cmd == DP_CMD_START && errorcode == DP_ERROR_NONE) {
+ //send signal to queue thread
+ dp_thread_queue_manager_wake_up();
+ }
+ }
+
+ if (errorcode == DP_ERROR_IO_ERROR) {
+ TRACE_ERROR("[IO_ERROR][%d] slot:%d pid:%d",
+ command.id, i,
+ privates->groups[i].group->credential.pid);
+ FD_CLR(sock, &listen_fdset);
+ __clear_group(privates, group);
+ privates->groups[i].group = NULL;
+ continue;
+ }
+ if (errorcode == DP_ERROR_UNKNOWN) { // UnKnown Command
+ TRACE_INFO("[UNKNOWN][%d] slot:%d pid:%d",
+ command.id, i,
+ privates->groups[i].group->credential.pid);
+ dp_ipc_send_errorcode(sock, DP_ERROR_IO_ERROR);
+ // disconnect this group, bad client
+ FD_CLR(sock, &listen_fdset);
+ __clear_group(privates, group);
+ privates->groups[i].group = NULL;
+ }
+
+ } // FD_ISSET
+ } // DP_MAX_GROUP
+
+ // timeout
+ if (is_timeout == 1) {
+ int now_timeout = (int)time(NULL);
+ TRACE_DEBUG("[TIMEOUT] prev %ld, now %ld, setted %ld sec",
+ prev_timeout, now_timeout, flexible_timeout);
+ if (prev_timeout == 0) {
+ prev_timeout = now_timeout;
+ } else if (now_timeout < prev_timeout ||
+ (now_timeout - prev_timeout) > flexible_timeout) {
+ TRACE_ERROR("[WARN] check system date prev[%ld]now[%ld]",
+ prev_timeout, now_timeout);
+ } else {
+ if ((now_timeout - prev_timeout) <
+ DP_CARE_CLIENT_MIN_INTERVAL) {
+ // this is error.
+ // terminate Process
+ TRACE_STRERROR
+ ("[CRITICAL] Sock exception prev[%ld]now[%ld][%ld]",
+ prev_timeout, now_timeout, flexible_timeout);
+ break;
+ }
+ }
+
+ // get 48hour old request from log DB
+ // clear old request
+ dp_db_limit_rows(DP_LOG_DB_LIMIT_ROWS);
+ int old_request_count = dp_db_get_count_by_limit_time();
+ if (old_request_count > 0) {
+ if (old_request_count > DP_LOG_DB_CLEAR_LIMIT_ONE_TIME)
+ old_request_count = DP_LOG_DB_CLEAR_LIMIT_ONE_TIME;
+
+ TRACE_DEBUG
+ ("[CLEAR] [%d] old reqeusts", old_request_count);
+
+ dp_request_slots *old_requests =
+ dp_request_slots_new(old_request_count);
+ if (old_requests != NULL) {
+ int list_count = dp_db_get_list_by_limit_time
+ (old_requests, old_request_count);
+ for (i = 0; i < list_count; i++) {
+ // search on slots by ID.
+ int index = __get_same_request_index
+ (privates->requests,
+ old_requests[i].request->id);
+ if (index >= 0) {
+ CLIENT_MUTEX_LOCK(&privates->requests[index].mutex);
+ dp_request *request =
+ privates->requests[index].request;
+ // if downloading..remain it.
+ if (request == NULL || __is_downloading(request->state) == 0) {
+ CLIENT_MUTEX_UNLOCK(&privates->requests[index].mutex);
+ continue;
+ }
+ CLIENT_MUTEX_UNLOCK(&privates->requests[index].mutex);
+ TRACE_DEBUG("[CLEAR][%d] 48 hour state:%s",
+ request->id,
+ dp_print_state(request->state));
+ // unload from slots ( memory )
+ dp_request_slot_free(&privates->requests[index]);
+ }
+ // remove tmp file regardless
+ __dp_remove_tmpfile
+ (old_requests[i].request->id,
+ old_requests[i].request);
+ // remove from DB
+ dp_db_remove_all(old_requests[i].request->id);
+ }
+ dp_request_slots_free(old_requests, old_request_count);
+ }
+ }
+
+ // clean slots
+ int ready_requests = 0;
+ for (i = 0; i < DP_MAX_REQUEST; i++) {
+ CLIENT_MUTEX_LOCK(&privates->requests[i].mutex);
+ if (privates->requests[i].request == NULL) {
+ CLIENT_MUTEX_UNLOCK(&privates->requests[i].mutex);
+ continue;
+ }
+ dp_request *request = privates->requests[i].request;
+
+ // If downloading is too slow ? how to deal this request?
+ // can limit too slot download using starttime.(48 hours)
+ if (__is_downloading(request->state) == 0) {
+ CLIENT_MUTEX_UNLOCK(&privates->requests[i].mutex);
+ continue;
+ }
+
+ // paused & agent_id not exist.... unload from memory.
+ if (request->state == DP_STATE_PAUSED &&
+ dp_is_alive_download(request->agent_id) == 0) {
+ TRACE_DEBUG("[FREE][%d] dead agent-id(%d) state:%s",
+ request->id, request->agent_id,
+ dp_print_state(request->state));
+ CLIENT_MUTEX_UNLOCK(&privates->requests[i].mutex);
+ dp_request_slot_free(&privates->requests[i]);
+ continue;
+ }
+
+ // client should call START command in 60 sec
+ // unload from memory
+ if (request->start_time <= 0 &&
+ (now_timeout - request->create_time) >
+ DP_CARE_CLIENT_MAX_INTERVAL) {
+ int download_id = request->id;
+ dp_state_type state = DP_STATE_FAILED;
+ errorcode = DP_ERROR_RESPONSE_TIMEOUT;
+ TRACE_DEBUG
+ ("[FREE][%d] start in %d sec state:%s last:%ld",
+ download_id, DP_CARE_CLIENT_MAX_INTERVAL,
+ dp_print_state(request->state),
+ request->start_time);
+ if (request->group != NULL &&
+ request->state_cb == 1 &&
+ request->group->event_socket >= 0)
+ dp_ipc_send_event(request->group->event_socket,
+ download_id, state, errorcode, 0);
+ CLIENT_MUTEX_UNLOCK(&privates->requests[i].mutex);
+ dp_request_slot_free(&privates->requests[i]);
+ // no problem although updating is failed.
+ if (dp_db_request_update_status(download_id, state, errorcode) < 0) {
+ TRACE_ERROR("[fail][%d][sql] set state:%s error:%s",
+ download_id, dp_print_state(state), dp_print_errorcode(errorcode));
+ }
+ continue;
+ }
+
+ // stopped by ipchanged. decide auto resume
+ if (request->stop_time <= 0 &&
+ request->state == DP_STATE_FAILED &&
+ request->error == DP_ERROR_CONNECTION_FAILED) {
+ if (dp_get_network_connection_instant_status() !=
+ DP_NETWORK_TYPE_OFF &&
+ request->ip_changed == 1) {
+ TRACE_DEBUG("[RESUME][%d] will be queued",
+ request->id);
+ request->state = DP_STATE_QUEUED;
+ request->error = DP_ERROR_NONE;
+ ready_requests++;
+ } else {
+ dp_request_state_response(request);
+ }
+ }
+
+ // client should call DESTROY command in MAX_INTERVAL sec after finished
+ if (request->stop_time > 0 &&
+ (now_timeout - request->stop_time) >
+ DP_CARE_CLIENT_MAX_INTERVAL) {
+ // check state again. stop_time means it's stopped
+ if (__is_stopped(request->state) == 0) {
+ TRACE_DEBUG
+ ("[FREE][%d] by timeout state:%s stop:%ld",
+ request->id,
+ dp_print_state(request->state),
+ request->stop_time);
+ CLIENT_MUTEX_UNLOCK(&privates->requests[i].mutex);
+ dp_request_slot_free(&privates->requests[i]);
+ continue;
+ }
+ }
+
+ // check after clear
+ if (request->state == DP_STATE_QUEUED)
+ ready_requests++;
+
+ CLIENT_MUTEX_UNLOCK(&privates->requests[i].mutex);
+ }
+
+ if (ready_requests > 0) {
+ //send signal to queue thread will check queue.
+ dp_thread_queue_manager_wake_up();
+ } else {
+ // if no request & timeout is bigger than 60 sec
+ // terminate by self.
+ if ((now_timeout - prev_timeout) >= flexible_timeout &&
+ dp_get_request_count(privates->requests) <= 0) {
+ TRACE_DEBUG("No Request. Terminate Daemon");
+ break;
+ }
+ }
+ prev_timeout = now_timeout;
+ } else {
+ prev_timeout = 0;
+ }
+ }
+ TRACE_DEBUG("terminate main thread ...");
+ dp_terminate(SIGTERM);
+ pthread_exit(NULL);
+ return 0;
+}
diff --git a/provider/include/download-provider-config.h b/provider/include/download-provider-config.h
new file mode 100755
index 0000000..96862ec
--- /dev/null
+++ b/provider/include/download-provider-config.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER2_CONFIG_H
+#define DOWNLOAD_PROVIDER2_CONFIG_H
+
+#include <download-provider.h>
+#include <download-provider-slots.h>
+
+#include <net_connection.h>
+
+#define DP_LOCK_PID "/tmp/download-provider.lock"
+
+#define DP_CARE_CLIENT_MIN_INTERVAL 5
+#define DP_CARE_CLIENT_MAX_INTERVAL 120
+
+// check this value should be lower than DP_MAX_REQUEST
+#define DP_MAX_DOWNLOAD_AT_ONCE 50
+
+#define DP_LOG_DB_LIMIT_ROWS 1000
+#define DP_LOG_DB_CLEAR_LIMIT_ONE_TIME 100
+
+// Share the structure for all threads
+typedef struct {
+ int listen_fd;
+ int is_connected_wifi_direct;
+ connection_h connection;
+ dp_network_type network_status;
+ dp_group_slots *groups;
+ dp_request_slots *requests;
+} dp_privates;
+
+#endif
diff --git a/provider/include/download-provider-da-interface.h b/provider/include/download-provider-da-interface.h
new file mode 100755
index 0000000..ab6e716
--- /dev/null
+++ b/provider/include/download-provider-da-interface.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER2_DA_INTERFACE_H
+#define DOWNLOAD_PROVIDER2_DA_INTERFACE_H
+
+int dp_is_file_exist(const char *file_path);
+int dp_init_agent();
+void dp_deinit_agent();
+dp_error_type dp_start_agent_download(dp_request_slots *request);
+dp_error_type dp_resume_agent_download(int req_id);
+dp_error_type dp_pause_agent_download(int req_id);
+dp_error_type dp_cancel_agent_download(int req_id);
+int dp_is_alive_download(int req_id);
+
+#endif
diff --git a/provider/include/download-provider-db.h b/provider/include/download-provider-db.h
new file mode 100755
index 0000000..24a7d27
--- /dev/null
+++ b/provider/include/download-provider-db.h
@@ -0,0 +1,243 @@
+/*
+ * 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER2_DB_H
+#define DOWNLOAD_PROVIDER2_DB_H
+
+#include "download-provider-config.h"
+#include "download-provider-slots.h"
+
+/*
+ * Memory ( sync with logging ) : id, state, errorcode, startcount, packagename
+ * DB TABLES
+ * logging : id, state, errorcode, startcount, createtime, accesstime, packagename
+ * requestinfo : id, auto_download, network_type, filename, destination, url
+ * downloadinfo : id, http_status, content_size, mimetype, contentname, saved_path, tmp_saved_path, etag
+ * httpheaders : id, header_field, header_data
+ * notification : id, noti_enable, extra_key, extra_data
+ */
+/*
+CREATE TABLE IF NOT EXISTS groups
+(
+ id INTEGER UNIQUE PRIMARY KEY,
+ uid INTEGER DEFAULT 0,
+ gid INTEGER DEFAULT 0,
+ extra_int INTEGER DEFAULT 0,
+ packagename TEXT DEFAULT NULL,
+ smack_label TEXT DEFAULT NULL,
+ extra TEXT DEFAULT NULL,
+ date_first_connected DATE,
+ date_last_connected DATE
+);
+
+CREATE TABLE logging
+(
+ id INTEGER UNIQUE PRIMARY KEY,
+ state INTEGER DEFAULT 0,
+ errorcode INTEGER DEFAULT 0,
+ startcount INTEGER DEFAULT 0,
+ packagename TEXT DEFAULT NULL,
+ createtime DATE,
+ accesstime DATE
+);
+
+CREATE TABLE requestinfo
+(
+ id INTEGER UNIQUE PRIMARY KEY,
+ auto_download BOOLEAN DEFAULT 0,
+ state_event BOOLEAN DEFAULT 0,
+ progress_event BOOLEAN DEFAULT 0,
+ network_type TINYINT DEFAULT 0,
+ filename TEXT DEFAULT NULL,
+ destination TEXT DEFAULT NULL,
+ url TEXT DEFAULT NULL,
+ FOREIGN KEY(id) REFERENCES logging(id) ON DELETE CASCADE
+);
+
+CREATE TABLE downloadinfo
+(
+ id INTEGER UNIQUE PRIMARY KEY,
+ http_status INTEGER DEFAULT 0,
+ content_size UNSIGNED BIG INT DEFAULT 0,
+ mimetype VARCHAR(64) DEFAULT NULL,
+ content_name TEXT DEFAULT NULL,
+ saved_path TEXT DEFAULT NULL,
+ tmp_saved_path TEXT DEFAULT NULL,
+ etag TEXT DEFAULT NULL,
+ FOREIGN KEY(id) REFERENCES logging(id) ON DELETE CASCADE
+);
+
+CREATE TABLE httpheaders
+(
+ id INTEGER NOT NULL,
+ header_field TEXT DEFAULT NULL,
+ header_data TEXT DEFAULT NULL,
+ FOREIGN KEY(id) REFERENCES logging(id) ON DELETE CASCADE
+);
+
+CREATE TABLE notification
+(
+ id INTEGER UNIQUE PRIMARY KEY,
+ noti_enable BOOLEAN DEFAULT 0,
+ extra_key TEXT DEFAULT NULL,
+ extra_data TEXT DEFAULT NULL,
+ FOREIGN KEY(id) REFERENCES logging(id) ON DELETE CASCADE
+);
+
+CREATE UNIQUE INDEX requests_index ON logging (id, state, errorcode, packagename, createtime, accesstime);
+*/
+
+#define DP_DB_TABLE_GROUPS "groups"
+#define DP_DB_TABLE_LOG "logging"
+#define DP_DB_TABLE_REQUEST_INFO "requestinfo"
+#define DP_DB_TABLE_DOWNLOAD_INFO "downloadinfo"
+#define DP_DB_TABLE_HTTP_HEADERS "httpheaders"
+#define DP_DB_TABLE_NOTIFICATION "notification"
+
+#define DP_DB_COL_ID "id"
+#define DP_DB_COL_STATE "state"
+#define DP_DB_COL_ERRORCODE "errorcode"
+#define DP_DB_COL_NETWORK_TYPE "network_type"
+#define DP_DB_COL_HTTP_STATUS "http_status"
+#define DP_DB_COL_AUTO_DOWNLOAD "auto_download"
+#define DP_DB_COL_STATE_EVENT "state_event"
+#define DP_DB_COL_PROGRESS_EVENT "progress_event"
+#define DP_DB_COL_CONTENT_SIZE "content_size"
+#define DP_DB_COL_CREATE_TIME "createtime"
+#define DP_DB_COL_ACCESS_TIME "accesstime"
+#define DP_DB_COL_STARTCOUNT "startcount"
+#define DP_DB_COL_PACKAGENAME "packagename"
+#define DP_DB_COL_DESTINATION "destination"
+#define DP_DB_COL_FILENAME "filename"
+#define DP_DB_COL_CONTENT_NAME "content_name"
+#define DP_DB_COL_MIMETYPE "mimetype"
+#define DP_DB_COL_ETAG "etag"
+#define DP_DB_COL_SAVED_PATH "saved_path"
+#define DP_DB_COL_TMP_SAVED_PATH "tmp_saved_path"
+#define DP_DB_COL_URL "url"
+#define DP_DB_COL_HEADER_FIELD "header_field"
+#define DP_DB_COL_HEADER_DATA "header_data"
+#define DP_DB_COL_NOTIFICATION_ENABLE "noti_enable"
+#define DP_DB_COL_EXTRA_KEY "extra_key"
+#define DP_DB_COL_DISTINCT_EXTRA_KEY "DISTINCT extra_key"
+#define DP_DB_COL_EXTRA_VALUE "extra_data"
+#define DP_DB_COL_RAW_BUNDLE_ONGOING "raw_bundle_data_ongoing_state"
+#define DP_DB_COL_RAW_BUNDLE_COMPLETE "raw_bundle_data_complete_state"
+#define DP_DB_COL_RAW_BUNDLE_FAIL "raw_bundle_data_fail_state"
+#define DP_DB_COL_TITLE "title"
+#define DP_DB_COL_DESCRIPTION "description"
+#define DP_DB_COL_NOTI_TYPE "noti_type"
+
+#define DP_DB_GROUPS_COL_UID "uid"
+#define DP_DB_GROUPS_COL_GID "gid"
+#define DP_DB_GROUPS_COL_PKG "packagename"
+#define DP_DB_GROUPS_COL_SMACK_LABEL "smack_label"
+
+
+typedef enum {
+ DP_DB_COL_TYPE_NONE = 0,
+ DP_DB_COL_TYPE_INT = 10,
+ DP_DB_COL_TYPE_INT64 = 20,
+ DP_DB_COL_TYPE_TEXT = 30
+} db_column_data_type;
+
+typedef struct {
+ char *column;
+ db_column_data_type type;
+ int is_like;
+ void *value;
+} db_conds_list_fmt;
+
+int dp_db_open();
+void dp_db_close();
+
+int dp_db_is_full_error();
+
+int dp_db_remove_all(int id);
+int dp_db_remove(int id, char *table);
+int dp_db_insert_column(int id, char *table, char *column,
+ db_column_data_type datatype, void *value);
+int dp_db_insert_blob_column(int id, char *table, char *column,
+ void *value, unsigned length);
+int dp_db_set_column(int id, char *table, char *column,
+ db_column_data_type datatype, void *value);
+int dp_db_set_blob_column(int id, char *table, char *column,
+ void *value, unsigned length);
+int dp_db_replace_column(int id, char *table, char *column,
+ db_column_data_type datatype, void *value);
+int dp_db_replace_blob_column(int id, char *table, char *column,
+ void *value, unsigned length);
+char *dp_db_get_text_column(int id, char *table, char *column);
+void *dp_db_get_blob_column(int id, char *table, char *column, int *length);
+int dp_db_get_int_column(int id, char *table, char *column);
+long long dp_db_get_int64_column(int id, char *table, char *column);
+int dp_db_update_date(int id, char *table, char *column);
+
+// cond : id & cond
+int dp_db_cond_set_column(int id, char *table, char *column,
+ db_column_data_type datatype, void *value,
+ char *condcolumn, db_column_data_type condtype,
+ void *condvalue);
+char *dp_db_cond_get_text_column(int id, char *table, char *column,
+ char *condcolumn, db_column_data_type condtype,
+ void *condvalue);
+int dp_db_cond_remove(int id, char *table,
+ char *condcolumn, db_column_data_type condtype,
+ void *condvalue);
+int dp_db_get_cond_rows_count(int id, char *table,
+ char *condcolumn, db_column_data_type condtype,
+ void *condvalue);
+
+char *dp_db_cond_get_text(char *table, char *column, char *condcolumn,
+ db_column_data_type condtype, void *condvalue);
+int dp_db_cond_get_int(char *table, char *column, char *condcolumn,
+ db_column_data_type condtype, void *condvalue);
+
+// Special API for http headers
+int dp_db_get_http_headers_list(int id, char **headers);
+
+// For auto-download in booting time
+int dp_db_crashed_list(dp_request_slots *requests, int limit);
+
+// For loading to memory when no in memory
+dp_request *dp_db_load_logging_request(int id);
+
+// For limitation by 48 hours & 1000 rows
+int dp_db_limit_rows(int limit);
+int dp_db_get_count_by_limit_time();
+int dp_db_get_list_by_limit_time(dp_request_slots *requests, int limit);
+
+int dp_db_insert_columns(char *table, int column_count,
+ db_conds_list_fmt *columns);
+int dp_db_update_columns(int id, char *table, int column_count,
+ db_conds_list_fmt *columns);
+
+int dp_db_get_conds_rows_count(char *table, char *getcolumn, char *op,
+ int conds_count, db_conds_list_fmt *conds);
+
+int dp_db_get_conds_list(char *table, char *getcolumn,
+ db_column_data_type gettype, void **list,
+ int rowslimit, int rowsoffset,
+ char *ordercolumn, char *ordering,
+ char *op, int conds_count,
+ db_conds_list_fmt *conds);
+
+int dp_db_request_new_logging(const int id, const int state, const char *pkgname);
+int dp_db_request_update_status(const int id, const int state, const int download_error);
+int dp_db_get_state(int id);
+int dp_db_request_new_logging(const int id,
+ const int state, const char *pkgname);
+#endif
diff --git a/provider/include/download-provider-defs.h b/provider/include/download-provider-defs.h
new file mode 100755
index 0000000..4387e49
--- /dev/null
+++ b/provider/include/download-provider-defs.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER_DEFS_H
+#define DOWNLOAD_PROVIDER_DEFS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ DP_STATE_NONE = 0,
+ DP_STATE_READY = DP_STATE_NONE + 5, // created id, set some info.
+ DP_STATE_QUEUED = DP_STATE_NONE + 10, // request to start
+ DP_STATE_CONNECTING = DP_STATE_NONE + 15, // try to connect to url
+ DP_STATE_DOWNLOADING = DP_STATE_NONE + 20, // started
+ DP_STATE_PAUSE_REQUESTED = DP_STATE_NONE + 25,
+ DP_STATE_PAUSED = DP_STATE_NONE + 30, // paused actually
+ DP_STATE_COMPLETED = DP_STATE_NONE + 40,
+ DP_STATE_CANCELED = DP_STATE_NONE + 45, // stopped with error
+ DP_STATE_FAILED = DP_STATE_NONE + 50 // failed with error
+} dp_state_type;
+
+typedef enum {
+ DP_ERROR_NONE = 10,
+ DP_ERROR_INVALID_PARAMETER = DP_ERROR_NONE + 1,
+ DP_ERROR_OUT_OF_MEMORY = DP_ERROR_NONE + 2,
+ DP_ERROR_IO_ERROR = DP_ERROR_NONE + 3,
+ DP_ERROR_NETWORK_UNREACHABLE = DP_ERROR_NONE + 4,
+ DP_ERROR_CONNECTION_TIMED_OUT = DP_ERROR_NONE + 5,
+ DP_ERROR_NO_SPACE = DP_ERROR_NONE + 6,
+ DP_ERROR_FIELD_NOT_FOUND = DP_ERROR_NONE + 7,
+ DP_ERROR_INVALID_STATE = DP_ERROR_NONE + 8,
+ DP_ERROR_CONNECTION_FAILED = DP_ERROR_NONE + 9,
+ DP_ERROR_INVALID_URL = DP_ERROR_NONE + 10,
+ DP_ERROR_INVALID_DESTINATION = DP_ERROR_NONE + 11,
+ DP_ERROR_QUEUE_FULL = DP_ERROR_NONE + 12,
+ DP_ERROR_ALREADY_COMPLETED = DP_ERROR_NONE + 13,
+ DP_ERROR_FILE_ALREADY_EXISTS = DP_ERROR_NONE + 14,
+ DP_ERROR_TOO_MANY_DOWNLOADS = DP_ERROR_NONE + 15,
+ DP_ERROR_NO_DATA = DP_ERROR_NONE + 17,
+ DP_ERROR_UNHANDLED_HTTP_CODE = DP_ERROR_NONE + 18,
+ DP_ERROR_CANNOT_RESUME = DP_ERROR_NONE + 19,
+ DP_ERROR_PERMISSION_DENIED = DP_ERROR_NONE + 20,
+ DP_ERROR_INVALID_NETWORK_TYPE = DP_ERROR_NONE + 21,
+ DP_ERROR_RESPONSE_TIMEOUT = DP_ERROR_NONE + 50,
+ DP_ERROR_REQUEST_TIMEOUT = DP_ERROR_NONE + 55,
+ DP_ERROR_SYSTEM_DOWN = DP_ERROR_NONE + 60,
+ DP_ERROR_CLIENT_DOWN = DP_ERROR_NONE + 65,
+ DP_ERROR_ID_NOT_FOUND = DP_ERROR_NONE + 90,
+ DP_ERROR_IO_EAGAIN = DP_ERROR_NONE + 97,
+ DP_ERROR_IO_EINTR = DP_ERROR_NONE + 98,
+ DP_ERROR_IO_TIMEOUT = DP_ERROR_NONE + 99,
+ DP_ERROR_UNKNOWN = DP_ERROR_NONE + 100
+} dp_error_type;
+
+typedef enum {
+ DP_NETWORK_TYPE_OFF = -1,
+ DP_NETWORK_TYPE_ALL = 0,
+ DP_NETWORK_TYPE_WIFI = 1,
+ DP_NETWORK_TYPE_DATA_NETWORK = 2,
+ DP_NETWORK_TYPE_ETHERNET = 3,
+ DP_NETWORK_TYPE_WIFI_DIRECT = 4
+} dp_network_type;
+
+typedef enum {
+ DP_NOTIFICATION_BUNDLE_TYPE_ONGOING = 0, // Ongoing, Failed
+ DP_NOTIFICATION_BUNDLE_TYPE_COMPLETE, // Completed
+ DP_NOTIFICATION_BUNDLE_TYPE_FAILED // Failed
+} dp_notification_bundle_type;
+
+typedef enum {
+ DP_NOTIFICATION_TYPE_NONE = 0, // Not register Noti.
+ DP_NOTIFICATION_TYPE_COMPLETE_ONLY, // Success, Failed
+ DP_NOTIFICATION_TYPE_ALL // Ongoing, Success, Failed
+} dp_notification_type;
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/provider/include/download-provider-log.h b/provider/include/download-provider-log.h
new file mode 100755
index 0000000..e828905
--- /dev/null
+++ b/provider/include/download-provider-log.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER2_LOG_H
+#define DOWNLOAD_PROVIDER2_LOG_H
+
+#ifdef SUPPORT_LOG_MESSAGE
+#include <errno.h>
+#include <dlog.h>
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "DOWNLOAD_PROVIDER"
+#define TRACE_DEBUG(format, ARG...) LOGD(format, ##ARG)
+#define TRACE_ERROR(format, ARG...) LOGE(format, ##ARG)
+#define TRACE_STRERROR(format, ARG...) LOGE(format" [%s]", ##ARG, strerror(errno))
+#define TRACE_INFO(format, ARG...) LOGI(format, ##ARG)
+
+#ifdef SECURE_LOGD
+#define TRACE_SECURE_DEBUG(format, ARG...) SECURE_LOGD(format, ##ARG)
+#else
+#define TRACE_SECURE_DEBUG(...) do { } while(0)
+#endif
+#ifdef SECURE_LOGI
+#define TRACE_SECURE_INFO(format, ARG...) SECURE_LOGI(format, ##ARG)
+#else
+#define TRACE_SECURE_INFO(...) do { } while(0)
+#endif
+#ifdef SECURE_LOGE
+#define TRACE_SECURE_ERROR(format, ARG...) SECURE_LOGE(format, ##ARG)
+#else
+#define TRACE_SECURE_ERROR(...) do { } while(0)
+#endif
+
+#else
+#define TRACE_DEBUG(...) do { } while(0)
+#define TRACE_ERROR(...) do { } while(0)
+#define TRACE_STRERROR(...) do { } while(0)
+#define TRACE_INFO(...) do { } while(0)
+#define TRACE_SECURE_DEBUG(...) do { } while(0)
+#define TRACE_SECURE_INFO(...) do { } while(0)
+#define TRACE_SECURE_ERROR(...) do { } while(0)
+#endif
+
+#endif
diff --git a/provider/include/download-provider-network.h b/provider/include/download-provider-network.h
new file mode 100755
index 0000000..98a9b43
--- /dev/null
+++ b/provider/include/download-provider-network.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER2_NETWORK_H
+#define DOWNLOAD_PROVIDER2_NETWORK_H
+
+#include <net_connection.h>
+
+#include "download-provider.h"
+
+dp_network_type dp_get_network_connection_status(connection_h connection, connection_type_e type);
+void dp_network_connection_type_changed_cb(connection_type_e type, void *data);
+int dp_network_connection_init(dp_privates *privates);
+void dp_network_connection_destroy(connection_h connection);
+dp_network_type dp_get_network_connection_instant_status();
+
+#ifdef SUPPORT_WIFI_DIRECT
+int dp_network_wifi_direct_is_connected();
+#endif
+
+#endif
diff --git a/provider/include/download-provider-notification.h b/provider/include/download-provider-notification.h
new file mode 100755
index 0000000..5a9f5b9
--- /dev/null
+++ b/provider/include/download-provider-notification.h
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER2_NOTIFICATION_H
+#define DOWNLOAD_PROVIDER2_NOTIFICATION_H
+
+#include "download-provider-config.h"
+
+int dp_set_downloadinginfo_notification(int id, char *packagename);
+int dp_set_downloadedinfo_notification(int priv_id, int id, char *packagename, dp_state_type state);
+void dp_update_downloadinginfo_notification(int priv_id, double received_size, double file_size);
+void dp_clear_downloadinginfo_notification(void);
+
+#endif
diff --git a/provider/include/download-provider-pthread.h b/provider/include/download-provider-pthread.h
new file mode 100755
index 0000000..8c02c59
--- /dev/null
+++ b/provider/include/download-provider-pthread.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER2_PTHREAD_H
+#define DOWNLOAD_PROVIDER2_PTHREAD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+
+// download-provider use default style mutex.
+
+#define CLIENT_MUTEX_LOCK(mutex_add) {\
+ int ret = 0;\
+ ret = pthread_mutex_lock(mutex_add);\
+ if (EINVAL == ret) {\
+ TRACE_STRERROR("ERR:pthread_mutex_lock FAIL with EINVAL.");\
+ } else if (EDEADLK == ret) {\
+ TRACE_STRERROR("ERR:pthread_mutex_lock FAIL with EDEADLK.");\
+ } else if (ret != 0) {\
+ TRACE_STRERROR("ERR:pthread_mutex_lock FAIL with %d.", ret);\
+ } \
+}
+
+#define CLIENT_MUTEX_UNLOCK(mutex_add) {\
+ int ret = 0;\
+ ret = pthread_mutex_unlock(mutex_add);\
+ if (EINVAL == ret) {\
+ TRACE_STRERROR("ERR:pthread_mutex_unlock FAIL with EINVAL.");\
+ } else if (EDEADLK == ret) {\
+ TRACE_STRERROR("ERR:pthread_mutex_unlock FAIL with EDEADLK.");\
+ } else if (ret != 0) {\
+ TRACE_STRERROR("ERR:pthread_mutex_unlock FAIL with %d.", ret);\
+ } \
+}
+
+#define CLIENT_MUTEX_DESTROY(mutex_add) { \
+ int ret = 0; \
+ ret = pthread_mutex_destroy(mutex_add); \
+ if(EINVAL == ret) {\
+ TRACE_STRERROR("ERR:pthread_mutex_destroy FAIL with EINVAL."); \
+ } else if(ENOMEM == ret) {\
+ TRACE_STRERROR("ERR:pthread_mutex_destroy FAIL with ENOMEM."); \
+ } else if(EBUSY == ret) {\
+ TRACE_STRERROR("ERR:pthread_mutex_destroy FAIL with EBUSY."); \
+ if (pthread_mutex_unlock(mutex_add) == 0) \
+ pthread_mutex_destroy(mutex_add); \
+ } else if (ret != 0) {\
+ TRACE_STRERROR("ERR:pthread_mutex_destroy FAIL with %d.", ret); \
+ } \
+}
+
+#define CLIENT_MUTEX_INIT(mutex_add, attr) { \
+ int ret = 0; \
+ unsigned retry = 3; \
+ while (retry > 0) { \
+ ret = pthread_mutex_init(mutex_add, attr); \
+ if (0 == ret) { \
+ break; \
+ } else if(EINVAL == ret) { \
+ TRACE_STRERROR("ERR:pthread_mutex_init FAIL with EINVAL."); \
+ } else if(ENOMEM == ret) { \
+ TRACE_STRERROR("ERR:pthread_mutex_init FAIL with ENOMEM."); \
+ usleep(1000); \
+ } else if(EBUSY == ret) {\
+ TRACE_STRERROR("ERR:pthread_mutex_destroy FAIL with EBUSY."); \
+ if (pthread_mutex_unlock(mutex_add) == 0) \
+ pthread_mutex_destroy(mutex_add); \
+ } else if (ret != 0) { \
+ TRACE_STRERROR("ERR:pthread_mutex_init FAIL with %d.", ret); \
+ } \
+ retry--; \
+ } \
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/provider/include/download-provider-queue.h b/provider/include/download-provider-queue.h
new file mode 100755
index 0000000..71bb62b
--- /dev/null
+++ b/provider/include/download-provider-queue.h
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER2_QUEUE_H
+#define DOWNLOAD_PROVIDER2_QUEUE_H
+
+void dp_thread_queue_manager_wake_up();
+void *dp_thread_queue_manager(void *arg);
+
+#endif
diff --git a/provider/include/download-provider-request.h b/provider/include/download-provider-request.h
new file mode 100755
index 0000000..bc26953
--- /dev/null
+++ b/provider/include/download-provider-request.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER2_REQUEST_H
+#define DOWNLOAD_PROVIDER2_REQUEST_H
+
+#include "download-provider.h"
+#include <bundle.h>
+
+// for Debugging
+char *dp_print_state(dp_state_type state);
+char *dp_print_errorcode(dp_error_type errorcode);
+
+int dp_is_smackfs_mounted(void);
+char *dp_strdup(char *src);
+
+dp_error_type dp_request_create(int id, dp_client_group *group, dp_request** empty_slot);
+dp_error_type dp_request_set_url(int id, dp_request *request, char *url);
+dp_error_type dp_request_set_destination(int id, dp_request *request, char *dest);
+dp_error_type dp_request_set_filename(int id, dp_request *request, char *filename);
+dp_error_type dp_request_set_title(int id, dp_request *request, char *filename);
+dp_error_type dp_request_set_bundle(int id, dp_request *request, int type, bundle_raw *b, unsigned length);
+dp_error_type dp_request_set_description(int id, dp_request *request, char *description);
+dp_error_type dp_request_set_noti_type(int id, dp_request *request, unsigned type);
+dp_error_type dp_request_set_notification(int id, dp_request *request, unsigned enable);
+dp_error_type dp_request_set_auto_download(int id, dp_request *request, unsigned enable);
+dp_error_type dp_request_set_state_event(int id, dp_request *request, unsigned enable);
+dp_error_type dp_request_set_progress_event(int id, dp_request *request, unsigned enable);
+dp_error_type dp_request_set_network_type(int id, dp_request *request, int type);
+char *dp_request_get_url(int id, dp_error_type *errorcode);
+char *dp_request_get_destination(int id, dp_request *request, dp_error_type *errorcode);
+char *dp_request_get_filename(int id, dp_request *request, dp_error_type *errorcode);
+char *dp_request_get_title(int id, dp_request *request, dp_error_type *errorcode);
+bundle_raw *dp_request_get_bundle(int id, dp_request *request, dp_error_type *errorcode, char* column, int* length);
+char *dp_request_get_description(int id, dp_request *request, dp_error_type *errorcode);
+int dp_request_get_noti_type(int id, dp_request *request, dp_error_type *errorcode);
+char *dp_request_get_contentname(int id, dp_request *request, dp_error_type *errorcode);
+char *dp_request_get_etag(int id, dp_request *request, dp_error_type *errorcode);
+char *dp_request_get_savedpath(int id, dp_request *request, dp_error_type *errorcode);
+char *dp_request_get_tmpsavedpath(int id, dp_request *request, dp_error_type *errorcode);
+char *dp_request_get_mimetype(int id, dp_request *request, dp_error_type *errorcode);
+char *dp_request_get_pkg_name(int id, dp_request *request, dp_error_type *errorcode);
+dp_request *dp_request_load_from_log(int id, dp_error_type *errorcode);
+void dp_request_state_response(dp_request *request);
+#endif
diff --git a/provider/include/download-provider-slots.h b/provider/include/download-provider-slots.h
new file mode 100755
index 0000000..53859f8
--- /dev/null
+++ b/provider/include/download-provider-slots.h
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER2_SLOTS_H
+#define DOWNLOAD_PROVIDER2_SLOTS_H
+
+#include "download-provider.h"
+#include "download-provider-pthread.h"
+
+// Backgound Daemon should has the limitation of resource.
+#define DP_MAX_GROUP 15
+#define DP_MAX_REQUEST 64
+
+typedef struct {
+ pid_t pid;
+ uid_t uid;
+ gid_t gid;
+} dp_credential;
+
+typedef struct {
+ // send command * get return value.
+ int cmd_socket;
+ // send event to client
+ int event_socket;
+ unsigned queued_count; // start ++, finish or failed -- ( queue & active )
+ // fill by app-manager
+ char *pkgname;
+ dp_credential credential;
+ char *smack_label;
+} dp_client_group;
+
+typedef struct {
+ int id; // ID created in create request in requests thread.
+ int agent_id;
+ int create_time;
+ int start_time; // setted by START command
+ int pause_time; // setted by PAUSE command
+ int stop_time; // time setted by finished_cb
+ int noti_priv_id;
+ unsigned state_cb; // set : 1 unset : 0
+ unsigned progress_cb; // set : 1 unset : 0
+ unsigned startcount;
+ unsigned auto_notification;
+ unsigned ip_changed;
+ dp_state_type state; // downloading state
+ dp_error_type error;
+ dp_network_type network_type;
+ size_t progress_lasttime;
+ unsigned long long received_size; // progress
+ unsigned long long file_size;
+ char *packagename;
+ dp_client_group *group; // indicate dp_client_group included this request
+} dp_request;
+
+typedef struct {
+ dp_client_group *group;
+} dp_group_slots;
+
+typedef struct {
+ pthread_mutex_t mutex;
+ dp_request *request;
+} dp_request_slots;
+
+
+// functions
+dp_group_slots *dp_client_group_slots_new(int size);
+dp_request_slots *dp_request_slots_new(int size);
+int dp_client_group_free(dp_client_group *group);
+int dp_client_group_slots_free(dp_group_slots *slots, int size);
+dp_request *dp_request_new();
+void dp_request_init(dp_request *request);
+int dp_request_free(dp_request *request);
+int dp_request_slot_free(dp_request_slots *request_slot);
+int dp_request_slots_free(dp_request_slots *slots, int size);
+int dp_get_request_count(dp_request_slots *slots);
+
+#endif
diff --git a/provider/include/download-provider-socket.h b/provider/include/download-provider-socket.h
new file mode 100755
index 0000000..b5a37cb
--- /dev/null
+++ b/provider/include/download-provider-socket.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER2_SOCKET_H
+#define DOWNLOAD_PROVIDER2_SOCKET_H
+
+#include <bundle.h>
+#include "download-provider.h"
+#include "download-provider-slots.h"
+
+int dp_ipc_send_errorcode(int fd, dp_error_type errorcode);
+int dp_ipc_send_event(int fd, int id, dp_state_type state,
+ dp_error_type errorcode, unsigned long long received_size);
+#if 0
+int dp_ipc_send_progressinfo(int fd, int id,
+ unsigned long long received_size, unsigned long long file_size,
+ unsigned int chunk_size);
+int dp_ipc_send_stateinfo(int fd, int id, dp_state_type state,
+ dp_error_type errorcode);
+#endif
+char *dp_ipc_read_string(int fd);
+unsigned dp_ipc_read_bundle(int fd, int *type, bundle_raw **b);
+int dp_ipc_send_string(int fd, const char *str);
+int dp_ipc_send_bundle(int fd, bundle_raw *b, unsigned length);
+int dp_ipc_send_custom_type(int fd, void *value, size_t type_size);
+int dp_ipc_read_custom_type(int fd, void *value, size_t type_size);
+int dp_accept_socket_new();
+int dp_socket_free(int sockfd);
+
+#endif
diff --git a/provider/include/download-provider.h b/provider/include/download-provider.h
new file mode 100755
index 0000000..a1f22f3
--- /dev/null
+++ b/provider/include/download-provider.h
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+#ifndef DOWNLOAD_PROVIDER2_H
+#define DOWNLOAD_PROVIDER2_H
+
+#include "download-provider-defs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DP_IPC "/tmp/download-provider"
+
+#define DP_MAX_STR_LEN_64 64
+#define DP_MAX_STR_LEN 256
+#define DP_MAX_PATH_LEN DP_MAX_STR_LEN
+#define DP_MAX_URL_LEN 2048
+#define DP_DEFAULT_BUFFER_SIZE 1024
+
+typedef enum {
+ DP_CMD_NONE = 0,
+ DP_CMD_ECHO,
+ DP_CMD_CREATE,
+ DP_CMD_START,
+ DP_CMD_SET_COMMAND_SOCKET,
+ DP_CMD_SET_EVENT_SOCKET,
+ DP_CMD_FREE,
+
+ DP_CMD_ACTION_SECT = 100,
+ DP_CMD_PAUSE,
+ DP_CMD_CANCEL,
+ DP_CMD_DESTROY,
+
+ DP_CMD_GET_SECT = 200,
+ DP_CMD_GET_URL,
+ DP_CMD_GET_DESTINATION,
+ DP_CMD_GET_FILENAME,
+ DP_CMD_GET_NOTIFICATION,
+ DP_CMD_GET_STATE_CALLBACK,
+ DP_CMD_GET_PROGRESS_CALLBACK,
+ DP_CMD_GET_HTTP_HEADERS,
+ DP_CMD_GET_AUTO_DOWNLOAD,
+ DP_CMD_GET_NETWORK_TYPE,
+ DP_CMD_GET_SAVED_PATH,
+ DP_CMD_GET_TEMP_SAVED_PATH,
+ DP_CMD_GET_MIME_TYPE,
+ DP_CMD_GET_HTTP_HEADER,
+ DP_CMD_GET_HTTP_HEADER_LIST,
+ DP_CMD_GET_EXTRA_PARAM,
+ DP_CMD_GET_RECEIVED_SIZE,
+ DP_CMD_GET_TOTAL_FILE_SIZE,
+ DP_CMD_GET_CONTENT_NAME,
+ DP_CMD_GET_HTTP_STATUS,
+ DP_CMD_GET_ETAG,
+ DP_CMD_GET_STATE,
+ DP_CMD_GET_ERROR,
+ DP_CMD_GET_NOTIFICATION_BUNDLE,
+ DP_CMD_GET_NOTIFICATION_TITLE,
+ DP_CMD_GET_NOTIFICATION_DESCRIPTION,
+ DP_CMD_GET_NOTIFICATION_TYPE,
+
+ DP_CMD_SET_SECT = 300,
+ DP_CMD_SET_URL,
+ DP_CMD_SET_DESTINATION,
+ DP_CMD_SET_FILENAME,
+ DP_CMD_SET_NOTIFICATION,
+ DP_CMD_SET_STATE_CALLBACK,
+ DP_CMD_SET_PROGRESS_CALLBACK,
+ DP_CMD_SET_AUTO_DOWNLOAD,
+ DP_CMD_SET_NETWORK_TYPE,
+ DP_CMD_SET_HTTP_HEADER,
+ DP_CMD_SET_EXTRA_PARAM, // prevent build error
+ DP_CMD_DEL_HTTP_HEADER,
+ DP_CMD_ADD_EXTRA_PARAM,
+ DP_CMD_REMOVE_EXTRA_PARAM,
+ DP_CMD_SET_NOTIFICATION_BUNDLE,
+ DP_CMD_SET_NOTIFICATION_TITLE,
+ DP_CMD_SET_NOTIFICATION_DESCRIPTION,
+ DP_CMD_SET_NOTIFICATION_TYPE,
+
+ DP_CMD_LAST_SECT = 400
+} dp_command_type;
+
+typedef struct {
+ unsigned int length;
+ char *str;
+} dp_string;
+
+typedef struct {
+ int id;
+ dp_state_type state;
+ dp_error_type err;
+ unsigned long long received_size;
+} dp_event_info;
+
+typedef struct {
+ dp_command_type cmd;
+ int id;
+} dp_command;
+
+ // Usage IPC : send(dp_command);send(dp_string);
+
+#ifdef __cplusplus
+}
+#endif
+#endif