From: Kyungwook Tak Date: Thu, 19 Nov 2015 07:48:05 +0000 (+0900) Subject: Revert "Remove TPCS and TWPServer features" X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=HEAD;p=platform%2Fupstream%2Fcsf-framework.git Revert "Remove TPCS and TWPServer features" This reverts commit 05eca95adfd234279596bfb329e1e9e718573f2b. Change-Id: I89ed847733b6cda2484e02a821fb7a89434cba08 --- diff --git a/README b/README index 6f9b017..29d69e2 100644 --- a/README +++ b/README @@ -32,6 +32,10 @@ Install following packages to the rootstrap and setup the build environment ************************* +dbus (Version 1.6.4) +dbus-glib (Version 0.100) +glib (Version 2.32.3) +gobject (Version 2.32.3) dlog (Version 1.0) Compiling for multiple architectures @@ -83,3 +87,48 @@ EMULATOR(x86) - use test/scripts/PrepareForEmul.sh - make - The library can be found at 'lib/libsecfw.so' + 2.2 Building IPC Client library + ====================== + - make -f Makefile_channel_client clean + - make -f Makefile_channel_client + - The library can be found at 'lib/libscclient.so' + + 2.3 Building IPC Server library + ====================== + - make -f Makefile_channel_server clean; + - make -f Makefile_channel_server + - The library can be found at 'lib/libscserver.so' + + 2.4 Building Plugin control service + ====================== + - make -f Makefile_TPCSSerDaemon clean; + - make -f Makefile_TPCSSerDaemon + - The binary can be found at 'bin/TPCSSerDaemon' + + 2.5 Building Web protection control service + ====================== + - make -f Makefile_TWPSerDaemon clean + - make -f Makefile_TWPSerDaemon + - The binary can be found at 'bin/TWPSerDaemon' + + 2.6 Testing Plugin control service + ====================== + -cd test (change your folder to test) + -Start the emulator + -chmod +x ./scripts/MfeTPCSSerDaemonToEmul.sh + -sdb -e shell (make sure you have enough privilege to write or read all folders under /opt/, /usr/bin/ and /tmp) + -cd /usr/bin + -chmod +x ./Test.sh + - ./Test.sh + - ./tpcsserdaemontest + + 2.7 Testing Web protection control service + ====================== + -cd test (change your folder to test) + -Start the emulator + -chmod +x ./scripts/MfeTWPSerDaemonToEmul.sh + -sdb -e shell (make sure you have enough privilege to write or read all folders under /opt/, /tmp) + -cd /usr/bin + -chmod +x ./Test.sh + - ./Test.sh + - ./twpserdaemontest \ No newline at end of file diff --git a/framework/IpcClient.c b/framework/IpcClient.c new file mode 100644 index 0000000..935b29c --- /dev/null +++ b/framework/IpcClient.c @@ -0,0 +1,785 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file IpcClient.c + * \brief Ipc Client Source File + * + * This file implements the IPC Client API functions used by Security framework. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "Debug.h" +#include "IpcClient.h" +#include "IpcStructs.h" +#include "TSCErrorCodes.h" + +static DBusHandlerResult _IpcClientMsgFilter(DBusConnection *dbconn, DBusMessage *dbmsg, void *data); +static bool _IpcClientInit(IpcClientInfo *pInfo); +static void _IpcClientDeInit(IpcClientInfo *pInfo); +static void _IpcHandleAsyncReply(DBusPendingCall *pPendingCall, void *pThreadData); +static void _free_str_array(char*** arr, int size); + +/** + * Initializes and returns handle to client side IPC. + */ +TSC_IPC_HANDLE IpcClientOpen(void) +{ + IpcClientInfo *pInfo = NULL; + pInfo = calloc(1, sizeof(IpcClientInfo)); + if (pInfo == NULL) + return NULL; + + snprintf(pInfo->pid, TSC_REQ_STR_LEN, "%d", getpid()); + snprintf(pInfo->req_name, TSC_REQ_STR_LEN, "%s%d", TSC_DBUS_CLIENT, getpid()); + + // Init Dbus Client + if (!_IpcClientInit(pInfo)) + goto err_conn; + + return (TSC_IPC_HANDLE)pInfo; + +err_conn: + if (pInfo) + free(pInfo); + + return INVALID_IPC_HANDLE; +} + +/** + * Close the client-side IPC and release the resources. + */ +void IpcClientClose(TSC_IPC_HANDLE hIpc) +{ + if (hIpc == INVALID_IPC_HANDLE) + return; + + IpcClientInfo *pInfo = (IpcClientInfo *)hIpc; + _IpcClientDeInit(pInfo); + free(pInfo); +} + +/** + * Gives the prefix for the unique id of message sent. + */ +char *_GetMsgIdPrefix(void) +{ + char szIdPrefix[MSGHANDLE_LEN] = {0}; + if (snprintf(szIdPrefix, MSGHANDLE_LEN, TSC_MID_PREFIX_FORMAT, getpid(), pthread_self()) >= 0) + return strdup(szIdPrefix); + + return NULL; +} + +/** + * Requests the Security framework's IPC server and returns back the reply. + */ +int TSCSendMessageN(TSC_IPC_HANDLE hIpc, const char *service_name, const char *szMethod, int argc, + char **argv, int *argc_reply, char ***argv_reply, int timeout_milliseconds) +{ + IpcClientInfo *pInfo = (IpcClientInfo *)hIpc; + DBusMessage *dbmsg = NULL; + DBusMessage *reply_msg = NULL; + DBusMessageIter dbiter; + DBusError dberr; + char *pArgItem = NULL; + char *pBuf = NULL; + int i = 0; + int j = 0; + int iErr = TSC_ERROR_MODULE_GENERIC; + int iSize = TSC_REPLY_MSG_COUNT_AVERAGE; + + *argc_reply = 0; + + // TODO: Avoid multiple exits. + if (pInfo == NULL) + return TSC_ERROR_INVALID_HANDLE; + + if (pInfo->dbconn == NULL) + return TSC_ERROR_INVALID_HANDLE; + + if (argc < 0 || !szMethod) + return TSC_ERROR_INVALID_PARAM; + + *argv_reply = malloc(iSize * sizeof(char *)); + if (!*argv_reply) + { + iErr = TSC_ERROR_INSUFFICIENT_RES; + goto err_send; + } + + dbus_error_init(&dberr); + + dbmsg = dbus_message_new_method_call(service_name, TSC_DBUS_PATH, TSC_DBUS_INTERFACE, szMethod); + if (dbmsg == NULL) + { + iErr = TSC_ERROR_INSUFFICIENT_RES; + goto err_send; + } + dbus_message_iter_init_append(dbmsg, &dbiter); + + // Add the message unique id as first element (the prefix). + char *szIdPrefix = _GetMsgIdPrefix(); + if (!szIdPrefix || !dbus_message_iter_append_basic(&dbiter, DBUS_TYPE_STRING, &szIdPrefix)) + { + DDBG("client_lib: Failed to append id prefix for %s.\n", szMethod); + free(szIdPrefix); + goto err_send; + } + free(szIdPrefix); + for (i = 0; i < argc; i++) + { + if (!dbus_validate_utf8(argv[i], &dberr)) + { + DDBG("%s", "client_lib: Not valid utf8 string\n"); + goto err_send; + } + if (!dbus_message_iter_append_basic(&dbiter, DBUS_TYPE_STRING, &argv[i])) + { + DDBG("client_lib: %s failed to append arguments\n", pInfo->pid); + goto err_send; + } + } + + if (timeout_milliseconds == 0) + timeout_milliseconds = DBUS_TIMEOUT_INFINITE; + + reply_msg = dbus_connection_send_with_reply_and_block(pInfo->dbconn, dbmsg, + timeout_milliseconds, + &dberr); + + if (reply_msg == NULL && dbus_error_is_set(&dberr)) + { + DDBG("client_lib: Failed to end %s\n", dberr.message); + goto err_send; + } + + if (reply_msg == NULL) + { + DDBG("%s\n", "client_lib: reply message is NULL"); + goto err_send; + } + + j = 0; + if (!dbus_message_iter_init(reply_msg, &dbiter)) + { + DDBG("%s\n", "client_lib: Message has no arguments."); + goto zero_args; + } + + do + { + if (dbus_message_iter_get_arg_type(&dbiter) != DBUS_TYPE_STRING) + { + DDBG("client_lib: %s argument is not string\n", pInfo->pid); + goto err_send; + } + + dbus_message_iter_get_basic(&dbiter, &pArgItem); + if (!pArgItem) + { + DDBG("client_lib: %s arg is NULL\n", pInfo->pid); + goto err_send; + } + + if (!(pBuf = strdup((const char*)pArgItem))) + { + goto err_send; + } + (*argv_reply)[j++] = pBuf; + + if (j >= iSize) + { + iSize += TSC_REPLY_MSG_COUNT_AVERAGE; + *argv_reply = realloc(*argv_reply, sizeof(char*) * iSize); + if (!*argv_reply) + { + goto err_send; + } + } + } while (dbus_message_iter_has_next(&dbiter) && dbus_message_iter_next(&dbiter)); + +zero_args: + *argc_reply = j; + return 0; + +err_send: + if (*argv_reply) + { + while (j) + free((*argv_reply)[--j]); + + free(*argv_reply); + *argv_reply = NULL; + } + if (dbmsg) + dbus_message_unref(dbmsg); + if(reply_msg) + dbus_message_unref(reply_msg); + + return -1; +} + +/** + * Block current thread till message is sent and structure is updated in child thread. + */ +void BlockTillSent(SharedData *pSharedData) +{ + pthread_mutex_lock(&pSharedData->lock); + while (pSharedData->iSent == 0) + pthread_cond_wait(&pSharedData->cond, &pSharedData->lock); + pthread_mutex_unlock(&pSharedData->lock); +} + +/** + * Unblock parent thread as the message structures have been updated. + * Unblocks only 1 thread associated with the condition variable. + * Broadcast avoided as only waiting thread is expected. + */ +void UnblockOnSent(SharedData *pSharedData) +{ + pthread_mutex_lock(&pSharedData->lock); + pSharedData->iSent = 1; + pthread_cond_signal(&pSharedData->cond); + pthread_mutex_unlock(&pSharedData->lock); +} + +/** + * Creates a thread for asynchronous task. + * TODO: Merge with TCS module. + */ +int _RunDetachedThread(void *pfWorkerFunc, void *pThreadData) +{ + pthread_t thread; + pthread_attr_t attr; + + int rc = -1; + do + { + if (pthread_attr_init(&attr) != 0) + break; + + if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) + break; + + if (pthread_create(&thread, &attr, pfWorkerFunc, pThreadData) != 0) + break; + + if (pthread_attr_destroy(&attr) != 0) + { + // As the thread is already running, return different error code. + rc = -2; + break; + } + + rc = 0; + } + while (0); + + return rc; +} + +void *_SendMessageWorker(void *pData) +{ + dbus_bool_t result; + DBusPendingCall *pPendingCall = NULL; + ThreadData *pThreadData = (ThreadData *) pData; + ThreadData *pPendingData = NULL; + int iSentFailed = 1; + + do + { + if (pThreadData == NULL) + { + DDBG("%s\n", "Nothing to send from thread. Deadlock!!"); + break; + } + + // Duplicate the User data to create the pending User data. + pPendingData = _AllocThreadData(NULL, DEF_TIMEOUT, NULL, pThreadData->pCallBack, + pThreadData->pPrivate); + if (pPendingData == NULL) + { + DDBG("%s\n", "Duplicating user data in thread failed. Deadlock!!"); + break; + } + + // Ownership of pThreadData remains with 'parent' thread. + result = dbus_connection_send_with_reply(pThreadData->pConn, pThreadData->pSharedData->pMsg, + &pPendingCall, pThreadData->timeout_milliseconds); + if (!result || !pPendingCall) + { + DDBG("%s\n", "client_lib: SendAsync failed."); + break; + } + + if (!pPendingData->pCallBack) + dbus_pending_call_cancel(pPendingCall); + else + dbus_pending_call_set_notify(pPendingCall, _IpcHandleAsyncReply, pPendingData, + _FreeThreadData); + + // Set the values for parent thread to allow cancellation or further async action if needed. + if (_CreateClientCallHandle(&pThreadData->pSharedData->pCallHandle, + pThreadData->pSharedData->szCallHandlePrefix, + dbus_message_get_serial(pThreadData->pSharedData->pMsg), + pPendingCall) != 0) + { + dbus_pending_call_cancel(pPendingCall); + break; + } + + UnblockOnSent(pThreadData->pSharedData); + // WARNING: Do not use pThreadData beyond this point, as parent thread may destroy it. + + dbus_pending_call_block(pPendingCall); + + iSentFailed = 0; + } + while(0); + + if (iSentFailed && pThreadData) + { + DDBG("%s\n", "Error in send messsage worker. Unblocking.."); + UnblockOnSent(pThreadData->pSharedData); + } + + DDBG("%s\n", "Finished send message worker."); + return NULL; +} + + +/** + * Requests the Security framework's IPC server asynchronously. + */ +int TSCSendMessageAsync(TSC_IPC_HANDLE hIpc, const char *service_name, const char *szMethod, + int argc, char **argv, TSC_CALL_HANDLE *phCallHandle, TSCCallback pCallback, + void *pPrivate, int timeout_milliseconds) +{ + DDBG("%s %s\n", "sendmessage async ", service_name); + IpcClientInfo *pInfo = (IpcClientInfo *)hIpc; + DBusMessage *pMsg = NULL; + DBusMessageIter dbiter; + DBusError dberr; + ThreadData *pThreadData = NULL; + int i = 0; + int iErr = TSC_ERROR_MODULE_GENERIC; + + // TODO: Avoid multiple exits. + if (pInfo == NULL) + return TSC_ERROR_INVALID_HANDLE; + + if (pInfo->dbconn == NULL) + return TSC_ERROR_INVALID_HANDLE; + + if (argc < 0 || !szMethod) + return TSC_ERROR_INVALID_PARAM; + + dbus_error_init(&dberr); + pMsg = dbus_message_new_method_call(service_name, TSC_DBUS_PATH, TSC_DBUS_INTERFACE, szMethod); + + if (pMsg == NULL) + { + iErr = TSC_ERROR_INSUFFICIENT_RES; + goto err_send; + } + + dbus_message_iter_init_append(pMsg, &dbiter); + + // Add the message unique id as first element (the prefix). + char *szIdPrefix = _GetMsgIdPrefix(); + if (!szIdPrefix || !dbus_message_iter_append_basic(&dbiter, DBUS_TYPE_STRING, &szIdPrefix)) + { + DDBG("client_lib: Failed to append id prefix for %s.\n", szMethod); + free(szIdPrefix); + goto err_send; + } + + for (i = 0; i < argc; i++) + { + if (!dbus_validate_utf8(argv[i], &dberr)) + { + DDBG("%s", "client_lib: Not valid utf8 string\n"); + goto err_send; + } + if (!dbus_message_iter_append_basic(&dbiter, DBUS_TYPE_STRING, &argv[i])) + { + DDBG("client_lib: %s failed to append arguments\n", pInfo->pid); + goto err_send; + } + } + + // Reply is discarded and not sent back to client, if no callback available. + if (!pCallback) + dbus_message_set_no_reply(pMsg, TRUE); + + SharedData *pSharedData = _CreateSharedData(szIdPrefix, pMsg); + free(szIdPrefix); + + if (!pSharedData) + { + iErr = TSC_ERROR_INSUFFICIENT_RES; + goto err_send; + } + + if (timeout_milliseconds == 0) + timeout_milliseconds = DBUS_TIMEOUT_INFINITE; + + pThreadData = _AllocThreadData(pInfo->dbconn, timeout_milliseconds, pSharedData, pCallback, + pPrivate); + if (!pThreadData) + { + _FreeSharedData(pSharedData); + iErr = TSC_ERROR_INSUFFICIENT_RES; + goto err_send; + } + + // Assert that the message is ready to be used. + if (pThreadData->pSharedData->iSent) + { + DDBG("%s\n", "client_lib: Sent flag already set!!"); + goto err_send; + } + + DDBG("Before sending: %d\n", dbus_message_get_serial(pMsg)); + if (_RunDetachedThread(_SendMessageWorker, pThreadData) == -1) + { + DDBG("%s\n", "client_lib: Running thread failed!!"); + goto err_send; + } + + BlockTillSent(pThreadData->pSharedData); + DDBG("After sending: %d\n", dbus_message_get_serial(pMsg)); + + if (phCallHandle) + { + *phCallHandle = (TSC_CALL_HANDLE)pThreadData->pSharedData->pCallHandle; + //TODO: should add here + DDBG("method unique id :%s\n", ((ClientCallHandle*) phCallHandle)->idUnique); + strncpy(pThreadData->pSharedData->pCallHandle->service_name, service_name, TSC_SERVER_NAME_LEN); + } + else + { + // The caller does not want to call special methods (cancel, get progress) later. + _FreeClientCallHandle(pThreadData->pSharedData->pCallHandle); + pThreadData->pSharedData->pCallHandle = NULL; + } + + iErr = 0; + +err_send: + if (pMsg) + dbus_message_unref(pMsg); + + if (pThreadData) + _FreeThreadData(pThreadData); + + return iErr; +} + +/** + * Releases the asynchronous call handle. + */ +void TSCFreeSentMessageHandle(TSC_CALL_HANDLE hCallHandle) +{ + _FreeClientCallHandle((ClientCallHandle *)hCallHandle); +} + +/** + * Callback when reply is received from IPC server for asynchronous method call. + */ +static void _IpcHandleAsyncReply(DBusPendingCall *pPendingCall, void *pThreadData) +{ + int i = 0; + int argc = 0; + char **argv = NULL; + char *pBuf = NULL; + char *pArgItem = NULL; + DBusError dberr; + DBusMessageIter dbiter; + DBusMessage *pMsg = NULL; + int iErr = TSC_ERROR_MODULE_GENERIC; + int iSize = TSC_REPLY_MSG_COUNT_AVERAGE; + ThreadData *pData = (ThreadData *)pThreadData; + + argv = malloc(iSize * sizeof(char *)); + if (!argv) + { + iErr = TSC_ERROR_INSUFFICIENT_RES; + goto reply_err; + } + + dbus_error_init(&dberr); + + pMsg = dbus_pending_call_steal_reply(pPendingCall); + if (pMsg == NULL) + { + DDBG("%s\n", "client_lib: reply message is NULL"); + goto reply_err; + } + + i = 0; + if (!dbus_message_iter_init(pMsg, &dbiter)) + { + DDBG("%s\n", "client_lib: Async reply has no arguments"); + goto reply_err; + } + + do + { + if (dbus_message_iter_get_arg_type(&dbiter) != DBUS_TYPE_STRING) + { + DDBG("%s\n", "client_lib: Reply argument is not string"); + goto reply_err; + } + + dbus_message_iter_get_basic(&dbiter, &pArgItem); + if (!pArgItem) + { + DDBG("%s\n", "client_lib: Failed getting string arg from reply"); + goto reply_err; + } + + if (!(pBuf = strdup((const char*)pArgItem))) + { + goto reply_err; + } + argv[i++] = pBuf; + + if (i >= iSize) + { + iSize += TSC_REPLY_MSG_COUNT_AVERAGE; + argv = realloc(argv, sizeof(char*) * iSize); + if (!argv) + { + goto reply_err; + } + } + } while (dbus_message_iter_has_next(&dbiter) && dbus_message_iter_next(&dbiter)); + + argc = i; + // Continue passing the returned values to callback. + goto forward_reply; + +reply_err: + // Reset values being returned. + _free_str_array(&argv, i); + +forward_reply: + if(pMsg) + dbus_message_unref(pMsg); + if (pPendingCall) + dbus_pending_call_unref(pPendingCall); + + if (pData && pData->pCallBack) + (*(pData->pCallBack))(pData->pPrivate, argc, (const char**)argv); + + _free_str_array(&argv, i); + + DDBG("%s\n", "client_lib: Async Reply Completed."); +} + + +/** + * Cancels an asynchronous request previously made to the Security framework's IPC server. + * On success, releases the handle of the previously called asynchronous method. + */ +int TSCCancelMessage(TSC_IPC_HANDLE hIpc, TSC_CALL_HANDLE hCallHandle) +{ + IpcClientInfo *pInfo = (IpcClientInfo *)hIpc; + ClientCallHandle *pCallHandle = (ClientCallHandle *)hCallHandle; + char *argv_req[1]; + int iResult = -1; + + do + { + DDBG("%s\n", "client_lib: CANCELing."); + if (!pInfo || !pCallHandle) + break; + + DDBG("%s\n", "prepare cancel"); + // Cancel the message call locally. + dbus_pending_call_cancel(pCallHandle->pPendingCall); + + // Now request the server to abort the running of the method. + argv_req[0] = pCallHandle->idUnique; + DDBG("cancel method unique id:%s\n", argv_req[0]); + //TODO: need change here for cancel message + + TSC_CALL_HANDLE handle = NULL; + iResult = TSCSendMessageAsync((TSC_IPC_HANDLE)pInfo, pCallHandle->service_name, + TSC_FN_CANCELMETHOD, 1, argv_req, &handle, NULL, NULL, + DEF_TIMEOUT); + DDBG("%s\n", "client_lib: Sent Cancel to server."); + + if (iResult == 0) + { + _FreeClientCallHandle(pCallHandle); + } + + } while (0); + + return iResult; +} + +static DBusHandlerResult _IpcClientMsgFilter(DBusConnection *dbconn, DBusMessage *dbmsg, void *data) +{ + IpcClientInfo *info = (IpcClientInfo*) data; + if (dbus_message_is_signal(dbmsg, DBUS_INTERFACE_LOCAL, "Disconnected")) + { + DDBG("client_lib: %s disconnected by signal\n", info->pid); + info->dbconn = NULL; + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static bool _IpcClientInit(IpcClientInfo *pInfo) +{ + if (!pInfo) + return false; + + DBusError dberr; + int ret; + + if (!dbus_threads_init_default()) + { + DDBG("failed dbus_threads_init_default %s\n", ""); + goto err; + } + + dbus_error_init(&dberr); + + + if (pInfo->dbconn != NULL) + return false; + + pInfo->dbconn = dbus_bus_get(DBUS_BUS_SYSTEM, &dberr); + + if (pInfo->dbconn == NULL && dbus_error_is_set(&dberr)) + { + DDBG("client_lib: %s error in get connection %s\n", pInfo->pid, dberr.message); + goto err_get; + } + + if (!pInfo->dbconn) + { + DDBG("client_lib: %s get connection is NULL\n", pInfo->pid); + goto err_get; + } + + dbus_connection_set_exit_on_disconnect(pInfo->dbconn, false); + + if (!dbus_connection_add_filter(pInfo->dbconn, _IpcClientMsgFilter, pInfo, NULL)) + { + DDBG("client_lib: %s failed to add filter %s\n", pInfo->pid, dberr.message); + goto err_get; + } + + ret = dbus_bus_request_name(pInfo->dbconn, pInfo->req_name, DBUS_NAME_FLAG_REPLACE_EXISTING, &dberr); + + if (ret == -1 && dbus_error_is_set(&dberr)) + { + DDBG("client_lib: %s failed to request name %s\n", pInfo->pid, dberr.message); + goto err_get; + } + + if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + { + DDBG("client_lib: %s failed, it is not primary owner %d\n", pInfo->req_name, ret); + goto err_get; + } + + dbus_error_free(&dberr); + return true; + +err_get: + if (pInfo->dbconn) + { + dbus_connection_unref(pInfo->dbconn); + pInfo->dbconn = NULL; + } + dbus_error_free(&dberr); + +err: + return false; +} + +static void _IpcClientDeInit(IpcClientInfo *pInfo) +{ + if (!pInfo) + return; + + DBusError dberr; + int ret; + + if (!pInfo->dbconn) + return; + + dbus_error_init(&dberr); + ret = dbus_bus_release_name(pInfo->dbconn, pInfo->req_name, &dberr); + + if (ret == -1 && dbus_error_is_set(&dberr)) + DDBG("client_lib: %s failed to release name %s\n", pInfo->pid, dberr.message); + + dbus_error_free(&dberr); + + dbus_connection_remove_filter(pInfo->dbconn, _IpcClientMsgFilter, pInfo); + dbus_connection_unref(pInfo->dbconn); + pInfo->dbconn = NULL; +} + +/** + * Release all the elements of the array and assign it to NULL. + */ +static void _free_str_array(char*** arr, int size) +{ + if (arr) + { + char **sArr = *arr; + if (sArr && *sArr) + { + while (size) + free(sArr[--size]); + + free(sArr); + *arr = NULL; + } + } +} diff --git a/framework/IpcClient.h b/framework/IpcClient.h new file mode 100644 index 0000000..42681c4 --- /dev/null +++ b/framework/IpcClient.h @@ -0,0 +1,151 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef IPCCLIENT_H +#define IPCCLIENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file IpcClient.h + * \brief Ipc Client Header File + * + * This file provides the IPC Client API functions used by Security framework. + */ + +#include "IpcTypes.h" + +/*================================================================================================== + CONSTANTS & ENUMS +==================================================================================================*/ +#define DEF_TIMEOUT -1 + + +/*================================================================================================== + FUNCTION PROTOTYPES +==================================================================================================*/ + +/** + * \brief Initializes client side IPC and returns its handle. + * + * Opens and initialises the handle to client side IPC using the security + * framework defaults. + * + * This is a synchronous API. + * + * \return Return Type (TSC_IPC_HANDLE) \n + * Client IPC handle - on success. \n + * NULL - on failure. \n + */ +TSC_IPC_HANDLE IpcClientOpen(void); + +/** + * \brief Requests the Security framework's IPC server and returns back the reply. + * + * This is a synchronous API. + * + * \param[in] hIpc IPC handle returned by IpcClientOpen(). + * + * \return Return Type (void) \n + */ +void IpcClientClose(TSC_IPC_HANDLE hIpc); + +/** + * \brief Requests the Security framework's IPC server and returns back the reply. + * + * This is a synchronous API. + * + * \param[in] hIpc Client side IPC handle. + * \param[in] szMethod Name of the method called. + * \param[in] argc Number of parameters passed in argv. + * \param[in] argv Array of strings representing parameters for method called. + * \param[out] reply_len Length of the string in reply_argv. + * \param[out] reply_argv Array of strings representing result value from method called. + * \param[in] timeout_milliseconds Timeout in milliseconds. -1 for default or 0 for no timeout. + * + * \return Return Type (int) \n + * 0 - on send success. \n + * -1 - on send failure. \n + */ +int TSCSendMessageN(TSC_IPC_HANDLE hIpc, const char *service_name, const char *szMethod, int argc, + char **argv, int *argc_reply, char ***argv_reply, int timeout_milliseconds); + +/** + * \brief Requests the Security framework's IPC server asynchronously. + * + * This is an asynchronous API. + * + * \param[in] hIpc Client side IPC handle. + * \param[in] szMethod Name of the method called. + * \param[in] argc Number of parameters passed in argv. + * \param[in] argv Array of strings representing parameters for method called. + * \param[out] phCallHandle Pointer to handle of the asynchronous message sent. + * \param[in] pCallback Callback function for the asynchronous reply. + * \param[in] pPrivate API caller's context information, to be supplied with callback. + * \param[in] timeout_milliseconds Timeout in milliseconds. -1 for default or 0 for no timeout. + * + * \return Return Type (int) \n + * 0 - on send success. \n + * Error code - on send failure. \n + */ +int TSCSendMessageAsync(TSC_IPC_HANDLE hIpc, const char *service_name, const char *szMethod, int argc, char **argv, + TSC_CALL_HANDLE *phCallHandle, TSCCallback pCallback, void *pPrivate, + int timeout_milliseconds); + +/** + * \brief Releases the asynchronous call handle. + * + * \param[in] hCallHandle Handle of the asynchronous message sent earlier. + */ +void TSCFreeSentMessageHandle(TSC_CALL_HANDLE hCallHandle); + +/** + * \brief Cancels an asynchronous request previously made to the Security framework's IPC server. + * On success, releases the handle of the previously called asynchronous method. + * + * This is an asynchronous API. + * + * \param[in] hIpc Client side IPC handle. + * \param[in] hCallHandle Handle of the asynchronous message sent earlier. + * + * \return Return Type (int) \n + * 0 - on send success. \n + * Error code - on failure. \n + */ +int TSCCancelMessage(TSC_IPC_HANDLE hIpc, TSC_CALL_HANDLE hCallHandle); + +#ifdef __cplusplus +} +#endif + +#endif /* IPCCLIENT_H */ diff --git a/framework/IpcForkDaemon.c b/framework/IpcForkDaemon.c new file mode 100644 index 0000000..5ee1f3c --- /dev/null +++ b/framework/IpcForkDaemon.c @@ -0,0 +1,96 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file IpcForkDaemon.c + * \brief Ipc Fork Daemon source file. + * + * This file implements the Ipc Fork Daemon function used by Security framework. + */ + +#include "Debug.h" +#include "IpcForkDaemon.h" +#include + +void +fork_daemon() +{ + pid_t pid; + + // Fork off the parent process. + pid = fork(); + + // An error occurred. + if (pid < 0) + { + DERR("%s\n", "unable to start the TWPSerDaemon"); + exit(EXIT_FAILURE); + } + + // Success: Let the parent terminate. + if (pid > 0) + { + DERR("%s\n", "Successfully forked the child process"); + exit(EXIT_SUCCESS); + } + + // On success: The child process becomes session leader. + if (setsid() < 0) + { + DERR("%s\n", "unable to start the TWPSerDaemon"); + exit(EXIT_FAILURE); + } + + signal(SIGCHLD, SIG_IGN); + signal(SIGHUP, SIG_IGN); + + // Fork off for the second time to ensure session leading process ends. + pid = fork(); + + // An error occurred. + if (pid < 0) + { + DERR("%s\n", "unable to start the TWPSerDaemon"); + exit(EXIT_FAILURE); + } + + // Success: Let the session leading process end. + if (pid > 0) + { + DERR("%s\n", "Successfully forked the TWPSerDaemon process in the new session"); + exit(EXIT_SUCCESS); + } + + //close the file descriptors of terminal associated with the process + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); +} diff --git a/framework/IpcForkDaemon.h b/framework/IpcForkDaemon.h new file mode 100644 index 0000000..da186ac --- /dev/null +++ b/framework/IpcForkDaemon.h @@ -0,0 +1,54 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file IpcForkDaemon.h + * \brief TWP Server Daemon Header file. + * + * This file has the function prototypes. + */ + +#include +#include +#include +#include +#include + +/** + * \brief this method forks the daemon + * This is a synchronized API. + * + * \param[in] none. + * \param[out] none. + * \return Return Type (void) \n + * + */ +void fork_daemon(); diff --git a/framework/IpcMacros.h b/framework/IpcMacros.h new file mode 100644 index 0000000..4c91412 --- /dev/null +++ b/framework/IpcMacros.h @@ -0,0 +1,87 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef IPCMACROS_H +#define IPCMACROS_H + +/** + * \file IpcMacros.h + * \brief Common constants and macros Header File + * + * This file provides the constants and macros for IPC used by Security framework. + */ + +#define TSC_DBUS_SERVER_GENERIC_STUB "com.tsc.ipc.server.generic" +#define TSC_DBUS_SERVER_WP_CHANNEL "com.tsc.ipc.server.wp" +#define TSC_DBUS_SERVER_PLUGIN_CHANNEL "com.tsc.ipc.server.plugin" +#define TSC_DBUS_SERVER_INTEGRITY_TEST_STUB "com.tsc.ipc.server.integrity" + +#define TSC_DBUS_SERVER "com.tsc.ipc.server" +#define TSC_DBUS_INTERFACE "org.tsc.ipc.interface" +#define TSC_DBUS_PATH "/org/tsc/ipc/path" +#define TSC_DBUS_CLIENT "com.tsc.ipc.client" +#define TSC_FN_FETCHLIST "FetchList" +#define TSC_FN_CANCELMETHOD "_Cancel_" +#define TSC_FN_PROGRESSMETHOD "_Progress_" +#define TSC_FN_SHUTDOWN "IpcShutdown" + +#define TSC_MID_PREFIX_FORMAT "%u_%lu_" +#define TSC_MID_FORMAT TSC_MID_PREFIX_FORMAT"%u" +#define TSC_MID_SVR_FORMAT "%s%u" + +#define TSC_READ_WRITE_DISPATCH_SLEEP_SECONDS 1 +#define TSC_SEND_MESSAGE_REPLY_TIME 5000 + +#define TSC_THREAD_POOL_NUMBERS 3 + +#define TSC_REQ_STR_LEN 128 +#define TSC_INFO_RULE_LEN 128 +#define TSC_SERVER_NAME_LEN 128 +#define TSC_METHOD_NAME_LEN 128 + +#define TSC_REPLY_MSG_COUNT_AVERAGE 4 + + +// Client side call handle length. +// TODO: Reduce size by avoiding string type handle. +#define MSGHANDLE_LEN 25 + +typedef enum +{ + TSC_CANCEL = -1, + TSC_PROGRESS = 0 +} TSC_METHOD_REASON_CODE; + +#define TSC_IS_CANCEL 0 +#define TSC_NON_CANCEL 1; + +#endif /* IPCMACROS_H */ + diff --git a/framework/IpcServer.c b/framework/IpcServer.c new file mode 100644 index 0000000..3d85e85 --- /dev/null +++ b/framework/IpcServer.c @@ -0,0 +1,1239 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file IpcServer.c + * \brief Ipc Server Source File + * + * This file implements the IPC Server API functions used by Security framework. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "Debug.h" +#include "IpcMacros.h" +#include "IpcServerError.h" +#include "IpcServerHdr.h" +#include "TSCErrorCodes.h" + + +#ifdef DEBUG +#define DBUS_D_LOG(_dbusErr_, _fmt_, _param_...) \ + { \ + DDBG("%s:%s; " _fmt_, _dbusErr_.name, _dbusErr_.message, _param_); \ + } +#else +#define DBUS_D_LOG(_dbusErr_, _fmt_, _param_...) +#endif + +static void IterateList(IpcMethodHandle* pHandle) +{ + IpcMethodHandle *ph; + int count = 0; + for(ph = pHandle; ph != NULL; ph = ph->pNext) + { + count++; + } + DDBG(".....total count: %d\n", count); +} + +inline DBusHandlerResult _IpcSendMessageAndUnref(DBusConnection *pConn, DBusMessage *pMsg) +{ + if (pMsg) { + dbus_connection_send(pConn, pMsg, NULL); + dbus_message_unref(pMsg); + } + return DBUS_HANDLER_RESULT_HANDLED; +} + +void _FreeHandleMethods(IpcServerInfo *pInfo) +{ + if (!pInfo) + return; + + // Free MethodList + IpcServerMethodList *pCurr = pInfo->pMethodList; + IpcServerMethodList *pPrev = NULL; + + pthread_mutex_lock(&(pInfo->Lock)); + while (pCurr) + { + pPrev = pCurr; + pCurr = pCurr->pNext; + + if (pPrev->pMethod) + { + /* TODO: Explain why its not leak for non-cancel methods. */ + //if (pPrev->pMethod->method == (METHODFUNC)IpcCancelMethod || pPrev->pMethod->method == (METHODFUNC)IpcGetProgressMethod) + free(pPrev->pMethod); + + pPrev->pMethod = NULL; + } + free(pPrev); + } + pInfo->pMethodList = NULL; + pInfo->pRunningMethods = NULL; + pthread_mutex_unlock(&(pInfo->Lock)); + +} + +void _FreeHandlePool(IpcServerInfo *pInfo) +{ + if (!pInfo) + return; + + while(IpcThrPoolIdleCount(pInfo->pHandlePool) != TSC_THREAD_POOL_NUMBERS && IpcThrPoolIdleCount(pInfo->pHandlePool) != -1) //wait till no detachable thread is running + { + // TODO: Use condition instead of infinite loop + sleep(1); + } + pthread_mutex_lock(&(pInfo->Lock)); + + if (pInfo->pHandlePool) + { + IpcThrPoolFree(&pInfo->pHandlePool); + } + + pthread_mutex_unlock(&(pInfo->Lock)); +} + +void _FreeHandleTable(IpcServerInfo *pInfo) +{ + if (!pInfo) + return; + + pthread_mutex_lock(&(pInfo->Lock)); + if (pInfo->pTable) + { + free(pInfo->pTable); + pInfo->pTable = NULL; + } + pthread_mutex_unlock(&(pInfo->Lock)); +} + +void _FreeHandleConn(IpcServerInfo *pInfo) +{ + if (!pInfo) + return; + + pthread_mutex_lock(&(pInfo->Lock)); + if (pInfo->pConn) + { + dbus_connection_remove_filter(pInfo->pConn, _IpcServerMsgFilter, pInfo); + pInfo->pConn = NULL; + } + pthread_mutex_unlock(&(pInfo->Lock)); + +} + +void _WaitForListenThreadClose(IpcServerInfo *pInfo) +{ + if (pInfo && pInfo->lDbus_listen_thread) + { + pthread_mutex_lock(&(pInfo->Lock)); + pInfo->start_server_flag = false; + pthread_mutex_unlock(&(pInfo->Lock)); + + if (pInfo->lDbus_listen_thread) + pthread_join(pInfo->lDbus_listen_thread, NULL); + } +} + +int IpcServerAddMethod(TSC_SERVER_HANDLE hServer, IpcServerMethod *pMethod) +{ + IpcServerInfo *pInfo = NULL; + IpcServerMethodList *pList = NULL; + int r = TSC_ERROR_ADD_METHOD_FAILED; + + if (INVALID_TSC_SERVER_HANDLE == hServer) + return r; + + pList = calloc(1, sizeof(IpcServerMethodList)); + if (!pList) + return r; + + IpcServerMethod* tpMethod = calloc(1, sizeof(IpcServerMethod)); + if (tpMethod == NULL) + { + free(pList); + pList = NULL; + return r; + } + // Copy method + + tpMethod->method = pMethod->method; + strncpy(tpMethod->szMethod, pMethod->szMethod, TSC_METHOD_NAME_LEN-1); + tpMethod->pData = pMethod->pData; + + pInfo = (IpcServerInfo *) hServer; + + pthread_mutex_lock(&(pInfo->Lock)); + pList->pNext = pInfo->pMethodList; + + //pList->pMethod = pMethod; + pList->pMethod = tpMethod; + + pInfo->pMethodList = pList; + pthread_mutex_unlock(&(pInfo->Lock)); + + r = 0; + return r; +} + +int IpcServerRemoveMethod(TSC_SERVER_HANDLE hServer, METHODFUNC method) +{ + IpcServerInfo *pInfo = NULL; + IpcServerMethodList **pPrev = NULL; + IpcServerMethodList *pCurr = NULL; + int r = TSC_ERROR_REMOVE_METHOD_NOT_FOUND; + + DDBG("%s\n", "IpcServerRemoveMethod"); + if (INVALID_TSC_SERVER_HANDLE == hServer) + return r; + + pInfo = (IpcServerInfo *) hServer; + + // Change the head to next node, if deleted. + pthread_mutex_lock(&(pInfo->Lock)); + for (pPrev = &pInfo->pMethodList; *pPrev; pPrev = &(*pPrev)->pNext) + { + DDBG("REMOVE method list name :%s\n", (*pPrev)->pMethod->szMethod); + if ((*pPrev)->pMethod->method == method) + { + DDBG("==== FIND REVMOE MOETHOD %s\n", " "); + pCurr = *pPrev; + *pPrev = (*pPrev)->pNext; + r = 0; + break; + } + } + pthread_mutex_unlock(&(pInfo->Lock)); + + // Release the found method now. + if (r == 0 && pCurr->pMethod) + { + free(pCurr->pMethod); + pCurr->pMethod = NULL; + } + free(pCurr); + + return r; +} + +TSC_SERVER_HANDLE IpcServerOpen(char *service_name) +{ + DDBG("IpcServerOpen: %s\n", service_name); + DBusError dberr; + + if (!dbus_threads_init_default()) + { + DDBG("failed dbus_threads_init_default %s\n", ""); + goto err_ret; + } + + dbus_error_init(&dberr); + + if (!dbus_validate_bus_name(service_name, &dberr) && dbus_error_is_set(&dberr)) + { + DDBG("it is invalid request name %s\n", ""); + goto err; + } + + IpcServerInfo *pInfo; + if ((pInfo = (IpcServerInfo *) calloc(1, sizeof(IpcServerInfo))) == NULL) + goto err; + + pInfo->pMethodList = NULL; + pInfo->count = 0; + if ((pInfo->pTable = (DBusObjectPathVTable *) calloc(1, sizeof(DBusObjectPathVTable))) == NULL) + goto free_info; + + pInfo->lDbus_listen_thread = 0; + strncpy(pInfo->name, service_name, TSC_SERVER_NAME_LEN - 1); + + if (_IpcServerInit(pInfo, service_name)) + { + DDBG("IpcServerInit failed: %s\n", service_name); + goto free_table; + } + + //DDBG("IpcServerOpen success conn:%s\n", pInfo->name); + dbus_error_free(&dberr); + return (TSC_SERVER_HANDLE) pInfo; + +free_table: + SAFE_FREE(pInfo->pTable); + +free_info: + DDBG("IpcServerOpen free_info, conn:%s\n", pInfo->name); + FREE(pInfo); + +err: + dbus_error_free(&dberr); + +err_ret: + return INVALID_TSC_SERVER_HANDLE; +} + +int IpcServerMainLoop(TSC_SERVER_HANDLE hServer) +{ + IpcServerInfo *pInfo = (IpcServerInfo*) hServer; + if (pInfo) + { + if (pInfo->lDbus_listen_thread) + { + pthread_join(pInfo->lDbus_listen_thread, NULL); + DDBG("finsihed main loop:%s\n", "=========="); + } + + } + return 0; +} +void IpcServerClose(TSC_SERVER_HANDLE *hServer) +{ + IpcServerInfo *pInfo = (IpcServerInfo *) *hServer; + if (pInfo != (IpcServerInfo*)INVALID_TSC_SERVER_HANDLE) + { + DDBG("IpcServerClose:%s\n", pInfo->name); + _WaitForListenThreadClose(pInfo); + + // Wait till no detachable thread is running + while (IpcThrPoolIdleCount(pInfo->pHandlePool) != TSC_THREAD_POOL_NUMBERS && IpcThrPoolIdleCount(pInfo->pHandlePool) != -1) + { + // TODO: Use conditional mutex. + sleep(1); + } + + _FreeHandleTable(pInfo); + _FreeHandleMethods(pInfo); + _FreeHandlePool(pInfo); + _FreeHandleConn(pInfo); + pthread_mutex_destroy(&(pInfo->Lock)); + + free(pInfo); + *hServer = INVALID_TSC_SERVER_HANDLE; + } +} + + +int _IpcServerInit(IpcServerInfo *pInfo, char *szServiceName) +{ + IpcServerMethod *pMethodCancel = NULL; + DBusError dberr; + int ret; + + if (!pInfo) + goto err; + + pInfo->pMethodList = NULL; + pInfo->pRunningMethods = NULL; + pInfo->start_server_flag = false; + + dbus_error_init(&dberr); + + pInfo->pConn = dbus_bus_get(DBUS_BUS_SYSTEM, &dberr); + if (pInfo->pConn == NULL && dbus_error_is_set(&dberr)) + { + DBUS_D_LOG(dberr, "%s\n", "Server failed: connection NULL."); + goto free_err; + } + + ret = dbus_bus_request_name(pInfo->pConn, szServiceName, DBUS_NAME_FLAG_REPLACE_EXISTING, &dberr); + if (ret == -1 && dbus_error_is_set(&dberr)) + { + DBUS_D_LOG(dberr, "%s\n", "server failed: request name."); + goto free_conn; + } + + // TODO: Why not allow DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER also? + if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + { + DDBG("server failed: Not primary owner :%d\n", ret); + goto free_conn; + } + + if (0 > snprintf(pInfo->rule, sizeof(pInfo->rule), "type='method_call', interface='%s'", + TSC_DBUS_INTERFACE)) + { + DDBG("%s\n", "server failed: Unable to write rule"); + goto free_conn; + } + + dbus_bus_add_match(pInfo->pConn, pInfo->rule, &dberr); + if (dbus_error_is_set(&dberr)) + { + DBUS_D_LOG(dberr, "%s\n", "Match add failed."); + goto free_conn; + } + + if (!dbus_connection_try_register_object_path(pInfo->pConn, TSC_DBUS_PATH, pInfo->pTable, + pInfo, &dberr) + && dbus_error_is_set(&dberr)) + { + DBUS_D_LOG(dberr, "%s\n", "server failed: register object path"); + goto free_match; + } + + dbus_connection_set_exit_on_disconnect(pInfo->pConn, false); + + if (!dbus_connection_add_filter(pInfo->pConn, _IpcServerMsgFilter, pInfo, NULL)) + { + DDBG("%s\n", "server failed: add filter."); + goto free_register; + } + + if (!dbus_connection_get_unix_fd(pInfo->pConn, &pInfo->fd) || pInfo->fd < 0) + { + DDBG("%s\n", "server failed: get fd."); + goto free_filter; + } + + pInfo->pHandlePool = calloc(1, sizeof(IpcHandlePool)); + if (pInfo->pHandlePool == NULL) + { + DDBG("%s\n", "Thread pool alloc failed."); + goto free_filter; + } + + ret = IpcThrPoolInit(pInfo->pHandlePool, TSC_THREAD_POOL_NUMBERS); + if (ret) + { + DDBG("%s\n", "*****Failed in IpcThrPoolInit"); + goto free_handle; + } + + ret = pthread_mutex_init(&(pInfo->Lock), NULL); + if (ret) + { + DDBG("Failed to init IpcServerInfo lock %d\n", ret); + goto free_pool; + } + + // Add default two methods: Cancel and GetStatus + pMethodCancel = calloc(1, sizeof(IpcServerMethod)); + if (pMethodCancel == NULL) + { + DDBG("%s\n", "Cancel alloc failed."); + goto free_mutex; + } + + ret = snprintf(pMethodCancel->szMethod, sizeof(pMethodCancel->szMethod), "%s", TSC_FN_CANCELMETHOD); + if (ret < 0) + { + DDBG("%s\n", "Cancel create failed."); + goto free_method_cancel; + } + + pMethodCancel->method = (METHODFUNC) IpcCancelMethod; + pMethodCancel->pData = NULL; + ret = IpcServerAddMethod((TSC_SERVER_HANDLE) pInfo, pMethodCancel); + if (ret) + { + DDBG("%s\n", "Cancel add failed."); + goto free_method_cancel; + } + + IpcServerMethod *pMethodProgress = calloc(1, sizeof(IpcServerMethod)); + if (pMethodProgress == NULL) + { + DDBG("%s\n", "Progress alloc failed."); + goto free_method_cancel; + } + + ret = snprintf(pMethodProgress->szMethod, sizeof(pMethodProgress->szMethod), "%s", TSC_FN_PROGRESSMETHOD); + if (ret < 0) + { + DDBG("%s\n", "Progress create failed."); + goto free_method_progress; + } + + pMethodProgress->method = (METHODFUNC) IpcGetProgressMethod; + pMethodProgress->pData = NULL; + + ret = IpcServerAddMethod((TSC_SERVER_HANDLE) pInfo, pMethodProgress); + if (ret) + { + DDBG("%s\n", "Progress add failed."); + goto free_method_progress; + } + + IpcServerMethod *pMethodShutdown = calloc(1, sizeof(IpcServerMethod)); + if (pMethodShutdown == NULL) + { + DDBG("%s\n", "shutdown alloc failed."); + goto free_method_progress; + } + + ret = snprintf(pMethodShutdown->szMethod, sizeof(pMethodShutdown->szMethod), "%s", TSC_FN_SHUTDOWN); + if (ret < 0) + { + DDBG("%s\n", "Shutdown create failed."); + goto free_method_shutdown; + } + + pMethodShutdown->method = (METHODFUNC) IpcShutdown; + pMethodShutdown->pData = NULL; + + ret = IpcServerAddMethod((TSC_SERVER_HANDLE) pInfo, pMethodShutdown); + if (ret) + { + DDBG("%s\n", "Shutdown add failed."); + goto free_method_shutdown; + } + SAFE_FREE(pMethodShutdown); + SAFE_FREE(pMethodProgress); + SAFE_FREE(pMethodCancel); + + pthread_mutex_lock(&(pInfo->Lock)); + + ret = pthread_create(&(pInfo->lDbus_listen_thread), NULL, _IpcPopMessage, (void *)pInfo); + DDBG("Creating thrd for Server: %s\n", pInfo->name); + + if (ret) + { + DDBG("%s(%d)\n", "** FAILED to launch thread", ret); + pInfo->start_server_flag = false; + pthread_mutex_unlock(&(pInfo->Lock)); + goto free_mutex; + } + pInfo->start_server_flag = true; + + pthread_mutex_unlock(&(pInfo->Lock)); + + return 0; +free_method_shutdown: + SAFE_FREE(pMethodShutdown); +free_method_progress: + SAFE_FREE(pMethodProgress); +free_method_cancel: + SAFE_FREE(pMethodCancel); +free_mutex: + pthread_mutex_destroy(&(pInfo->Lock)); +free_pool: +free_handle: + if (pInfo->pHandlePool) + IpcThrPoolFree(&pInfo->pHandlePool); +free_filter: + //dbus_connection_remove_filter(pInfo->pConn, _IpcServerMsgFilter, pInfo); +free_register: + //dbus_connection_unregister_object_path(pInfo->pConn, TSC_DBUS_PATH); +free_match: + //dbus_bus_remove_match(pInfo->pConn, pInfo->rule, &dberr); +free_conn: + //dbus_connection_close(pInfo->pConn); TODO: Why not???? +free_err: + dbus_error_free(&dberr); + DDBG("%s", "_IpcServerInit free_err before return -1\n"); +err: + return -1; +} + +void _IpcServerDeInit(TSC_SERVER_HANDLE hServer) +{ + DDBG("%s\n", "IpcServerDeInit========"); + IpcServerInfo *pInfo = (IpcServerInfo *) hServer; + if (pInfo) + { + if (pInfo->lDbus_listen_thread) + { + pthread_join(pInfo->lDbus_listen_thread, NULL); + } + FreeIpcServerHandle((TSC_SERVER_HANDLE) pInfo); + } + //dbus_shutdown(); // for valgrind only + DDBG("%s\n", "*_*_*_*_*_*_* Server is disconnected *_*_*_*_*_*_*_*_*"); +} + + +DBusHandlerResult _IpcServerReplyMessage(DBusConnection *pConn, DBusMessage *pMsg, + char **pReply, int size) +{ + DDBG("%s %d\n", "ReplyMessage size: ", size); + DBusMessage *pReplyMsg = NULL; + DBusMessageIter iter; + int i; + + if (pConn == NULL) + return DBUS_HANDLER_RESULT_HANDLED; + + pReplyMsg = dbus_message_new_method_return(pMsg); + + if (pReplyMsg == NULL) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + dbus_message_iter_init_append(pReplyMsg, &iter); + + for (i = 0; i < size; i++) + { + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &(pReply[i]))) + { + DDBG("----- Replied string :%s\n", pReply[i]); + dbus_message_unref(pReplyMsg); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + } + + return _IpcSendMessageAndUnref(pConn, pReplyMsg); +} + +DBusHandlerResult _IpcServerReplyError(DBusConnection *pConn, DBusMessage *pMsg, + int iErrCode) +{ + DDBG("%s\n", "IpcServerReplyError"); + DBusMessage *pErrMsg = NULL; + + if (!pConn || !pMsg) + return DBUS_HANDLER_RESULT_HANDLED; + + pErrMsg = dbus_message_new_error(pMsg, GetErrorName(iErrCode), GetErrorDescription(iErrCode)); + if (!pErrMsg) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + return _IpcSendMessageAndUnref(pConn, pErrMsg); +} + + +DBusHandlerResult _IpcServerMsgFilter(DBusConnection *pConn, DBusMessage *pMsg, void *pData) +{ + DDBG("%s\n", "IpcServerMsgFilter"); + IpcServerInfo *pInfo = (IpcServerInfo*) pData; + if (!pInfo) + { + DDBG("%s\n", "not handled the server info"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + else if (dbus_message_is_signal(pMsg, DBUS_INTERFACE_LOCAL, "Disconnected")) + { + DDBG("%s\n", "server is disconnected by signal"); + IpcServerClose((TSC_SERVER_HANDLE*) pInfo); + //return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +DBusHandlerResult _IpcServerMsgHandler(void *user_data) +{ + DBusHandlerResult ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + IpcAsyncInfo *pAsync = user_data; + + if (pAsync) + { + DBusMessage *pMsg = pAsync->pMsg; + IpcServerInfo *pInfo = pAsync->pInfo; + + bool handle_flag = false; + if (pInfo) + { + DDBG("==IpcServerMsgHandler:%s\n", pInfo->name); + IpcServerMethodList **pPrev; + pthread_mutex_lock(&(pInfo->Lock)); + for (pPrev = &pInfo->pMethodList; *pPrev; pPrev = &(*pPrev)->pNext) + { + if ((*pPrev) && (*pPrev)->pMethod) + { + if (dbus_message_is_method_call(pMsg, TSC_DBUS_INTERFACE, (*pPrev)->pMethod->szMethod)){ + DDBG("FOUND method: %s\n", (*pPrev)->pMethod->szMethod); + handle_flag = true; + pAsync->pMethod = (*pPrev)->pMethod; + break; + } + } + } + pthread_mutex_unlock(&(pInfo->Lock)); + if (handle_flag) + { + return _IpcServerProcessMessage(pAsync); + } + } + if (ret == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) + { + if (pAsync->pInfo->pHandlePool) + { + IpcThrPoolPut(pAsync->pInfo->pHandlePool, pAsync->pHandle); + } + CleanupAsync(pAsync); + } + + } + + return ret; +} + +int _ParseDBusMessage(DBusMessage *pMsg, int *pargc, char ***argv) +{ + DBusBasicValue temp = {{0}}; + int argc = 0; + int iSize = TSC_REPLY_MSG_COUNT_AVERAGE; + DBusMessageIter iter; + int iRet = TSC_ERROR_NOT_IMPLEMENTED; // Return as result of method requested by client. + + if (dbus_message_iter_init(pMsg, &iter)) + { + do + { + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + { + DDBG("%s\n", "wrong type"); + if (argc == 0) + iSize = 0; + iRet = TSC_ERROR_NOT_IMPLEMENTED; + goto clean_up; + } + dbus_message_iter_get_basic(&iter, &temp); + if (!temp.str) + { + DDBG("%s\n", "no string"); + iRet = TSC_ERROR_INTERNAL; + goto clean_up; + } + + if (argc >= iSize) + { + iSize += TSC_REPLY_MSG_COUNT_AVERAGE; + (*argv) = realloc((*argv), sizeof(char*) * iSize); + + if (!(*argv)) + { + DDBG("PARSE message, insufficient: 7-1, argc:%d iSize:%d\n", argc, iSize); + iRet = TSC_ERROR_INSUFFICIENT_RES; + iSize = iSize - TSC_REPLY_MSG_COUNT_AVERAGE; + goto clean_up; + } + } + else if (argc == 0) + { + (*argv) = calloc(1, iSize * sizeof(char *)); + if (!(*argv)) + { + iRet = TSC_ERROR_INSUFFICIENT_RES; + iSize = 0; //reset iSize, used to free the memory + goto clean_up; + } + } + + (*argv)[argc] = strdup((const char*)temp.str); + + if (!(*argv)[argc]) + { + DDBG("not engough memory: %s\n", "4"); + iRet = TSC_ERROR_INSUFFICIENT_RES; + goto clean_up; + } + argc++; + } while (dbus_message_iter_next(&iter)); + + iRet = 0; // TODO: Is this the right place & code? + } + else + { + DDBG("%s\n", "Request message has no arguments"); + *pargc = argc; + return iRet; + } + +clean_up: + + if (iRet) + { + //Error code here + int i = 0; + if (*argv) + { + for (i = 0; i < iSize; i++) + { + if ((*argv)[i]) + free((*argv)[i]); + (*argv)[i] = NULL; + } + free(*argv); + *argv = NULL; + } + } + else + { + // Everything went well till now... + *pargc = argc; + } + + return iRet; +} + + +DBusHandlerResult _IpcServerProcessMessage(void *user_data) +{ + DDBG("%s\n", "IpcServerProcessMessage"); + IpcAsyncInfo *pAsync = user_data; + DBusError dberr; + char **reply = NULL; + int iFreeMtdHandle = 0; + int len = 0; +// int iErr = DBUS_HANDLER_RESULT_HANDLED; // Return the result to caller of this function. + int iRet = TSC_ERROR_MODULE_GENERIC; // Return as result of method requested by client. + IpcMethodHandle *pMtdHandle = NULL; + + dbus_error_init(&dberr); + if (pAsync->pConn == NULL) + { + goto clean_up; + } + // Here when calling method, pass the callback function + pMtdHandle = calloc(1, sizeof(IpcMethodHandle)); + + if (pMtdHandle == NULL) + { + goto clean_up; + } + + pMtdHandle->pMethod = pAsync->pMethod; + iRet = pthread_mutex_init(&(pMtdHandle->Lock), NULL); + if (iRet) + { + if (pMtdHandle) + free(pMtdHandle); + pMtdHandle = NULL; + goto clean_up; + } + + if ((pAsync->pMethod)->method) + { + // insert to RunningMethods + if (pAsync->argv[0] == NULL) + { + goto clean_up; + } + + strncpy(pMtdHandle->unique_id, pAsync->async_unique_id, MSGHANDLE_LEN); + (pMtdHandle->unique_id)[MSGHANDLE_LEN] = '\0'; + + pthread_mutex_lock(&pAsync->pInfo->Lock); + (pAsync->pInfo->count)++; + pMtdHandle->pNext = pAsync->pInfo->pRunningMethods; + pAsync->pInfo->pRunningMethods = pMtdHandle; +/* + DDBG("============== after adding running method:%s\n", "------"); + IterateList(pMtdHandle); +*/ + pthread_mutex_unlock(&pAsync->pInfo->Lock); + + pMtdHandle->pInfo = pAsync->pInfo; + pMtdHandle->cStatus = "1"; + pMtdHandle->iCancel = TSC_NON_CANCEL; + + // Skip the first params which is for unique_id + DDBG("method to run:%s, argv[0]:%s\n", pAsync->pMethod->szMethod, pAsync->argv[0]); + + iRet = (pAsync->pMethod)->method((pAsync->pMethod)->pData, pAsync->argc - 1, + &(pAsync->argv[1]), &reply, &len, + (CALLBACKFUNC) IpcServerCallbackMethod, pMtdHandle); + iRet = 0; //till here, able to run the method, it is success + } + +clean_up: + + if (iRet) + _IpcServerReplyError(pAsync->pConn, pAsync->pMsg, TSC_ERROR_INTERNAL); + else + { + // Everything went well till now... + _IpcServerReplyMessage(pAsync->pConn, pAsync->pMsg, reply, len); + } + + dbus_connection_flush(pAsync->pConn); + CleanupArray(&reply, len); + + // Method finished, remove it from pInfo, running methods list + IpcMethodHandle **pmpPrev; + pthread_mutex_lock(&(pAsync->pInfo->Lock)); + for (pmpPrev = &(pAsync->pInfo->pRunningMethods); *pmpPrev; pmpPrev = &((*pmpPrev)->pNext)) + { + if (strncmp((*pmpPrev)->unique_id, pAsync->async_unique_id, MSGHANDLE_LEN) == 0) + { + *pmpPrev = (*pmpPrev)->pNext; + iFreeMtdHandle = 1; + DDBG("FOUND method, and remove from running one, method:%s, uniquid:%s\n", + pAsync->pMethod->szMethod, pAsync->async_unique_id); + IterateList(pAsync->pInfo->pRunningMethods); + break; + } + } + pthread_mutex_unlock(&(pAsync->pInfo->Lock)); + + IpcThrPoolPut(pAsync->pInfo->pHandlePool, pAsync->pHandle); + CleanupAsync(pAsync); + dbus_error_free(&dberr); + + if (pMtdHandle && iFreeMtdHandle) + { + free(pMtdHandle); + pMtdHandle = NULL; + } + + return iRet; +} + +void *_IpcPopMessage(void *hServer) +{ + IpcServerInfo *pInfo = (IpcServerInfo *) hServer; + DDBG("=IpcPopMessage:%s\n", pInfo->name); + int iRet = 0; + + while (pInfo != NULL && pInfo->pConn != NULL && pInfo->start_server_flag) { + + // non blocking read of the next available message + dbus_connection_read_write(pInfo->pConn, 0); + DBusMessage *pMsg = dbus_connection_pop_message(pInfo->pConn); + + if (NULL == pMsg) { + sleep(TSC_READ_WRITE_DISPATCH_SLEEP_SECONDS); + continue; + } + else + { + // TODO: Strangely, first message needs to be processed, for the next N pending msgs + // to be picked up for asynchronous processing. + IpcHandles *pIpcHandle = IpcThrPoolGet(pInfo->pHandlePool); + IpcAsyncInfo *pAsync = calloc(1, sizeof(IpcAsyncInfo)); + if (pAsync != NULL) + { + pAsync->pConn = pInfo->pConn; + pAsync->pInfo = pInfo; + pAsync->pMsg = pMsg; + pAsync->argc = 0; + pAsync->argv = NULL; + pAsync->pHandle = pIpcHandle; + + iRet = _ParseDBusMessage(pMsg, &(pAsync->argc), &(pAsync->argv)); + + if (iRet == 0) + { + iRet = snprintf(pAsync->async_unique_id, MSGHANDLE_LEN, TSC_MID_SVR_FORMAT, pAsync->argv[0], + dbus_message_get_serial(pAsync->pMsg)); + //DDBG("ASYNC_UNQIEU-DI: %s\n", pAsync->async_unique_id); + if (iRet < 0) + break; + + iRet = _RunDetachedThread(_IpcServerMsgHandler, pAsync); + DDBG("====RunDetachedThread ret:%d\n", iRet); + } + + if (iRet) + { + IpcThrPoolPut(pInfo->pHandlePool, pIpcHandle); + CleanupAsync(pAsync); + } + + } + } + } + DDBG("popmessage ended :%s\n", "============"); + + return NULL; +} + + +void CleanupArray(char*** pArr, int len) +{ + if (pArr) { + while (len > 0) + { + len--; + free ((*pArr)[len]); + (*pArr)[len] = NULL; + } + free(*pArr); + *pArr = NULL; + } +} + +void CleanupAsync(IpcAsyncInfo *pAsync) +{ + if (pAsync) + { + CleanupArray(&(pAsync->argv), pAsync->argc); + if (pAsync->pMsg) + dbus_message_unref(pAsync->pMsg); + + if (pAsync) + free(pAsync); + pAsync = NULL; + + } +} + +/*** + * reason_params is cleaned up within this method + */ +int IpcServerCallbackMethod(TSC_METHOD_HANDLE *pMHandle, TSC_METHOD_REASON_CODE iReason, void *reason_params) +{ + IpcMethodHandle *p_MHandle = (IpcMethodHandle *) pMHandle; + char *data = reason_params; + int iRet = -1; + + if (iReason == TSC_CANCEL) + { + pthread_mutex_lock(&(p_MHandle->Lock)); + if (p_MHandle->iCancel == TSC_IS_CANCEL) + { + iRet = 0; + DDBG("%s", "callback check, it is cancel true\n"); + } + pthread_mutex_unlock(&(p_MHandle->Lock)); + } + else if (iReason == TSC_PROGRESS) + { + pthread_mutex_lock(&(p_MHandle->Lock)); + p_MHandle->cStatus = strdup(data); // TODO: any better way to update data? + iRet = 0; + pthread_mutex_unlock(&(p_MHandle->Lock)); + + if (data) + free(data); + data = NULL; + } + return iRet; +} + +/*void IpcCancelMethod(TSC_SERVER_HANDLE hServer, char *method_unique_id)*/ +int IpcCancelMethod(void *pData, int argc, char **argv, char ***szReply, int *len, CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle) +{ + + int ret = 0; + if (argc > 0) + { + DDBG("IpcCancelMethod unique_id %s\n", argv[0]); + } + else + { + DDBG("%s\n", "Error params in cancel method"); + } + + //TODO :error checking + IpcMethodHandle *pMHandle = (IpcMethodHandle*) handle; + IpcServerInfo *pInfo = (IpcServerInfo*) pMHandle->pInfo; + // Get the running method by the method_unique_id, then set its cancel flag + IpcMethodHandle **pmpPrev; + + if (argc != 1) + { + //the argc should be 2, the second param is unique id of to cancel method + ret = -1; + } + pthread_mutex_lock(&(pInfo->Lock)); + + for (pmpPrev = &(pInfo->pRunningMethods); *pmpPrev; pmpPrev = &((*pmpPrev)->pNext)) + { + DDBG("Method to cancel: %s, list method:%s\n", argv[0], (*pmpPrev)->unique_id); + if (strcmp((*pmpPrev)->unique_id, argv[0]) == 0) + { + DDBG("%s\n", "found the running method to cancel"); + pthread_mutex_lock(&(pMHandle->Lock)); + (*pmpPrev)->iCancel = TSC_IS_CANCEL; + DDBG("%s %s\n", "set is cancel to true for this method: ", (*pmpPrev)->unique_id); + //TODO: should we return something? + *len = 1; + *szReply = calloc(1, sizeof(char*) *(*len)); + (*szReply)[0] = strdup("0"); + pthread_mutex_unlock(&(pMHandle->Lock)); + break; + } + } + pthread_mutex_unlock(&(pInfo->Lock)); + + DDBG("%s\n", "END OF cancel method"); + return ret; +} + + + +int +IpcGetProgressMethod(void *pData, int argc, char **argv, char ***szReply, int *len, CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle) +{ + DDBG("%s\n", "IpcGetProgressMethod"); + IpcMethodHandle *pMHandle = (IpcMethodHandle*) handle; + IpcServerInfo *pInfo = (IpcServerInfo*) pMHandle->pInfo; + + //TODO: Error handling, check argv argc + //Here the running method finished, either end or cancelled. + IpcMethodHandle **pmpPrev; + for (pmpPrev = &(pInfo->pRunningMethods); *pmpPrev; pmpPrev = &((*pmpPrev)->pNext)) + { + DDBG("running methods unique id :%s, passing id :%s \n", (*pmpPrev)->unique_id, argv[0]); + + if (!strcmp((*pmpPrev)->unique_id, argv[0])) + { + DDBG("=== found running method to get progress %s\n", argv[0]); + // get the running method, update its status + *len = 1; + *szReply = calloc(1, sizeof(char*) * 10); + DDBG("-- status to reply :%s\n",(*pmpPrev)->cStatus); + (*szReply)[0] = strdup((*pmpPrev)->cStatus); + break; + } + } + return 0; +} + +int +IpcShutdown(void *pData, int argc, char **argv, char ***szReply, int *len, CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle) +{ + DDBG("==============%s\n", "IpcShutdownMethod"); + IpcMethodHandle *pMHandle = (IpcMethodHandle*) handle; + IpcServerInfo *pInfo = (IpcServerInfo*) pMHandle->pInfo; + + pthread_mutex_lock(&(pInfo->Lock)); + pInfo->start_server_flag = false; + pthread_mutex_unlock(&(pInfo->Lock)); + DDBG("end of shutdown:%s\n", "==================="); + return 0; +} + + +void FreeIpcServerHandle(TSC_SERVER_HANDLE hServer) +{ + DDBG("%s\n", "FreeIpcServerHandle"); + IpcServerInfo *pInfo = (IpcServerInfo*) hServer; + + if (pInfo) + { + pthread_mutex_lock(&(pInfo->Lock)); + // Free MethodList + IpcServerMethodList *pCurr = pInfo->pMethodList; + IpcServerMethodList *pPrev; + + while (pCurr) + { + pPrev = pCurr; + pCurr = pCurr->pNext; + DDBG("*****pPrev method is 0 :%s\n", pPrev->pMethod->szMethod); + + if (pPrev) + { + if (pPrev->pMethod) + { + if (pPrev->pMethod->method == (METHODFUNC) IpcCancelMethod + || pPrev->pMethod->method == (METHODFUNC) IpcGetProgressMethod + || pPrev->pMethod->method == (METHODFUNC) IpcShutdown) + { + free(pPrev->pMethod); + } + pPrev->pMethod = NULL; + } + if (pPrev->pNext) + { + pPrev->pNext = NULL; + } + + free(pPrev); + pPrev = NULL; + } + } + + pInfo->pMethodList = NULL; + pInfo->pRunningMethods = NULL; + + if (pInfo->pHandlePool) + IpcThrPoolFree(&pInfo->pHandlePool); + + pthread_mutex_unlock(&(pInfo->Lock)); + + pthread_mutex_destroy(&(pInfo->Lock)); + + if (pInfo->pTable) + free(pInfo->pTable); + pInfo->pTable = NULL; + + if (pInfo->pConn) + { + DBusError dberr; + dbus_error_init(&dberr); + + dbus_connection_remove_filter(pInfo->pConn, _IpcServerMsgFilter, pInfo); + dbus_connection_unregister_object_path(pInfo->pConn, TSC_DBUS_PATH); + dbus_bus_remove_match(pInfo->pConn, pInfo->rule, &dberr); + + dbus_bus_release_name(pInfo->pConn, TSC_DBUS_SERVER, &dberr); + + dbus_connection_unref(pInfo->pConn); + dbus_error_free(&dberr); + } + pInfo->pConn = NULL; + + free(pInfo); + pInfo = NULL; + } +} + + + +/** + * Creates a thread for asynchronous task. + * TODO: Merge with TCS module. + */ +int _RunDetachedThread(void *pfWorkerFunc, void *pThreadData) +{ + pthread_t thread; + pthread_attr_t attr; + + int rc = -1; + do + { + if (pthread_attr_init(&attr) != 0) + break; + + if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) + break; + + + if (pthread_create(&thread, &attr, pfWorkerFunc, pThreadData) != 0) + break; + + if (pthread_attr_destroy(&attr) != 0) + { + // As the thread is already running, return different error code. + rc = -2; + break; + } + + rc = 0; + } + while (0); + return rc; +} + diff --git a/framework/IpcServer.h b/framework/IpcServer.h new file mode 100644 index 0000000..d187700 --- /dev/null +++ b/framework/IpcServer.h @@ -0,0 +1,170 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef IPCSERVER_H +#define IPCSERVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file IpcServer.h + * \brief Ipc Server Header File + * + * This file provides the IPC Server API functions used by Security framework. + */ + +#include +#include +#include "IpcMacros.h" + + +/*================================================================================================== + STRUCTURES AND OTHER TYPEDEFS +==================================================================================================*/ + +/** + * Pointer to method requested by client module. + */ +/*typedef int (*CALLBACKFUNC) (void *pHandle, TSC_METHOD_REASON_CODE iReason, void *user_data);*/ +typedef int (*CALLBACKFUNC) (void *pHandle, int iReason, void *reason_params); + +typedef int (*METHODFUNC) (void *pData, int argc, char **argv, char ***szReply, int *len, CALLBACKFUNC callback, void *pHandle); + +/** + * Server side method to handle request from client module. All the requests + * are managed in a list. + */ +typedef struct _IpcServerMethod +{ + char szMethod[TSC_METHOD_NAME_LEN]; + METHODFUNC method; + void *pData; //when execute the method, the pData besides the data passed from client, also has methodHandle for this method +} IpcServerMethod; + +#define TSC_NULL ((void *) 0) + +#define TSCSERVERHANDLE(n) struct n##_struct {int iDummy;}; typedef struct n##_struct *n +TSCSERVERHANDLE(TSC_SERVER_HANDLE); + +#define TSCMETHODHANDLE(n) struct n##_struct {int iDummy;}; typedef struct n##_struct *n +TSCMETHODHANDLE(TSC_METHOD_HANDLE); + +#define INVALID_TSC_METHOD_HANDLE ((TSC_METHOD_HANDLE) TSC_NULL) + +#define INVALID_TSC_SERVER_HANDLE ((TSC_SERVER_HANDLE) TSC_NULL) + +/*================================================================================================== + FUNCTION PROTOTYPES +==================================================================================================*/ + +/** + * \brief Adds a handler method to the list of methods at server, to process + * request from the client. + * + * During initialisation, the server builds a list of handlers to process + * request coming from client-side IPC. Later the client side IPC sends request + * along with the name of the handler to use. The handlers are implemented + * in the module hosting the server-side IPC. + * + * This is a synchronous API. + * + * \param[in] pMethod Details of the handler method to be added at server-side. + * + * \return Return Type (void) \n + * + */ +int IpcServerAddMethod(TSC_SERVER_HANDLE hServer, IpcServerMethod *pMethod); + +/** + * \brief Removes a handler method from the list of methods at server. + * + * During initialisation, the server builds a list of handlers to process + * request coming from client-side IPC. Later the client side IPC sends request + * along with the name of the handler to use. The handlers are implemented + * in the module hosting the server-side IPC. As part of un-initialisation + * the handler should be removed from the list. + * + * This is a synchronous API. + * + * \param[in] pMethod Pointer to handler method to be removed. + * + * \return Return Type (void) \n + * + */ +int IpcServerRemoveMethod(TSC_SERVER_HANDLE hServer, METHODFUNC pMethod); + + +/* +void IpcCancelMethod(TSC_SERVER_HANDLE hServer, char *method_unique_id); +char *IpcGetProgressMethod(TSC_SERVER_HANDLE hServer, char *method_unique_id); +*/ +/** + * \brief Initialises the server-side IPC to make it ready for request from + * client side IPC. + * + * The IPC has two parts - client and server. The server-side IPC processes the + * request sent from the client-side IPC. The server-side uses handlers provided + * by the hosting module. When server comes up, the IPC needs to be initialised + * and be ready for the requests. + * + * This is a synchronous API. + * + * \return Return Type (int) \n + * 0 - on send success. \n + * -1 - on send failure. \n + */ +TSC_SERVER_HANDLE IpcServerOpen(char *servie_name); + +/** + * \brief Close the server-side IPC and release the resources. + * + * This is a synchronous API. + * + * \return Return Type (void) \n + */ +void IpcServerClose(TSC_SERVER_HANDLE*); + +int IpcServerMainLoop(TSC_SERVER_HANDLE hServer); + +/** + * Callback function for Server Stub in cancel the method, update method progress + */ + + + +#ifdef __cplusplus +} +#endif + +#endif /* IPCSERVER_H */ + diff --git a/framework/IpcServerError.c b/framework/IpcServerError.c new file mode 100644 index 0000000..cdcb069 --- /dev/null +++ b/framework/IpcServerError.c @@ -0,0 +1,89 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file IpcServerError.c + * \brief Ipc server-side error handling File + * + * This file contains the server-side exception handling, used by Security framework. + */ + +#include "IpcMacros.h" +#include "IpcServerError.h" +#include "TSCErrorCodes.h" + +const char *GetErrorName(const int iErrCode) +{ + switch (iErrCode) + { + case TSC_ERROR_CANCELLED: + return TSC_DBUS_INTERFACE ERR_NAME_CANCELLED; + case TSC_ERROR_DATA_ACCESS: + return TSC_DBUS_INTERFACE ERR_NAME_DATA_ACCESS; + case TSC_ERROR_INVALID_PARAM: + return TSC_DBUS_INTERFACE ERR_NAME_INVALID_PARAM; + case TSC_ERROR_INSUFFICIENT_RES: + return TSC_DBUS_INTERFACE ERR_NAME_INSUFFICIENT_RES; + case TSC_ERROR_INTERNAL: + return TSC_DBUS_INTERFACE ERR_NAME_INTERNAL; + case TSC_ERROR_INVALID_HANDLE: + return TSC_DBUS_INTERFACE ERR_NAME_INVALID_HANDLE; + case TSC_ERROR_NOT_IMPLEMENTED: + return TSC_DBUS_INTERFACE ERR_NAME_NOT_IMPLEMENTED; + } + + /* default: TSC_ERROR_MODULE_GENERIC */ + return TSC_DBUS_INTERFACE ERR_NAME_MODULE_GENERIC; +} + +const char *GetErrorDescription(const int iErrCode) +{ + switch (iErrCode) + { + case TSC_ERROR_CANCELLED: + return ERR_DESC_CANCELLED; + case TSC_ERROR_DATA_ACCESS: + return ERR_DESC_DATA_ACCESS; + case TSC_ERROR_INVALID_PARAM: + return ERR_DESC_INVALID_PARAM; + case TSC_ERROR_INSUFFICIENT_RES: + return ERR_DESC_INSUFFICIENT_RES; + case TSC_ERROR_INTERNAL: + return ERR_DESC_INTERNAL; + case TSC_ERROR_INVALID_HANDLE: + return ERR_DESC_INVALID_HANDLE; + case TSC_ERROR_NOT_IMPLEMENTED: + return ERR_DESC_NOT_IMPLEMENTED; + } + + /* default: TSC_ERROR_MODULE_GENERIC */ + return ERR_DESC_MODULE_GENERIC; +} diff --git a/framework/IpcServerError.h b/framework/IpcServerError.h new file mode 100644 index 0000000..e45a450 --- /dev/null +++ b/framework/IpcServerError.h @@ -0,0 +1,53 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef IPCSERVERERROR_H +#define IPCSERVERERROR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file IpcServerError.h + * \brief Ipc server-side error Header File + * + * This file contains the server-side error code details, used by Security framework. + */ + +const char *GetErrorName(const int iErrCode); +const char *GetErrorDescription(const int iErrCode); + +#ifdef __cplusplus +} +#endif + +#endif /* IPCSERVERERROR_H */ diff --git a/framework/IpcServerHdr.h b/framework/IpcServerHdr.h new file mode 100644 index 0000000..d48d4d2 --- /dev/null +++ b/framework/IpcServerHdr.h @@ -0,0 +1,143 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef IPCSERVERHDR_H +#define IPCSERVERHDR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "IpcServer.h" +#include "IpcThrdPool.h" + +#define SAFE_FREE(x) if (x) {free(x); x = NULL;} +#define FREE(x) if (x) {free(x);} + +/** + * Forward Declarations. + */ +/*struct IpcServerInfo;*/ +typedef struct _IpcServerInfo IpcServerInfo; + +/** + * Keep registered methods list + */ +typedef struct _IpcServerMethodList +{ + IpcServerMethod *pMethod; + struct _IpcServerMethodList *pNext; +} IpcServerMethodList; + +/** + * Keep the context for callback passed to stub method + */ +typedef struct _IpcMethodHandle +{ + IpcServerMethod *pMethod; + void *pData; + IpcServerInfo *pInfo; + char unique_id[MSGHANDLE_LEN + 1]; //uniquely identify the running method + int iCancel; // 1 is cancel, 0 not cancel + char *cStatus; // any status + pthread_mutex_t Lock; + + struct _IpcMethodHandle *pNext; +} IpcMethodHandle; + +/** + * Single context per server connection. + */ +struct _IpcServerInfo +{ + char name[TSC_SERVER_NAME_LEN + 1]; + DBusConnection *pConn; + IpcServerMethodList *pMethodList; // available methods list + char rule[TSC_INFO_RULE_LEN]; + int fd; + bool start_server_flag; + DBusObjectPathVTable *pTable; //TODO: it is core dump if new thread the running method through pTable registered list + pthread_t lDbus_listen_thread; //listen thread on the socket for reading message + IpcHandlePool *pHandlePool; // thread pool for the running methods + int count; + IpcMethodHandle *pRunningMethods; // current running methods + pthread_mutex_t Lock; // mutex to manage methods - iteration, add, remove. +}; + + +/** + * Copy the data from the message read from the listening/reading socket thread, and pass it to the reply thread, where executing the method + */ +typedef struct _IpcAsyncInfo +{ + DBusConnection *pConn; + IpcServerInfo *pInfo; + DBusMessage *pMsg; + int argc; + char **argv; + IpcServerMethod *pMethod; + IpcHandles *pHandle; + char async_unique_id[MSGHANDLE_LEN + 1]; //uniquely identify the running method +} IpcAsyncInfo; + +int _IpcServerInit(IpcServerInfo *pServerInfo, char *szServiceName); +void _IpcServerDeInit(TSC_SERVER_HANDLE hServer); +DBusHandlerResult _IpcServerReplyMessage(DBusConnection *pConn, DBusMessage *pMsg, + char **pReply, int size); +DBusHandlerResult _IpcServerMsgFilter(DBusConnection *pConn, DBusMessage *pMsg, void *pData); +int _ParseDBusMessage(DBusMessage *pMsg, int *argc, char ***argv); +DBusHandlerResult _IpcServerMsgHandler(void *data); +DBusHandlerResult _IpcServerProcessMessage(void *data); +void *_IpcPopMessage(void *hServer); +void CleanupArray(char*** pArr, int len); +void CleanupAsync(IpcAsyncInfo *pAsync); +void FreeIpcServerHandle(TSC_SERVER_HANDLE hServer); +DBusHandlerResult _IpcServerReplyError(DBusConnection *pConn, DBusMessage *pMsg, + int iErrCode); +int IpcCancelMethod(void *pData, int argc, char **argv, char ***szReply, int *len, CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle); +int IpcGetProgressMethod(void *pData, int argc, char **argv, char ***szReply, int *len, CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle); +int IpcShutdown(void *pData, int argc, char **argv, char ***szReply, int *len, CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle); +int IpcServerCallbackMethod(TSC_METHOD_HANDLE *pMHandle, TSC_METHOD_REASON_CODE iReason, void *reason_params); +int _RunDetachedThread(void *pfWorkerFunc, void *pThreadData); + + +void _FreeHandleMethods(IpcServerInfo *pServerInfo); +void _FreeHandlePool(IpcServerInfo *pServerInfo); +void _FreeHandleTable(IpcServerInfo *pServerInfo); +void _FreeHandleConn(IpcServerInfo *pServerInfo); +void _WaitForListenThreadClose(IpcServerInfo *pServerInfo); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/framework/IpcStructs.c b/framework/IpcStructs.c new file mode 100644 index 0000000..1d73751 --- /dev/null +++ b/framework/IpcStructs.c @@ -0,0 +1,185 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file IpcStructs.c + * \brief Source File for structures needed by Ipc. + * + * This file implements the structures needed by IPC Client, used by Security framework. + */ + +#include +#include +#include + +#include "IpcStructs.h" + +/** + * Assign new fields to existing call handle. + * A NULL pPendingCall will not replace the existing one. + */ +int _AssignToClientCallHandle(ClientCallHandle *pHandle, const char *szPrefix, dbus_uint32_t serial, + DBusPendingCall *pPendingCall) +{ + int iRet = 1; + + do + { + if (!pHandle) + break; + + if (0 > (iRet = snprintf(pHandle->idUnique, MSGHANDLE_LEN, TSC_MID_SVR_FORMAT, szPrefix, + serial))) + break; + + if (pPendingCall) + pHandle->pPendingCall = pPendingCall; + + iRet = 0; + + } while(0); + + return iRet; +} + +int _CreateClientCallHandle(ClientCallHandle **ppHandle, const char *szPrefix, dbus_uint32_t serial, + DBusPendingCall *pPendingCall) +{ + int iRet = 1; + ClientCallHandle *pHandle = NULL; + + do + { + if (!ppHandle) + break; + + pHandle = (ClientCallHandle *) malloc(sizeof(ClientCallHandle)); + if (!pHandle) + break; + + if ((iRet = _AssignToClientCallHandle(pHandle, szPrefix, serial, pPendingCall))) + break; + + *ppHandle = pHandle; + iRet = 0; + + } while(0); + + if (iRet && pHandle) + { + free(pHandle); + pHandle = NULL; + } + + return iRet; +} + +void _FreeClientCallHandle(ClientCallHandle *pHandle) +{ + free(pHandle); +} + +void _FreeSharedData(SharedData *pSharedData) +{ + if (pSharedData) + { + pthread_mutex_destroy(&pSharedData->lock); + pthread_cond_destroy(&pSharedData->cond); + free(pSharedData); + } +} + +// Create the handle to monitor send completion and receive sent message details. +// Maintains only reference of DBusMessage; Ownership is not changed. +SharedData *_CreateSharedData(const char *szCallHandlePrefix, DBusMessage *pMsg) +{ + int iDone = 0; + SharedData *pSharedData = NULL; + + do + { + if (!pMsg) + break; + + if ((pSharedData = (SharedData *)calloc(1, sizeof(SharedData))) == NULL) + break; + + if (0 > snprintf(pSharedData->szCallHandlePrefix, MSGHANDLE_LEN, "%s", szCallHandlePrefix)) + break; + + pSharedData->pMsg = pMsg; + pSharedData->pCallHandle = NULL; + pSharedData->iSent = 0; + + if (pthread_mutex_init(&(pSharedData->lock), NULL)) + break; + + if (pthread_cond_init(&(pSharedData->cond), NULL)) + break; + + iDone = 1; + } while(0); + + if (!iDone) + { + _FreeSharedData(pSharedData); + return NULL; + } + return pSharedData; +} + +ThreadData *_AllocThreadData(DBusConnection *pConn, int timeout_milliseconds, + SharedData *pSharedData, TSCCallback pCallback, void *pPrivate) +{ + ThreadData *pThreadData = (ThreadData *)dbus_malloc(sizeof(ThreadData)); + if (!pThreadData) + return NULL; + + pThreadData->pConn = pConn; + pThreadData->timeout_milliseconds = timeout_milliseconds; + pThreadData->pSharedData = pSharedData; + pThreadData->pCallBack = pCallback; + pThreadData->pPrivate = pPrivate; + + return pThreadData; +} + +void _FreeThreadData(void *pThreadData) +{ + if (pThreadData) + { + _FreeSharedData(((ThreadData*)pThreadData)->pSharedData); + } + dbus_free(pThreadData); +} + + +#include "IpcStructs.h" diff --git a/framework/IpcStructs.h b/framework/IpcStructs.h new file mode 100644 index 0000000..d312a24 --- /dev/null +++ b/framework/IpcStructs.h @@ -0,0 +1,139 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef IPCSTRUCTS_H +#define IPCSTRUCTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file IpcStructs.h + * \brief Header File for structures by Ipc. + * + * This file implements the structures needed by IPC Client, used by Security framework. + */ + +#include +#include + +#include "IpcMacros.h" +#include "IpcTypes.h" + +/*================================================================================================== + STRUCTURES AND OTHER TYPEDEFS +==================================================================================================*/ + +/** + * Handle for message sent, to be used for future reference. + */ +typedef struct _ClientCallHandle +{ + char idUnique[MSGHANDLE_LEN]; + DBusPendingCall *pPendingCall; + char service_name[TSC_SERVER_NAME_LEN + 1]; +} ClientCallHandle; + +/** + * IPC client connection info. + */ +typedef struct _IpcClientInfo +{ + DBusConnection *dbconn; + char req_name[TSC_REQ_STR_LEN]; + char pid[TSC_REQ_STR_LEN]; +} IpcClientInfo; + +/** + * Data shared between the synchronized thread. It wraps the asynchronous call handle. + */ +typedef struct _SharedData +{ + int iSent; + ClientCallHandle *pCallHandle; + char szCallHandlePrefix[MSGHANDLE_LEN]; + DBusMessage *pMsg; + pthread_mutex_t lock; + pthread_cond_t cond; +} SharedData; + +/** + * Data passed to threads sending messages asynchronously. + * Owns only SharedData, rest are owned by 'parent thread'. + */ +typedef struct _ThreadData +{ + DBusConnection *pConn; + int timeout_milliseconds; + SharedData *pSharedData; + TSCCallback pCallBack; + void *pPrivate; +} ThreadData; + +/*================================================================================================== + FUNCTION PROTOTYPES +==================================================================================================*/ + +/** + * _ClientCallHandle related. + */ +int _AssignToClientCallHandle(ClientCallHandle *pHandle, const char *szPrefix, dbus_uint32_t serial, + DBusPendingCall *pPendingCall); + +int _CreateClientCallHandle(ClientCallHandle **ppHandle, const char *szPrefix, dbus_uint32_t serial, + DBusPendingCall *pPendingCall); + +void _FreeClientCallHandle(ClientCallHandle *pHandle); + +/** + * SharedData related. + */ +void _FreeSharedData(SharedData *pSharedData); + +// Create the handle to monitor send completion and receive sent message details. +// Maintains only reference of DBusMessage; Ownership is not changed. +SharedData *_CreateSharedData(const char *szCallHandlePrefix, DBusMessage *pMsg); + +/** + * ThreadData related. + */ +ThreadData *_AllocThreadData(DBusConnection *pConn, int timeout_milliseconds, + SharedData *pSharedData, TSCCallback pCallback, void *pPrivate); + +void _FreeThreadData(void *pThreadData); + +#ifdef __cplusplus +} +#endif + +#endif /* IPCSTRUCTS_H */ + diff --git a/framework/IpcThrdPool.c b/framework/IpcThrdPool.c new file mode 100644 index 0000000..253b638 --- /dev/null +++ b/framework/IpcThrdPool.c @@ -0,0 +1,173 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file IpcThrdPool.c + * \brief Ipc Thread pool Ipc Source File + * + * This file implements the thread pool used by IPC Server in Security framework. + */ + +#include +#include +#include +#include +#include "Debug.h" +#include "IpcThrdPool.h" + +static void IpcThrPoolReset(IpcHandlePool *pHPool) +{ + IpcHandles *pHandle; + + if (!pHPool) + return; + + while ((pHandle = pHPool->pHList) != NULL) + { + pHPool->pHList = pHPool->pHList->pNext; + free(pHandle); + } + + pthread_cond_destroy(&pHPool->Cond); + pthread_mutex_destroy(&pHPool->Lock); + pHPool->iIdleCount = 0; +} + +/** + * Frees the resources and nullifies the thread pool object. + */ +void IpcThrPoolFree(IpcHandlePool **pHPool) +{ + IpcThrPoolReset(*pHPool); + free(*pHPool); + *pHPool = NULL; +} + +/** + * Creates a new handle and makes it head of the pool list. + * Return 0 on success and -1 on failure. + */ +static int AddHandleToThrPool(IpcHandlePool *pHPool) +{ + IpcHandles *pHandle = NULL; + if ((pHandle = (IpcHandles *) calloc(1, sizeof(IpcHandles))) == NULL) + { + DDBG("%s\n", "calloc IpcHandles"); + return -1; + } + + + pHandle->pNext = pHPool->pHList; + pHPool->pHList = pHandle; + return 0; +} + +/** + * Initializes thread pool. Returns 0 on success and -1 on failure. + */ +int IpcThrPoolInit(IpcHandlePool *pHPool, int iNumHandles) +{ + int i; + int result = 0; + + if (!pHPool) + return -1; + + if (pthread_mutex_init(&pHPool->Lock, NULL)) + { + DDBG("%s\n", "mutex init"); + return -1; + } + + + if (pthread_cond_init(&pHPool->Cond, NULL)) + { + pthread_mutex_destroy(&pHPool->Lock); + DDBG("%s\n", "cond_init"); + return -1; + } + + pHPool->iIdleCount = iNumHandles; + pHPool->pHList = NULL; + + for (i = 0; i < iNumHandles; i++) + { + if (0 != AddHandleToThrPool(pHPool)) + { + DDBG("%s\n", "add to thrpool"); + result = -1; + break; + } + } + + return result; +} + +/** + * Synchronized method to returns a thread handle from the pool. The method is blocked till a + * handle is available. + */ +IpcHandles *IpcThrPoolGet(IpcHandlePool *pHPool) +{ + IpcHandles *pHandle; + pthread_mutex_lock(&pHPool->Lock); + while ((pHandle = pHPool->pHList) == NULL) + { + pthread_cond_wait(&pHPool->Cond, &pHPool->Lock); + } + pHPool->pHList = pHandle->pNext; + (pHPool->iIdleCount)--; + pthread_mutex_unlock(&pHPool->Lock); + + return pHandle; +} + +void IpcThrPoolPut(IpcHandlePool *pHPool, IpcHandles *pHandle) +{ + pthread_mutex_lock(&pHPool->Lock); + pHandle->pNext = pHPool->pHList; + pHPool->pHList = pHandle; + (pHPool->iIdleCount)++; + + pthread_cond_broadcast(&pHPool->Cond); + pthread_mutex_unlock(&pHPool->Lock); +} + +/** + * Returns number of handles available in thread pool. + * Returns -1 when pool is invalid. + */ +int IpcThrPoolIdleCount(IpcHandlePool *pHPool) +{ + + return pHPool? pHPool->iIdleCount : -1; +} + diff --git a/framework/IpcThrdPool.h b/framework/IpcThrdPool.h new file mode 100644 index 0000000..2e98f2c --- /dev/null +++ b/framework/IpcThrdPool.h @@ -0,0 +1,95 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _IPCTHRDPOOL_H +#define _IPCTHRDPOOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "IpcServer.h" + +/** + * + */ +typedef struct IpcHandles_struct +{ + struct IpcHandles_struct *pNext; + void *pMethodHandle; + void *pData; +} IpcHandles; + +/** + * + */ +typedef struct IpcHandlePool_struct +{ + IpcHandles *pHList; + pthread_mutex_t Lock; + pthread_cond_t Cond; + int iIdleCount; +} IpcHandlePool; + +/** + * Initializes thread pool. Returns 0 on success and -1 on failure. + */ +int IpcThrPoolInit(IpcHandlePool *pHPool, int iNumHandles); + +/** + * Frees the resources and nullifies the thread pool object. + */ +void IpcThrPoolFree(IpcHandlePool **pHPool); + +/** + * Synchronized method to returns a thread handle from the pool. The method is blocked till a + * handle is available. + */ +IpcHandles *IpcThrPoolGet(IpcHandlePool *pHPool); + +/** + * + */ +void IpcThrPoolPut(IpcHandlePool *pHPool, IpcHandles *pHandle); + +/** + * Returns number of handles available in thread pool. + * Returns -1 when pool is invalid. + */ +int IpcThrPoolIdleCount(IpcHandlePool *pHPool); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/framework/IpcTypes.h b/framework/IpcTypes.h new file mode 100644 index 0000000..296c03b --- /dev/null +++ b/framework/IpcTypes.h @@ -0,0 +1,72 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef IPCTYPES_H +#define IPCTYPES_H + +/** + * \file IpcTypes.h + * \brief Data types and structs for Security framework IPC clients. + * + * This file provides the data types and structs needed by clients of Security framework IPC. + */ + +/*================================================================================================== + STRUCTURES AND OTHER TYPEDEFS +==================================================================================================*/ + +/** + * \brief CallBack Function type for Async method supported by the IPC. + * + * \param[in] pPrivate API caller's context information, supplied with TSCSendMessageAsync earlier. + * \param[in] argc Length of the string in argv. + * \param[in] argv Array of strings representing result value of asynchronous reply. + */ +typedef void (*TSCCallback)(void *pPrivate, int argc, const char **argv); + +/** + * Client side IPC handles. + */ +#define TSCHANDLE(n) struct n##_struct { int iDummy; }; typedef struct n##_struct *n + +/** + * IPC client handle. + */ +TSCHANDLE(TSC_IPC_HANDLE); +#define INVALID_IPC_HANDLE ((TSC_IPC_HANDLE) NULL) + +/** + * Asynchronous call handle. + */ +TSCHANDLE(TSC_CALL_HANDLE); + +#endif /* IPCTYPES_H */ + diff --git a/framework/Makefile_TPCSSerDaemon b/framework/Makefile_TPCSSerDaemon new file mode 100644 index 0000000..47614bf --- /dev/null +++ b/framework/Makefile_TPCSSerDaemon @@ -0,0 +1,103 @@ +# +# Copyright (c) 2014, McAfee, Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# Neither the name of McAfee, Inc. nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# + +OUTDIR = bin +TARGET = $(OUTDIR)/TPCSSerDaemon +SRCDIR = . +LD_FLAGS := $(LD_FLAGS) -ldl $(shell pkg-config --libs libtzplatform-config) + +ifeq ($(TCS_CC), ) + CC = gcc +else + CC = $(TCS_CC) +endif +ifeq ($(TCS_LD), ) + LD = ld +else + LD = $(TCS_LD) +endif +ifeq ($(TCS_AR), ) + AR = ar +else + AR = $(TCS_AR) +endif +ifeq ($(TCS_STRIP), ) + STRIP = strip +else + STRIP = $(TCS_STRIP) +endif + +ifeq ($(TCS_CFG), release) + CFLAGS := -O3 -fPIE -DUNIX $(CFLAGS) +else + CFLAGS := -g -fPIE -DUNIX -DDEBUG $(CFLAGS) +endif + +# Define a list of pkg-config packages we want to use +pkg_packages = dbus-glib-1 dlog + +PKG_CFLAGS = $(shell pkg-config --cflags $(pkg_packages)) +PKG_LDFLAGS = $(shell pkg-config --libs $(pkg_packages)) + +# Combine user supplied, additional, and pkg-config flags +LD_FLAGS += $(PKG_LDFLAGS) -lscserver -L./lib -lxml2 + +GBS_CFLAGS = -I${SYSROOT}/usr/include/dbus-1.0 -I${SYSROOT}/usr/lib/dbus-1.0/include -I${SYSROOT}/usr/include/libxml2 +CFLAGS += -I$(SRCDIR) $(PKCL_CFLAGS) $(GBS_CFLAGS) $(PKG_CFLAGS) + +SOURCES = $(SRCDIR)/TPCSSerDaemon.c \ + $(SRCDIR)/IpcForkDaemon.c + +OBJECTS = $(OUTDIR)/TPCSSerDaemon.o \ + $(OUTDIR)/IpcForkDaemon.o + +$(OUTDIR)/%.o: $(SRCDIR)/%.c + $(CC) $(CFLAGS) -o $(OUTDIR)/$*.o -c $(SRCDIR)/$*.c + +all: $(OUTDIR) $(TARGET) + +$(TARGET): $(OBJECTS) + $(CC) -Wl,-zdefs -o $(TARGET) $(OBJECTS) $(LD_FLAGS) $(PKG_LDFLAGS) + +$(OUTDIR): + @mkdir $(OUTDIR) + +install: all + mkdir -p ${DESTDIR}/bin + cp ${TARGET} ${DESTDIR}/bin/ + +distclean: clean + @rm -rf $(OUTDIR) + +clean: + @rm -f $(TARGET) + @rm -f $(OBJECTS) *~ + @rm -f *.bb *.bbg *.da *.gcov diff --git a/framework/Makefile_TWPSerDaemon b/framework/Makefile_TWPSerDaemon new file mode 100644 index 0000000..14e36de --- /dev/null +++ b/framework/Makefile_TWPSerDaemon @@ -0,0 +1,106 @@ +# +# Copyright (c) 2014, McAfee, Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# Neither the name of McAfee, Inc. nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# + +OUTDIR = bin +TARGET = $(OUTDIR)/TWPSerDaemon +SRCDIR = . +INCLUDE = -I. $(TCS_INC) -I../plugin +LD_FLAGS := $(LD_FLAGS) -ldl -lpthread -lsecfw -lscserver -lm -Llib $(shell pkg-config --libs libtzplatform-config) + +ifeq ($(TCS_CC), ) + CC = gcc +else + CC = $(TCS_CC) +endif +ifeq ($(TCS_LD), ) + LD = ld +else + LD = $(TCS_LD) +endif +ifeq ($(TCS_AR), ) + AR = ar +else + AR = $(TCS_AR) +endif +ifeq ($(TCS_STRIP), ) + STRIP = strip +else + STRIP = $(TCS_STRIP) +endif + +ifeq ($(TCS_CFG), release) + CFLAGS := -O3 -fPIC $(INCLUDE) -DUNIX $(CFLAGS) +else + CFLAGS := -g -fPIC $(INCLUDE) -DUNIX -DDEBUG $(CFLAGS) +endif + +CFLAGS := $(CFLAGS) $(PKCL_CFLAGS) $(TCS_CFLAGS) + +SOURCES = $(SRCDIR)/TWPSerDaemon.c \ + $(SRCDIR)/IpcForkDaemon.c + +OBJECTS = $(OUTDIR)/TWPSerDaemon.o \ + $(OUTDIR)/IpcForkDaemon.o + +# Define a list of pkg-config packages we want to use +ifeq ($(TCS_CFG), release) + pkg_packages = dbus-glib-1 +else + pkg_packages = dbus-glib-1 dlog +endif + +PKG_CFLAGS = $(shell pkg-config --cflags $(pkg_packages)) +PKG_LDFLAGS = $(shell pkg-config --libs $(pkg_packages)) + +# Combine user supplied, additional, and pkg-config flags +PKGLD_FLAGS += $(PKG_LDFLAGS) -lscserver -L./lib + +GBS_CFLAGS = -I${SYSROOT}/usr/include/dbus-1.0 -I${SYSROOT}/usr/lib/dbus-1.0/include +PKGCFLAGS += -I$(SRCDIR) $(PKCL_CFLAGS) $(GBS_CFLAGS) $(PKG_CFLAGS) + +$(OUTDIR)/%.o: $(SRCDIR)/%.c + $(CC) $(CFLAGS) $(PKGCFLAGS) -I. -o $(OUTDIR)/$*.o -c $(SRCDIR)/$*.c + +all: $(OUTDIR) $(TARGET) + +$(TARGET): $(OBJECTS) + $(CC) -Wl,-zdefs -o $(TARGET) $(OBJECTS) $(LD_FLAGS) $(PKGLD_FLAGS) + +$(OUTDIR): + @mkdir $(OUTDIR) + +distclean: clean + @rm -rf $(OUTDIR) + +clean: + @rm -f $(TARGET) + @rm -f $(OBJECTS) *~ + @rm -f *.bb *.bbg *.da *.gcov diff --git a/framework/Makefile_channel_client b/framework/Makefile_channel_client new file mode 100644 index 0000000..a1ce28e --- /dev/null +++ b/framework/Makefile_channel_client @@ -0,0 +1,108 @@ +# +# Copyright (c) 2014, McAfee, Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# Neither the name of McAfee, Inc. nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# + +OUTDIR = lib +TARGET = $(OUTDIR)/libscclient.so +SRCDIR = . +LD_FLAGS := $(LD_FLAGS) -ldl -lpthread $(shell pkg-config --libs libtzplatform-config) + +ifeq ($(TCS_CC), ) + CC = gcc +else + CC = $(TCS_CC) +endif +ifeq ($(TCS_LD), ) + LD = ld +else + LD = $(TCS_LD) +endif +ifeq ($(TCS_AR), ) + AR = ar +else + AR = $(TCS_AR) +endif +ifeq ($(TCS_STRIP), ) + STRIP = strip +else + STRIP = $(TCS_STRIP) +endif + +ifeq ($(TCS_CFG), release) + CFLAGS := -O3 -fPIC -DUNIX $(CFLAGS) +else + CFLAGS := -g -fPIC -DUNIX -DDEBUG $(CFLAGS) +endif + +# Define a list of pkg-config packages we want to use + +ifeq ($(TCS_CFG), release) + pkg_packages = dbus-glib-1 +else + pkg_packages = dbus-glib-1 dlog +endif + +PKG_CFLAGS = $(shell pkg-config --cflags $(pkg_packages)) +PKG_LDFLAGS = $(shell pkg-config --libs $(pkg_packages)) + +# Combine user supplied, additional, and pkg-config flags +LD_FLAGS += $(PKG_LDFLAGS) + +GBS_CFLAGS = -I${SYSROOT}/usr/include/dbus-1.0 -I${SYSROOT}/usr/lib/dbus-1.0/include +CFLAGS += $(PKCL_CFLAGS) $(TCS_CFLAGS) $(GBS_CFLAGS) $(PKG_CFLAGS) + +SOURCES = $(SRCDIR)/IpcClient.c \ + $(SRCDIR)/IpcStructs.c + +OBJECTS = $(OUTDIR)/IpcClient.o \ + $(OUTDIR)/IpcStructs.o + +$(OUTDIR)/%.o: $(SRCDIR)/%.c + $(CC) $(CFLAGS) -o $(OUTDIR)/$*.o -c $(SRCDIR)/$*.c + +all: $(OUTDIR) $(TARGET) + +$(TARGET): $(OBJECTS) + $(CC) -shared -Wl,-zdefs -o $(TARGET) $(OBJECTS) $(LD_FLAGS) + +$(OUTDIR): + @mkdir $(OUTDIR) + +install: all + mkdir -p ${DESTDIR}/bin + cp ${TARGET} ${DESTDIR}/bin/ + +distclean: clean + @rm -rf $(OUTDIR) + +clean: + @rm -f $(TARGET) + @rm -f $(OBJECTS) *~ + @rm -f *.bb *.bbg *.da *.gcov diff --git a/framework/Makefile_channel_server b/framework/Makefile_channel_server new file mode 100644 index 0000000..e5b94c1 --- /dev/null +++ b/framework/Makefile_channel_server @@ -0,0 +1,109 @@ +# +# Copyright (c) 2014, McAfee, Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# Neither the name of McAfee, Inc. nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# + +OUTDIR = lib +TARGET = $(OUTDIR)/libscserver.so +SRCDIR = . +LD_FLAGS := $(LD_FLAGS) -ldl -lpthread $(shell pkg-config --libs libtzplatform-config) + +ifeq ($(TCS_CC), ) + CC = gcc +else + CC = $(TCS_CC) +endif +ifeq ($(TCS_LD), ) + LD = ld +else + LD = $(TCS_LD) +endif +ifeq ($(TCS_AR), ) + AR = ar +else + AR = $(TCS_AR) +endif +ifeq ($(TCS_STRIP), ) + STRIP = strip +else + STRIP = $(TCS_STRIP) +endif + +ifeq ($(TCS_CFG), release) + CFLAGS := -O3 -fPIC -DUNIX $(CFLAGS) +else + CFLAGS := -g -fPIC -DUNIX -DDEBUG $(CFLAGS) +endif + +# Define a list of pkg-config packages we want to use +ifeq ($(TCS_CFG), release) + pkg_packages = dbus-glib-1 +else + pkg_packages = dbus-glib-1 dlog +endif + +PKG_CFLAGS = $(shell pkg-config --cflags $(pkg_packages)) +PKG_LDFLAGS = $(shell pkg-config --libs $(pkg_packages)) + +# Combine user supplied, additional, and pkg-config flags +LD_FLAGS += $(PKG_LDFLAGS) + +GBS_CFLAGS = -I${SYSROOT}/usr/include/dbus-1.0 -I${SYSROOT}/usr/lib/dbus-1.0/include +CFLAGS += $(PKCL_CFLAGS) $(TCS_CFLAGS) $(GBS_CFLAGS) $(PKG_CFLAGS) + +SOURCES = $(SRCDIR)/IpcServer.c \ + $(SRCDIR)/IpcServerError.c \ + $(SRCDIR)/IpcThrdPool.c + +OBJECTS = $(OUTDIR)/IpcServer.o \ + $(OUTDIR)/IpcServerError.o \ + $(OUTDIR)/IpcThrdPool.o + +$(OUTDIR)/%.o: $(SRCDIR)/%.c + $(CC) $(CFLAGS) -o $(OUTDIR)/$*.o -c $(SRCDIR)/$*.c + +all: $(OUTDIR) $(TARGET) + +$(TARGET): $(OBJECTS) + $(CC) -shared -Wl,-zdefs -o $(TARGET) $(OBJECTS) $(LD_FLAGS) + +$(OUTDIR): + @mkdir $(OUTDIR) + +install: all + mkdir -p ${DESTDIR}/bin + cp ${TARGET} ${DESTDIR}/bin/ + +distclean: clean + @rm -rf $(OUTDIR) + +clean: + @rm -f $(TARGET) + @rm -f $(OBJECTS) *~ + @rm -f *.bb *.bbg *.da *.gcov diff --git a/framework/TPCSSerDaemon.c b/framework/TPCSSerDaemon.c new file mode 100644 index 0000000..fcb2687 --- /dev/null +++ b/framework/TPCSSerDaemon.c @@ -0,0 +1,1399 @@ +/** + * Methods supported in TPCS (Tizen Plugin Control Service) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Debug.h" +#include "IpcServer.h" +#include "IpcForkDaemon.h" +#include "TPCSSerDaemon.h" + +/** + * This daemon provides four services to manage plugins. + * InstallPlugin, UninstallPlugin, SetActivePlugin, GetInfoPlugin + * + * It maintains config.xml that has the plugin info. + * It will recover the config.xml if it is corrupted. + * + * During the services, the update config.xml and set up the symbolic link of the library is an + * atomic action. + * Daemon will store the config.xml in the buffer. When running each method, the buffer config.xml + * is copied to pData and being update inside the method. + * Except the GetInfoPlugin(), all other methods serializing when updating the config.xml. + */ + +/** + * Common Utils, TODO: move to Utils.c + * + */ + +typedef struct _ConfigBuf +{ + xmlDoc *pConfigBuffer; + pthread_mutex_t configLock; +} ConfigBuf; + +static void GetNSURI(xmlDoc *pXmlDoc, xmlChar **pns, xmlChar **uri); +static void GetConfigElements(xmlDoc **pXmlDoc, xmlChar *pXPath, int *size, char ***content); +static int WriteXmlToFile(xmlDoc *pXmlDoc, const char* filename); +static int UpdatePluglibList(const char *appPath, xmlDoc **pXmlDoc, const char *appId); +static int ActivePlugin(ConfigBuf *pBuf, xmlDoc **pXmlCp, const xmlChar *appId); +static void SetSuccessReturn(int *argc, char ***argv); +static void SetFailureReturn(int *argc, char ***argv); +static void CleanupArray(char*** pArr, int len); +static int EndsWith(char const *hay, char const *needle); + +/** + * Local functions declaration. + */ +static int HasTag(const char *pTag, const char *pFileName, const char *xpath); +int UpdateNode(const xmlChar* content, xmlDoc **pDoc, const xmlChar *xpathNodeParent, + const char* appID); + +static void SetReturn(int *res_argc, char ***res_argv, char *val) +{ + if (val) + { + *res_argv = calloc(1, sizeof(char*)); + if (*res_argv) + { + (*res_argv)[0] = strdup((const char*) val); + if ((*res_argv)[0]) + { + *res_argc = 1; + return; + } + } + + free(*res_argv); + *res_argc = 0; + } +} + +static void SetSuccessReturn(int *res_argc, char ***res_argv) +{ + SetReturn(res_argc, res_argv, RETURN_SUCCESS); +} + +static void SetFailureReturn(int *res_argc, char ***res_argv) +{ + SetReturn(res_argc, res_argv, RETURN_FAILURE); +} + +int SearchNodeN(const xmlChar *xpath, xmlDoc *pXmlDoc, xmlXPathObject **pXPathObj) +{ + DDBG("searchNode :%s\n", xpath); + int result = -1; + xmlXPathContextPtr pXPathCtx; + + pXPathCtx = xmlXPathNewContext(pXmlDoc); + if (pXPathCtx == NULL) + return result; + + xmlChar *pns = NULL; + xmlChar *puri = NULL; + GetNSURI(pXmlDoc, &pns, &puri); + + if (pns != NULL && puri != NULL) + { + if (xmlXPathRegisterNs(pXPathCtx, pns, puri) != 0) + return result; + } + + //Evaluate xpath expression + *pXPathObj = xmlXPathEvalExpression(xpath, pXPathCtx); + DDBG("============== XPATHobj address:%p\n", *pXPathObj); + + if (*pXPathObj == NULL) + { + DDBG("Cannot find node:%s\n", xpath); + free(pns); + free(puri); + return result; + } + + result = 0; + + free(pns); + free(puri); + + xmlXPathFreeContext(pXPathCtx); + return result; + +} + +// Dynamically load the library, get the product name, vendor name and version number, then +// update the xml file. +int InsertNode(xmlDoc **pDoc, const xmlChar *xpathNodeParent, const char *content) +{ + DDBG("insert node :%s\n", "=============="); + int result = -1; + xmlXPathContext *pXPathCtx; + xmlXPathObject *pXPathObj; + + pXPathCtx = xmlXPathNewContext(*pDoc); + if (pXPathCtx != NULL) + { + xmlChar *pns = NULL; + xmlChar *puri = NULL; + GetNSURI(*pDoc, &pns, &puri); + if (pns != NULL && puri != NULL) + { + if (xmlXPathRegisterNs(pXPathCtx, pns, puri) != 0) + { + DDBG("Cannot register xpath :%s\n", ""); + return result; + } + } + + // Evaluate xpath expression + pXPathObj = xmlXPathEvalExpression(xpathNodeParent, pXPathCtx); + if (pXPathObj != NULL) + { + xmlNodeSet *pNodeSet = pXPathObj->nodesetval; + int size; + size = pNodeSet ? pNodeSet->nodeNr : 0; + if (size == 1) // Should find only one node + { + // Get xmlnode + xmlDoc *pPlugDoc = xmlReadMemory(content, strlen(content), NULL, NULL, 0); + DDBG("plugdoc :%s\n", content); + + if (pPlugDoc != NULL) + { + xmlNode *newnode = xmlDocCopyNode(xmlDocGetRootElement(pPlugDoc), + pNodeSet->nodeTab[0]->doc,1); + DDBG("=========== pplugdoc address:%p\n", pPlugDoc); + + xmlFreeDoc(pPlugDoc); + //xmlNode *addNode = xmlAddChildList(pNodeSet->nodeTab[0], newnode->children); + xmlNode *addNode = xmlAddChildList(pNodeSet->nodeTab[0], newnode->children); + DDBG("=========== new node addr:%p\n", newnode); + + if (addNode != NULL) + { + result = 0; + DDBG("FREE new node:%p\n", newnode); + newnode->children = NULL; + xmlFreeNode(newnode); + } + } + } + } + free(pns); + free(puri); + pns = NULL; + puri = NULL; + + xmlXPathFreeObject(pXPathObj); + xmlXPathFreeContext(pXPathCtx); + } + + return result; +} + +int RemoveNodeParent(xmlDoc **pDoc, const xmlChar *path, const char* value) +{ + int result = -1; + if (*pDoc != NULL) + { + xmlXPathContext *pXPathCtx; + xmlXPathObject *pXPathObj; + + pXPathCtx = xmlXPathNewContext(*pDoc); + + if (pXPathCtx != NULL) + { + xmlChar *pns = NULL; + xmlChar *puri = NULL; + GetNSURI(*pDoc, &pns, &puri); + if (pns != NULL && puri != NULL) + { + if (xmlXPathRegisterNs(pXPathCtx, pns, puri) != 0) + { + return result; + } + } + pXPathObj = xmlXPathEvalExpression(path, pXPathCtx); + if (pXPathObj != NULL) + { + xmlNodeSet *pNodeSet = pXPathObj->nodesetval; + + int size; + size = pNodeSet ? pNodeSet->nodeNr : 0; + int i = 0; + xmlNode *cur; + xmlNode *parent; + for (; i < size; i++) + { + cur = pNodeSet->nodeTab[i]->children; + if (strcmp((const char*)cur->content, value) == 0) + { + parent = cur->parent->parent; + xmlUnlinkNode(parent); + break; + } + else + DDBG("THEY ARE NOT EQUAL:%s\n", value); + + } + result = 0; + xmlXPathFreeObject(pXPathObj); + } + free(pns); + free(puri); + pns = NULL; + puri = NULL; + xmlXPathFreeContext(pXPathCtx); + } + } + return result; +} + +int PrintXmlDoc(xmlDocPtr pDoc) +{ +#ifdef DEBUG + int result = 0; + int xmlSize; + xmlChar *xmlMem; + xmlDocDumpFormatMemory(pDoc, &xmlMem, &xmlSize, 0); + DDBG("pdoc content:%s\n", xmlMem); + free(xmlMem); + return result; +#else + return 0; +#endif +} + +int UpdateConfigFile(ConfigBuf **pData, xmlDoc **pXmlCp) +{ + int result = -1; + + if (pData && *pData) + { + pthread_mutex_lock(&((*pData)->configLock)); + if (pXmlCp && *pXmlCp) + { + result = WriteXmlToFile(*pXmlCp, CONFIG_FILE_NEW_W_PATH); + if (result == 0) + { + DDBG("==============update config file%s\n", " "); + PrintXmlDoc(*pXmlCp); + result = WriteXmlToFile(*pXmlCp, CONFIG_FILE_W_PATH); + if (result == 0) + { + //delete config new file + DDBG("REMOVE file:%s\n", CONFIG_FILE_NEW_W_PATH); + result = remove(CONFIG_FILE_NEW_W_PATH); + + if ((*pData)->pConfigBuffer != NULL) + xmlFreeDoc((*pData)->pConfigBuffer); + + (*pData)->pConfigBuffer = xmlCopyDoc(*pXmlCp, DO_RECURSIVE_COPY); + } + } + } + pthread_mutex_unlock(&((*pData)->configLock)); + } + return result; +} + +static int UpdatePlugin(const char *libname, xmlDoc **pXmlDoc, const char* appId) +{ + DDBG("~~~~~ UPDATE plugin: libname:%s, appID:%s\n", libname, appId); + int result = -1; + void *pHandle = NULL; + + pHandle = dlopen(libname, RTLD_LAZY); + if (pHandle == NULL) + { + char *error; + if ((error = dlerror()) != NULL) + DDBG("failed to open lib: %s, error:%s\n", libname, error); + } + else + { + char *pInfo = NULL; + char* (*getInfo)(void); + + DDBG("open library:%s\n", libname); + getInfo = dlsym(pHandle, "TCSGetInfo"); + + if (getInfo == NULL) + { + char *error; + if ((error = dlerror()) != NULL) + DDBG("SOMETHID :%s\n", error); + } + else + { + pInfo = strdup(getInfo()); + if (pInfo != NULL) + { + // Update node tree + result = UpdateNode((const xmlChar*) pInfo, pXmlDoc, (const xmlChar*) XPATH_PLUGINS, + appId); + free(pInfo); + pInfo = NULL; + } + } + + dlclose(pHandle); + } + return result; +} + +/** + * Get plugins node, should only have one node. After that, Check if has the node with appId, if so, + * remove this node. otherwise, add the new node. + */ +int UpdateNode(const xmlChar* content, xmlDoc **pDoc, const xmlChar *xpathNodeParent, + const char* appId) +{ + int result = -1; + + // Remove the plugin first if its appId same + char appidpath[GENERIC_STRING_SIZE]; + strncpy(appidpath, (const char*) XPATH_PLUGINS_PLUG, sizeof(appidpath)); + result = RemoveNodeParent(pDoc, (const xmlChar *)appidpath, appId); + + result = InsertNode(pDoc, xpathNodeParent, (const char*)content); + return result; +} + +static int ActivePlugin(ConfigBuf *pBuf, xmlDoc **pXmlCp, const xmlChar *appId) +{ + int result = -1; + + xmlXPathObject *pObj = NULL; + result = SearchNodeN((const xmlChar *)XPATH_ACTIVE_PLUGIN, *pXmlCp, &pObj); + + PrintXmlDoc(*pXmlCp); + + if (result == -1) + return result; + + result = -1; + xmlNodeSet *pNodeSet = NULL; + if (pObj) + { + pNodeSet = pObj->nodesetval; + } + + // If appId is empty, disable the active plugin, update activePlugin Node to None + if (strcmp((const char*)appId, APP_ID_NULL) == 0) + { + pthread_mutex_lock(&(pBuf->configLock)); + result = unlink(SYSLINK_PLUG_PATH); + pthread_mutex_unlock(&(pBuf->configLock)); + + if (pNodeSet) + { + if (pNodeSet->nodeTab[0]) + { + xmlNode *cur = pNodeSet->nodeTab[0]; + xmlNodeSetContent(cur, (xmlChar*)ACTIVE_NONE); + DDBG("GET node content :%s\n", cur->content); + } + } + result = 0; + } + else + { + // Get the plugin path from the appPath, set symbolic link for the plugin, update the xmlDoc + int count; + char **paths = NULL; + GetConfigElements(pXmlCp, (xmlChar *) XPATH_APP_PATHS, &count, &paths); + int i = 0; + for (; i < count; i++) + { + char appPath[FILE_NAME_MAX_SIZE]; + snprintf(appPath, FILE_NAME_MAX_SIZE, "%s%s%s%s", paths[i], "/", appId, + PLUGIN_DEFAULT_DIR_NAME); + + //Found the app path + struct stat info; + if (stat(appPath, &info) != 0) + continue; + + pthread_mutex_lock(&(pBuf->configLock)); + unlink(SYSLINK_PLUG_PATH); + result = symlink(appPath, SYSLINK_PLUG_PATH); + pthread_mutex_unlock(&(pBuf->configLock)); + + DDBG("set symbolic link result:from :%s to %s result:%d\n", appPath, SYSLINK_PLUG_PATH, result); + if (result == 0 && pNodeSet) + { + //update active Id node + xmlNode *cur = pNodeSet->nodeTab[0]; + xmlNodeSetContent(cur, appId); + DDBG("GET NOde conten :%s\n", cur->content); + + //xmlFreeNode(cur); + DDBG("RETURn from active plu g 0000:%d\n", result); + PrintXmlDoc(*pXmlCp); + + } + DDBG("RETURn from active plu g 0000 000000:%d\n", result); + //xmlXPathFreeNodeSet(pNodeSet); + break; + } + DDBG("RETURn from active plu g 0000 0111 :%d\n", result); + CleanupArray(&paths, count); + xmlXPathFreeObject(pObj); + + } + + DDBG("RETURn from active plug :%d\n", result); + return result; +} + +/** + * @appPath: /opt/usr/app/appId + */ +static int UpdatePluglibList(const char *appPath, xmlDoc **pXmlDoc, const char* appId) +{ + DDBG("=========================update plugin lib path:%s\n", appPath); + + int result = -1; + char plugPath[FILE_NAME_MAX_SIZE]; + + sprintf(plugPath, "%s%s", appPath, PLUGIN_DEFAULT_DIR_NAME); + DIR *pDir; + struct dirent *pDirEnt; + + pDir = opendir(plugPath); + DDBG("OPEN DIR:%s\n", plugPath); + if (pDir) + { + //open directories + while ((pDirEnt = readdir(pDir)) != NULL) + { + if (strcmp(pDirEnt->d_name, ".") == 0 || strcmp(pDirEnt->d_name, "..") == 0) + continue; + + if (pDirEnt->d_type == DT_REG) + { + // load the library, update xml node + char libPath[FILE_NAME_MAX_SIZE]; + sprintf(libPath, "%s%s%s", plugPath, "/", pDirEnt->d_name); + result = UpdatePlugin(libPath, pXmlDoc, appId); + break; + } + else + { + DDBG("IT IS NO regular file:%s\n", pDirEnt->d_name); + continue; + } + } + closedir(pDir); + + } + DDBG("RESTURN from update pluglib list :%d\n", result); + return result; +} + +/** + * + */ +int GetInfoPlugin(void *pData, int req_argc, char **req_argv, char ***res_argv, int *res_argc, + CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle) +{ + // check data pass is valid xml + xmlDoc *pXml = (xmlDoc*) *((xmlDoc**) pData); + *res_argc = FN_GET_INFO_RTN_COUNT; + *res_argv = calloc(1, sizeof(char*) * FN_GET_INFO_RTN_COUNT); + if (*res_argv == NULL) + goto no_memory; + + (*res_argv)[0] = strdup((const char*) RETURN_SUCCESS); + if ((*res_argv)[0] != NULL) + { + xmlChar *xmlMem; + int xmlSize; + xmlDocDumpFormatMemory(pXml, &xmlMem, &xmlSize, 0); + if (xmlMem != NULL) + { + DDBG("size is: %d, xmlmem is ** :%s\n", xmlSize, xmlMem); + (*res_argv)[1] = strdup((const char*) xmlMem); + if ((*res_argv)[1] == NULL) + { + DDBG("Not enough memory in :%s\n", "set xmlmem in return"); + free((*res_argv)[0]); + (*res_argv)[0] = NULL; + goto invalid_xml; + } + xmlFree(xmlMem); + xmlMem = NULL; + } + else + goto invalid_xml; + } + else + { + DDBG("failed to copy return_successS:%s\n", ""); + goto no_memory; + } + DDBG("successfully finished:%s\n", "GetInfoPlugin"); + return 0; + + invalid_xml: + // get recoverred config.xml and return + no_memory: + *res_argc = 0; + return 0; +} + +/** + * pData is the buffer of config.xml, + * ** apply lock + * if copy pData to pData.cp success, + * if update pData.cp with the newly installed info + * if successfully update the symbolic link, + * if write pData.cp to config.xml.new + * if switch config.xml.new to config.xml + * else do nothing, wait for next time update + * else do nothing, wait for next time udpate + * copy pData.cp to pData, free pData.cp + * else return failure update + * ** unlock + * + * @req_argc: 1 + * @req_argv: app installation path, i.e. /opt/usr/apps/appID + */ +int InstallPlugin(void *pData, int req_argc, char **req_argv, char ***res_argv, int *res_argc, + CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle) +{ + DDBG("InstallPlugin for serverstub:%s\n", req_argv[0]); + int result = -1; + ConfigBuf *pBuf = *((ConfigBuf **) pData); + pthread_mutex_lock(&(pBuf->configLock)); + xmlDoc *pXml = (*((ConfigBuf **) pData))->pConfigBuffer; + xmlDoc *pXmlCp = xmlCopyDoc(pXml, DO_RECURSIVE_COPY); + pthread_mutex_unlock(&(pBuf->configLock)); + + if (pXmlCp != NULL) + { + if (req_argc == 1 && req_argv != NULL) + { + // Get apppath list + int count; + char **paths = NULL; + GetConfigElements(&pXmlCp, (xmlChar *) XPATH_APP_PATHS, &count, &paths); + int i = 0; + for (; i < count; i++) + { + char appPath[FILE_NAME_MAX_SIZE]; + sprintf(appPath, "%s%s%s", paths[i], "/", req_argv[0]); + + PrintXmlDoc(pXmlCp); + if (UpdatePluglibList(appPath, &pXmlCp, req_argv[0]) == 0) + { + if (ActivePlugin(*((ConfigBuf**) pData), &pXmlCp, (const xmlChar *)req_argv[0]) == 0) + { + // Write to new file + DDBG("Success cpy xml 2:%s\n", appPath); + + *res_argc = FN_INSTALL_PLUG_RTN_COUNT; + *res_argv = calloc(1, sizeof(char*) * FN_INSTALL_PLUG_RTN_COUNT); + if (*res_argv == NULL) + goto no_memory; + + (*res_argv)[0] = strdup((const char*) RETURN_SUCCESS); + if ((*res_argv)[0] == NULL) + goto no_memory; + + xmlChar *xmlMem = NULL; + int xmlSize; + + xmlDocDumpFormatMemory(pXmlCp, &xmlMem, &xmlSize, 0); + DDBG("XMLmEM address: %p\n", xmlMem); + if (xmlMem != NULL) + { + (*res_argv)[1] = strdup((const char*) xmlMem); + DDBG("return from install plug:%s\n", (*res_argv)[1]); + free(xmlMem); + xmlMem = NULL; + + if ((*res_argv)[1] != NULL) + { + result = UpdateConfigFile(pData, &pXmlCp); + break; + } + } + } + } + } + CleanupArray(&paths, count); + } + } + xmlFreeDoc(pXmlCp); + + if (result == -1) + goto failure; + else + { + return result; + } + +no_memory: + xmlFreeDoc(pXmlCp); + +failure: + *res_argc = 1; + *res_argv = calloc(1, sizeof(char*)); + (*res_argv)[0] = strdup((const char*) RETURN_FAILURE); + return result; +} + +/** + * If it is active plugin, unlink the syslink, and update active element with AppId to None. + * If the request plugin is not active one, remove it from the plugin list + */ +int UninstallPlugin(void *pData, int req_argc, char **req_argv, char ***res_argv, int *res_argc, + CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle) +{ + int result = -1; + xmlDoc *pXml = NULL; + xmlDoc *pXmlCp = NULL; + ConfigBuf *pBuf = NULL; + xmlXPathObject *pObj = NULL; + + if (req_argc != 1 || req_argv == NULL) + goto failure; + + pBuf = *((ConfigBuf **) pData); + + pthread_mutex_lock(&(pBuf->configLock)); + pXml = pBuf->pConfigBuffer; + pXmlCp = xmlCopyDoc(pXml, DO_RECURSIVE_COPY); + pthread_mutex_unlock(&(pBuf->configLock)); + + if (pXmlCp == NULL) + goto failure; + + result = SearchNodeN((const xmlChar *)XPATH_ACTIVE_PLUGIN, pXmlCp, &pObj); + if (result != 0) + goto failure; + + xmlNodeSet *pNodeSet = pObj->nodesetval; + xmlNode *pNode = pNodeSet->nodeTab[0]; + if (pNode == NULL) + { + DDBG("not such node %s\n", XPATH_ACTIVE_PLUGIN); + goto failure; + } + + if (pNode->type != XML_ELEMENT_NODE) + goto failure; + + // Search for plugin. If found, unlink the plugin. Otherwise, the plugin was already + // unlinked and updated in the config file. + DDBG("node name:%s, activenode value: %s\n", pNode->name, pNode->children->content); + if (strcmp((const char *)pNode->children->content, req_argv[0]) == 0) + { + pthread_mutex_lock(&(pBuf->configLock)); + result = unlink(SYSLINK_PLUG_PATH); + pthread_mutex_unlock(&(pBuf->configLock)); + + if (result != 0 && result != ENOENT) + goto failure; + + xmlNodeSetContent(pNode, (const xmlChar *)ACTIVE_NONE); + } + + // Remove the plugin node if it is in the plugin list + result = RemoveNodeParent(&pXmlCp, (const xmlChar *)XPATH_PLUGINS_PLUG, req_argv[0]); + result = UpdateConfigFile((ConfigBuf**) pData, &pXmlCp); + if (result != 0) + { + DDBG("Unable to update config file with uninstall info\n"); + goto failure; + } + SetSuccessReturn(res_argc, res_argv); + goto cleanup; + +failure: + SetFailureReturn(res_argc, res_argv); + +cleanup: + if (pObj) + xmlXPathFreeObject(pObj); + if (pXmlCp) + xmlFreeDoc(pXmlCp); + + return result; +} + +/** + * Copy the xmlDoc + * Update the symbolic link if it is not the active plug + * Update xmlDoc, save to the tpcs_config.xml + */ +int SetActivePlugin(void *pData, int req_argc, char **req_argv, char ***res_argv, int *res_argc, + CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle) +{ + DDBG("SetActivePlugin :%s\n", req_argv[0]); + + ConfigBuf *pBuf = NULL; + xmlDoc *pXml = NULL; + xmlDoc *pXmlCp = NULL; + int result = -1; + + if (req_argc != 1 || req_argv == NULL) + return result; + + pBuf = *((ConfigBuf **) pData); + + pthread_mutex_lock(&(pBuf->configLock)); + pXml = pBuf->pConfigBuffer; + pXmlCp = xmlCopyDoc(pXml, DO_RECURSIVE_COPY); + pthread_mutex_unlock(&(pBuf->configLock)); + + if (pXmlCp == NULL) + return result; + + PrintXmlDoc(pXmlCp); + if ((ActivePlugin(pBuf, &pXmlCp, (const xmlChar *)req_argv[0]) == 0) + && UpdateConfigFile((ConfigBuf**) pData, &pXmlCp) == 0) + { + SetSuccessReturn(res_argc, res_argv); + DDBG("==== FINd tha ppid %s\n", req_argv[0]); + } + else + { + DDBG("==== **** FINd tha ppid %s\n", req_argv[0]); + SetFailureReturn(res_argc, res_argv); + } + + xmlFreeDoc(pXmlCp); + return result; +} + +static int WriteXmlToFile(xmlDoc *pXmlDoc, const char* filename) +{ + + DDBG("Write xml to file: %s\n", filename); + int result = -1; + FILE *pfConfig = fopen(filename, "w"); + if (pfConfig != NULL) + { + xmlDocDump(pfConfig, pXmlDoc); + fclose(pfConfig); + result = 0; + } + return result; +} + +static int InitConfigFile(xmlDoc **pXmlDoc) +{ + int result = -1; + DDBG("Size of xml doc in memory :%d\n", sizeof(CONFIG_DEFAULT_STRING)); + + *pXmlDoc = xmlReadMemory(CONFIG_DEFAULT_STRING, sizeof(CONFIG_DEFAULT_STRING) + 1, + CONFIG_FILE_NAME, + NULL, 0); + + if (*pXmlDoc != NULL) + { + result = 0; + } + + return result; +} + +static bool IsValidTPCSConfig(const char *pFileName, xmlDoc **ppXmlDoc) +{ + // Create a parse context + bool ret = FALSE; + xmlParserCtxt *pParserCtxt = xmlNewParserCtxt(); + xmlDoc *pXmlDoc; + if (pParserCtxt == NULL) + { + DDBG("%s\n", "======Failed to allocate parser context"); + return ret; + } + else + { + // valid this config file + // Parse the file, activating the DTD validation option */ + DDBG("------------------ IS VALID config file :%s\n", "---------------------"); + pXmlDoc = xmlCtxtReadFile(pParserCtxt, pFileName, NULL, XML_PARSE_DTDVALID); + DDBG("--- 1 pxmldoc address: %p\n", pXmlDoc); + DDBG("file to read:%s\n", pFileName); + PrintXmlDoc(pXmlDoc); + if (pXmlDoc != NULL) + { + // Check if validation succeeded + if (pParserCtxt->valid) + { + *ppXmlDoc = pXmlDoc; + DDBG("address of ppxmldoc: %p\n", *ppXmlDoc); + ret = TRUE; + } + } + else + { + DDBG("NOT VALID file: %s\n", pFileName); + } + + xmlFreeParserCtxt(pParserCtxt); + return ret; + } +} + +/** + * Return directory list that has the specified directory within + */ +static void GetDirsHasPath(const char *dir, const char *search_path, int *pCount, + char ***name_w_path, char ***appId) +{ + DIR *pDir = NULL; + struct dirent *pDirEnt = NULL; + + if (!dir || !search_path || !pCount || !appId || !name_w_path) + return; + + pDir = opendir(dir); + *pCount = 0; + if (pDir) + { + char plugPath[FILE_NAME_MAX_SIZE]; + char appPath[FILE_NAME_MAX_SIZE]; + + struct stat info; + while ((pDirEnt = readdir(pDir)) != NULL) + { + if (strcmp(pDirEnt->d_name, ".") == 0 || strcmp(pDirEnt->d_name, "..") == 0) + { + continue; + } + if (pDirEnt->d_type == DT_DIR) + { + sprintf(appPath, "%s%s%s", dir, "/", pDirEnt->d_name); + + sprintf(plugPath, "%s%s", appPath, PLUGIN_DEFAULT_DIR_NAME); + + if (stat(plugPath, &info) == 0) + { + if (*pCount == 0) + { + *name_w_path = calloc(1, sizeof(char*)); + + if (*name_w_path) + { + (*pCount)++; + (*name_w_path)[0] = strdup((const char*) appPath); + + if ((*name_w_path)[0] == NULL) + goto clean_up; + } + else + goto clean_up; + + *appId = calloc(1, sizeof(char*)); + if (*appId) + { + (*appId)[0] = strdup((const char*) pDirEnt->d_name); + DDBG("COUNT 0, name: %s\n", pDirEnt->d_name); + if ((*appId)[0] == NULL) + goto clean_up; + } + } + else + { + //TODO: all the realloc * size, use chunk + *name_w_path = realloc(*name_w_path, sizeof(char*) * (*pCount + 1)); + if (*name_w_path) + { + (*pCount)++; + (*name_w_path)[(*pCount) - 1] = strdup((const char*) appPath); + if ((*name_w_path)[(*pCount) - 1] == NULL) + goto clean_up; + + *appId = realloc(*appId, sizeof(char*) * (*pCount + 1)); + if (*appId) + { + (*appId)[*pCount - 1] = strdup((const char*) pDirEnt->d_name); + if (((*appId)[*pCount - 1]) == NULL) + { + goto clean_up; + } + } + else + { + goto clean_up; + } + } + else + { + goto clean_up; + } + } + } + } + } + + goto success; + } + +clean_up: + CleanupArray(name_w_path, *pCount); + +success: + DDBG("CLOSE dir: %s\n", " " ); + if (pDir) + closedir(pDir); + + return; +} + +/** + * + */ +static void CleanupArray(char*** pArr, int len) +{ + if (pArr) + { + while (len > 0) + { + len--; + if ((*pArr)[len]) + { + free((*pArr)[len]); + (*pArr)[len] = NULL; + } + } + + if (*pArr) + { + free(*pArr); + *pArr = NULL; + } + } +} + +/* + * int ftw(const char *dir, int (*fn)(const char *file, const struct stat *sb, int flag), int nopenfd); + */ +int FileTreeCallback(const char *pFile, const struct stat *pStat, int flag) +{ + int result = 0; + if (pStat->st_mode & S_IFREG) + { + //DDBG(">>>>>file tree walk :%s, such substring:%s\n", pFile, MANIFEST_FILE_NAME); + if (EndsWith(pFile, MANIFEST_FILE_NAME) == 0) + { + DDBG("FOUNd the file: %s\n", pFile); + // check if it has the plugin tag + if (HasTag(PLUGIN_ANTI_VIRUS_TAG, pFile, XPATH_PLUGIN_CATEGORY) == 0) + { + // found the library + DDBG("this app is plugin app:%s\n", pFile); + result = 1; + } + } + } + return result; +} + +/** + * Checks if str ends with needle. Return zero on success otherwise non-zero. + */ +static int EndsWith(const char *hay, const char *needle) +{ + size_t haylen, needlelen; + + if (!hay || !needle) + return -1; + + needlelen = strlen(needle); + haylen = strlen(hay); + + if (needlelen > haylen) + return -1; + + return strncmp(hay + haylen - needlelen, needle, needlelen); +} + +static void GetNSURI(xmlDoc *pXmlDoc, xmlChar **pns, xmlChar **uri) +{ + xmlNode *root_node = xmlDocGetRootElement(pXmlDoc); + + if (root_node) + { + xmlNs *pXmlNS = root_node->ns; + xmlNs *pXmlNSDef = root_node->nsDef; + + if (pXmlNS != NULL) + { + if (pXmlNS->prefix != NULL) + { + *pns = (xmlChar*) strdup((const char*) pXmlNS->prefix); + } + else + { + DDBG("root node name:%s\n", root_node->name); + *pns = (xmlChar*) strdup((const char*) root_node->name); + } + } + + if (pXmlNSDef != NULL) + { + if (pXmlNSDef->href != NULL) + { + DDBG("nsdef :%s\n", pXmlNSDef->href); + *uri = (xmlChar*) strdup((const char*) pXmlNSDef->href); + } + } + } + return; +} + +/** + * Get elements from xmlDoc, and output to the count and content + */ +static void GetConfigElements(xmlDoc **pXmlDoc, xmlChar *pXPath, int *size, char ***content) +{ + DDBG("GetConfigElements in xpath: %s\n", (char*)pXPath); + // Scan all the directories that has av category, update its plugin element in config.xml + xmlXPathContext *pXPathCtx; + xmlXPathObject *pXPathObj; + + pXPathCtx = xmlXPathNewContext(*pXmlDoc); + if (pXPathCtx != NULL) + { + xmlChar *pns = NULL; + xmlChar *puri = NULL; + GetNSURI(*pXmlDoc, &pns, &puri); + if (pns != NULL && puri != NULL) + { + if (xmlXPathRegisterNs(pXPathCtx, pns, puri) != 0) + { + DDBG("Cannot register xpath :%s\n", ""); + return; + } + } + // Evaluate xpath expression + pXPathObj = xmlXPathEvalExpression(pXPath, pXPathCtx); + if (pXPathObj != NULL) + { + xmlNode *cur; + xmlNodeSet *pNodeSet = pXPathObj->nodesetval; + + *size = pNodeSet ? pNodeSet->nodeNr : 0; + if (*size > 0) + { + int i = 0; + *content = calloc(1, sizeof(char*) * (*size)); + DDBG("XAPTH OBJCT FOUND:%s, size:%d\n", "", *size); + if (*content) + { + for (; i < *size; i++) + { + if (pNodeSet->nodeTab[i]->type == XML_ELEMENT_NODE) + { + cur = pNodeSet->nodeTab[i]; + + if (*content) + { + DDBG("content; %s\n", cur->children->content); + (*content)[i] = strdup((const char*) cur->children->content); + } + } + } + } + else + { + DDBG("CANNOT FOUND content:%s\n", ""); + } + + } + xmlXPathFreeObject(pXPathObj); + } + if (pns) + { + free(pns); + pns = NULL; + } + + if (puri) + { + free(puri); + puri = NULL; + } + + xmlXPathFreeContext(pXPathCtx); + } +} + +static int HasTag(const char *pTag, const char *pFileName, const char *xpath) +{ + int result = 1; + xmlDoc *pConfigXml = NULL; + + if (!pTag) + return result; + + pConfigXml = xmlReadFile(pFileName, NULL, 0); + if (pConfigXml != NULL) + { + int size; + char **pCategory = NULL; + GetConfigElements(&pConfigXml, (xmlChar*) xpath, &size, &pCategory); + if (size > 0) + { + DDBG("size is: %d, category:%s\n", size, pCategory[0]); + int i = 0; + for (; i < size; i++) + { + if (strcmp(pCategory[i], pTag) == 0) + { + result = 0; + break; + } + } + } + CleanupArray(&pCategory, size); + } + xmlFreeDoc(pConfigXml); + return result; +} + +/* + * config.xml validation + * If config.xml.new exists, and it is valid, + * if it is consistent with symbolic link, switch this to config.xml + * else if there is config.xml, and + * if it is valid + * if it is consistent with symbolic link, buffer the config.xml + * else based on the symbolic link, update config.xml, then buffer the config.xml + * else + * recover the config.xml by scan all the applications, checking symbolic link, create the + * config.xml, buffer it. + * Pass the data address to the pData + */ +int main(int argc, char **argv) +{ + //TODO: make it a daemon + +#ifndef DEBUG + fork_daemon(); +#endif + + //Add methods + //Start TPCS daemon + TSC_SERVER_HANDLE hServer = NULL; + int ret = -1; + + + fprintf(stderr, "TPCS Service Daemon Started%s\n", ""); + //TODO: rename TSC_DBUS_SERVER_PLUGIN_CHANNEL to TSC_DBUS_SERVER_PLUGIN_CHANNEL + if ((hServer = IpcServerOpen(TSC_DBUS_SERVER_PLUGIN_CHANNEL)) != NULL) + { + DDBG("%s", "**** successfully opened server ****\n"); + // Write out the DTD validation file + FILE *pDTD = fopen(CONFIG_DTD_FILE_W_PATH, "r"); + if (pDTD == NULL) + { + pDTD = fopen(CONFIG_DTD_FILE_W_PATH, "w"); + if (pDTD) + { + fwrite(CONFIG_DEFAULT_DTD_STRING, strlen(CONFIG_DEFAULT_DTD_STRING), 1, pDTD); + fclose(pDTD); + } + else + { + goto done; + } + } + else + { + //TODO: close the file, check if the file exists lstat, signature of the file + } + + ConfigBuf *pConfigBuf = calloc(1, sizeof(ConfigBuf)); + if (pConfigBuf == NULL) + return ret; + ret = pthread_mutex_init(&(pConfigBuf->configLock), NULL); + if (ret == -1) + { + //TODO: memory clean up + free(pConfigBuf); + pConfigBuf = NULL; + return ret; + } + + if (IsValidTPCSConfig(CONFIG_FILE_NEW_W_PATH, &(pConfigBuf->pConfigBuffer))) + { + // switch to config.xml + if (rename(CONFIG_FILE_NEW_W_PATH, CONFIG_FILE_W_PATH) == 0) + { + DDBG("%s has been renamed to :%s\n", CONFIG_FILE_NEW_W_PATH, CONFIG_FILE_W_PATH); + } + //TODO: if failed, it will exist, + } + else + { + DDBG("=== check config.xml not valid config file: %s\n", CONFIG_FILE_NEW_W_PATH); + + + // Buffer config.xml + if (!IsValidTPCSConfig(CONFIG_FILE_W_PATH, &(pConfigBuf->pConfigBuffer))) + { + //Recover config.xml from memory + InitConfigFile(&(pConfigBuf->pConfigBuffer)); + DDBG("***************** initconfigfile: %p\n", pConfigBuf->pConfigBuffer); + + DDBG("Failed to parse file : %s\n", CONFIG_FILE_W_PATH); + + // Add plugins by scanning appPath directory + int count; + char **paths = NULL; + GetConfigElements(&(pConfigBuf->pConfigBuffer), (xmlChar*) XPATH_APP_PATHS, &count, + &paths); + + int i; + int dirCount = 0; + char **app_path = NULL; + char **appId = NULL; + for (i = 0; i < count; i++) + { + // Get list of directories under the app path, if it has $appPath/lib/plugin/, + // search its manifest.xml for av tag, then recompose config.xml + + //TODO: if better way to get list of directory + GetDirsHasPath(paths[i], PLUGIN_DEFAULT_DIR_NAME, &dirCount, &app_path, &appId); + DDBG("fater get dirshas path:%s\n", PLUGIN_DEFAULT_DIR_NAME); + if (dirCount > 0) + { + // search manifest.xml within the app_path, if found, copy the appid to plugin element + int j; + for (j = 0; j < dirCount; j++) + { + //ftw return 0: tree exhausted, -1: error, others whatever the FileTreeCallback return + int result = ftw(app_path[j], FileTreeCallback, 12); + if (result == 1) + { + DDBG("it found the plugin app dir:%s, appID:%s\n", app_path[j], appId[j]); + //Update plugin element node + UpdatePluglibList(app_path[j], &(pConfigBuf->pConfigBuffer), + appId[j]); + } + } + } + CleanupArray(&appId, dirCount); + CleanupArray(&app_path, dirCount); + } + + CleanupArray(&paths, count); + + // Recover config.xml from memory + WriteXmlToFile(pConfigBuf->pConfigBuffer, CONFIG_FILE_W_PATH); + DDBG("before clean up:%s, dircoutn:%d, pathCount:%d, \n", CONFIG_FILE_W_PATH, dirCount, count); + + } + else + { + DDBG("Success in paring file: %s\n", CONFIG_FILE_W_PATH); + } + } + + // Register methods for GetInfoPlugin + IpcServerMethod method_getPlugin; + snprintf(method_getPlugin.szMethod, sizeof(method_getPlugin.szMethod), "%s", + "TPCSGetInfoPlugin"); + method_getPlugin.method = (METHODFUNC) GetInfoPlugin; + method_getPlugin.pData = &(pConfigBuf->pConfigBuffer); + + if (IpcServerAddMethod(hServer, &method_getPlugin) != 0) + { + DDBG("%s", "unable to add method GetInfoPlugin\n"); + goto close_server; + } + + // Register methods for InstallPlugin + IpcServerMethod method_installPlugin; + snprintf(method_installPlugin.szMethod, sizeof(method_installPlugin.szMethod), "%s", + "TPCSInstallPlugin"); + method_installPlugin.method = (METHODFUNC) InstallPlugin; + method_installPlugin.pData = &pConfigBuf; + + if (IpcServerAddMethod(hServer, &method_installPlugin) != 0) + { + DDBG("%s", "unable to add method InstallPlugin\n"); + goto close_server; + } + + // Register methods for SetActivePlugin + IpcServerMethod method_setActivePlugin; + snprintf(method_setActivePlugin.szMethod, sizeof(method_setActivePlugin.szMethod), "%s", + "TPCSSetActivePlugin"); + method_setActivePlugin.method = (METHODFUNC) SetActivePlugin; + method_setActivePlugin.pData = &pConfigBuf; + + if (IpcServerAddMethod(hServer, &method_setActivePlugin) != 0) + { + DDBG("%s", "unable to add method SetActivePlugin\n"); + goto close_server; + } + + // Register methods for UnInstallPlugin + IpcServerMethod method_uninstallPlugin; + snprintf(method_uninstallPlugin.szMethod, sizeof(method_uninstallPlugin.szMethod), "%s", + "TPCSUninstallPlugin"); + method_uninstallPlugin.method = (METHODFUNC) UninstallPlugin; + method_uninstallPlugin.pData = &pConfigBuf; + + if (IpcServerAddMethod(hServer, &method_uninstallPlugin) != 0) + { + DDBG("%s", "unable to add method UninstallPlugin\n"); + goto close_server; + } + + DDBG("----------------- START method loop----------%s", "\n"); + + // Daemon waits here for request from clients. + IpcServerMainLoop(hServer); + DDBG("----------------- END method loop----------%s", "\n"); + // Clean up + DDBG("======================= free xmldoc for isvalidConfig %s\n", "=============="); + DDBG("pconfigbuf address:%p\n", pConfigBuf->pConfigBuffer); + xmlFreeDoc(pConfigBuf->pConfigBuffer); + free(pConfigBuf); + + IpcServerClose(&hServer); + } + else + { + DDBG("%s", "unable to open server connection \n"); + ret = -1; + goto done; + } + xmlCleanupParser(); // clean up library for xml library for valgrind + close_server: + IpcServerClose(&hServer); + + done: + DDBG("%s", "Unable to start the Daemon \n"); + + return ret; + +} diff --git a/framework/TPCSSerDaemon.h b/framework/TPCSSerDaemon.h new file mode 100644 index 0000000..7dd3e2c --- /dev/null +++ b/framework/TPCSSerDaemon.h @@ -0,0 +1,59 @@ +#define ERROR_GENERIC -1 +#define RETURN_SUCCESS "0" +#define RETURN_FAILURE "1" + +#define FN_GET_INFO_RTN_COUNT 2 +#define FN_INSTALL_PLUG_RTN_COUNT 2 +#define DO_RECURSIVE_COPY 1 +#define FILE_NAME_MAX_SIZE 128 +#define GENERIC_STRING_SIZE 128 +#define FN_GET_INFO "getInfo" +#define TAG_VERSION "Version" +#define TAG_VENDOR_NAME "VendorName" +#define TAG_PRODUCT_NAME "ProductName" +#define TAG_APP_ID "AppId" +#define TAG_PLUG_NODE "Plug" +#define MANIFEST_FILE_NAME "manifest.xml" +#define XPATH_PLUGIN_CATEGORY "//Manifest:Manifest/Manifest:Apps/Manifest:UiApp/Manifest:Categories/Manifest:Category" +#define PLUGIN_ANTI_VIRUS_TAG "http://tizen.org/category/antivirus" +#define PLUGIN_SYSTEM_PATH "/usr/bin" +#define PLUGIN_DEFAULT_DIR_NAME "/lib/plugin" +#define XPATH_PLUGINS "//TPCSConfig/Plugins" +#define XPATH_PLUGINS_PLUG "//TPCSConfig/Plugins/Plug/AppId" +#define XPATH_ACTIVE_PLUGIN "//TPCSConfig/Active/AppId" +#define XPATH_ACTIVE "//TPCSConfig/Active" +#define XPATH_APP_PATHS "//TPCSConfig/AppPaths/Path" +#define CONFIG_ENCODING "UTF-8" +#define CONFIG_DTD_FILE_W_PATH "/usr/bin/tpcs_config.dtd" +#define CONFIG_FILE_W_PATH "/usr/bin/tpcs_config.xml" +#define CONFIG_FILE_NEW_W_PATH "/usr/bin/tpcs_config_new.xml" +#define SYSLINK_PLUG_PATH "/lib/plugin" +#define ACTIVE_NONE "None" +#define APP_ID_NULL "" +#define CONFIG_DEFAULT_STRING "\n\ + \n\ + \n\ + \n\ + /opt/usr/apps\n\ + /sdcard\n \ + \n\ + \n\ + None\n\ + \n\ + \n\ + \n\ +" + + +#define CONFIG_DEFAULT_DTD_STRING "\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +\n\ +" +#define CONFIG_FILE_NAME "tpcs_config.xml" + diff --git a/framework/TSCErrorCodes.h b/framework/TSCErrorCodes.h new file mode 100644 index 0000000..e345971 --- /dev/null +++ b/framework/TSCErrorCodes.h @@ -0,0 +1,84 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef TSCERRORCODES_H +#define TSCERRORCODES_H + +#ifdef __cplusplus +extern "C" { +#endif +/** + * \file TSCErrorCodes.h + * \brief TSC Error Code Header File + * + * This file provides the TSC error code definition. + */ + +#define TSC_ERROR_MODULE_GENERIC 1 /* A generic error code. */ +#define ERR_NAME_MODULE_GENERIC "Generic" +#define ERR_DESC_MODULE_GENERIC "A generic error." + +#define TSC_ERROR_CANCELLED 1 /* Operation cancelled. */ +#define ERR_NAME_CANCELLED "Cancelled" +#define ERR_DESC_CANCELLED "Operation cancelled." + +#define TSC_ERROR_DATA_ACCESS 2 /* Unable to access data. */ +#define ERR_NAME_DATA_ACCESS "DataAccess" +#define ERR_DESC_DATA_ACCESS "Unable to access data." + +#define TSC_ERROR_INVALID_PARAM 3 /* Invalid parameter. */ +#define ERR_NAME_INVALID_PARAM "InvalidParam" +#define ERR_DESC_INVALID_PARAM "Invalid parameter." + +#define TSC_ERROR_INSUFFICIENT_RES 4 /* Insufficient resource. */ +#define ERR_NAME_INSUFFICIENT_RES "InsufficientRes" +#define ERR_DESC_INSUFFICIENT_RES "Insufficient resource." + +#define TSC_ERROR_INTERNAL 5 /* Unexpected internal error. */ +#define ERR_NAME_INTERNAL "Internal" +#define ERR_DESC_INTERNAL "Unexpected internal error." + +#define TSC_ERROR_INVALID_HANDLE 6 /* Invalid handle. */ +#define ERR_NAME_INVALID_HANDLE "InvalidHandle" +#define ERR_DESC_INVALID_HANDLE "Invalid handle." + +#define TSC_ERROR_NOT_IMPLEMENTED 7 /* Specified method is not implemented by the Channel server. */ +#define ERR_NAME_NOT_IMPLEMENTED "NotImplemented" +#define ERR_DESC_NOT_IMPLEMENTED "Specified method is not implemented." + +#define TSC_ERROR_REMOVE_METHOD_NOT_FOUND -1 +#define TSC_ERROR_ADD_METHOD_FAILED -1 + +#ifdef __cplusplus +} +#endif + +#endif /* TSCERRORCODES_H */ diff --git a/framework/TWPSerDaemon.c b/framework/TWPSerDaemon.c new file mode 100644 index 0000000..bc01242 --- /dev/null +++ b/framework/TWPSerDaemon.c @@ -0,0 +1,344 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file TWPSerDaemon.c + * \brief TWP Service Daemon source file. + * + * This file implements the TWP Service Daemon functions used by Security framework. + */ + +#include +#include +#include +#include + +#include "Debug.h" +#include "IpcForkDaemon.h" +#include "TWPImpl.h" +#include "TWPSerDaemon.h" + +#define RISK_LEVEL_LEN 2 +#define RETURN_STATUS_STR_LEN 4 + +int +TWPSerGetVersion(void *pData, int req_argc, char **req_argv, char ***rep_argv, int *rep_argc, + CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle) +{ + // Opens TWP Framework library. + TWPAPIInit Init; + TWPLIB_HANDLE hLib; + + Init.api_version = TWPAPI_VERSION; + Init.memallocfunc = (TWPFnMemAlloc) malloc; + Init.memfreefunc = free; + hLib = TWPInitLibrary(&Init); + + *rep_argc = 1; + *rep_argv = NULL; + + TWP_RESULT iRes; + char *szRes = NULL; + + if (hLib == INVALID_TWPLIB_HANDLE) + { + iRes = TWP_INVALID_HANDLE; + goto close_library; + } + + // Get the Version Information of TWP Framework. + TWPVerInfo VerInfo; + iRes = TWPGetVersion(hLib, &VerInfo); + + // Check if TWPGetVersion call returned TWP_SUCCESS. + if (iRes != TWP_SUCCESS) + { + DERR("%s", "TWPGetVersion did not return TWP_SUCCESS\n"); + } + else + { + DINFO("TWPGetVersion returns = %s %s\n", VerInfo.szFrameworkVer, VerInfo.szPluginVer); + + char *szRepArgv1 = strdup(VerInfo.szFrameworkVer); + char *szRepArgv2 = strdup(VerInfo.szPluginVer); + char *szRepArgv3 = strdup(TWP_DAEMON_VERSION); + + if (szRepArgv1 == NULL || szRepArgv2 == NULL || szRepArgv3 == NULL) + { + DERR("%s", "strdup fails to allocate mem for version info"); + + free(szRepArgv1); + free(szRepArgv2); + free(szRepArgv3); + iRes = TWP_NOMEM; + goto close_library; + } + + *rep_argc = 4; + *rep_argv = (char **) malloc(sizeof(char*) * (*rep_argc)); + + if (*rep_argv == NULL) + { + DERR("%s", "malloc returns Error for reply pointer array\n"); + + free(szRepArgv1); + free(szRepArgv2); + free(szRepArgv3); + *rep_argc = 1; + iRes = TWP_NOMEM; + goto close_library; + } + + (*rep_argv)[1] = szRepArgv1; + (*rep_argv)[2] = szRepArgv2; + (*rep_argv)[3] = szRepArgv3; + } + +close_library: + // Compose the return value. + // Convert iRes to String. + szRes = (char *) malloc(sizeof(char) * RETURN_STATUS_STR_LEN); + if (szRes == NULL) + { + DERR("%s", "malloc returns error\n"); + goto err; + } + snprintf(szRes, RETURN_STATUS_STR_LEN, "%d", iRes); + + if (*rep_argc == 1) + { + *rep_argv = (char **) malloc (sizeof(char*) * 1); + if (*rep_argv == NULL) + goto err; + } + + //Assign result code. + (*rep_argv)[0] = szRes; + + TWPUninitLibrary(hLib); + return 0; + +err: + if (*rep_argv != NULL) + { + free((*rep_argv)[1]); + free((*rep_argv)[2]); + free((*rep_argv)[3]); + } + *rep_argc = 0; + free(*rep_argv); + *rep_argv = NULL; + rep_argv = NULL; + free(szRes); + TWPUninitLibrary(hLib); + + return -1; +} + +int +TWPSerGetURLReputation(void *pData, int req_argc, char **req_argv, char ***rep_argv, int *rep_argc, + CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle) +{ + // open TWP framework library + TWPAPIInit Init; + TWPLIB_HANDLE hLib; + + Init.api_version = TWPAPI_VERSION; + Init.memallocfunc = (TWPFnMemAlloc) malloc; + Init.memfreefunc = free; + hLib = TWPInitLibrary(&Init); + + *rep_argc = 1; + *rep_argv = NULL; + + TWP_RESULT iRes; + char *szRes = NULL; + + if (hLib == INVALID_TWPLIB_HANDLE) + { + iRes = TWP_INVALID_HANDLE; + goto close_library; + } + + // Get Risk Level. + int iRiskLevel; + unsigned int uBlkUrlLen; + char *pBlkUrl = NULL; + + // Check for Risk Level of URL. + iRes = TWPCheckURL(hLib, req_argv[0], &pBlkUrl, &uBlkUrlLen, &iRiskLevel); + + // Check if TWPCheckURL call returned TWP_SUCCESS. + if (iRes != TWP_SUCCESS) + { + DERR("%s : %s\n", "TWPCheckURL returned Error", req_argv[0]); + } + else + { + DINFO("TWPCheckURL returns risk level = %d\n", iRiskLevel); + + // convert RiskLevel integer to string + char *szRiskLevel; + szRiskLevel = (char *) malloc(sizeof(char) * RISK_LEVEL_LEN); + if (szRiskLevel == NULL) + { + DINFO("%s", "malloc returns error\n"); + iRes = TWP_NOMEM; + goto close_library; + } + snprintf(szRiskLevel, RISK_LEVEL_LEN, "%d", iRiskLevel); + + *rep_argc = 2; + *rep_argv = (char **) malloc(sizeof(char*) * (*rep_argc)); + if (*rep_argv == NULL) + { + DINFO("%s", "realloc returns Error for reply pointer array\n"); + free(szRiskLevel); + *rep_argc = 1; + iRes = TWP_NOMEM; + goto close_library; + } + + //Assign Risk Level + (*rep_argv)[1] = szRiskLevel; + + // Assign redirect url if RiskLevel is greater than or equal to TWP_Medium + if (iRiskLevel >= TWP_Medium) + { + *rep_argc = 3; + *rep_argv = (char **) realloc(*rep_argv, sizeof(char*) * (*rep_argc)); + if (*rep_argv == NULL) + { + DINFO("%s", "realloc returns Error for reply pointer array\n"); + free(szRiskLevel); + *rep_argc = 1; + iRes = TWP_NOMEM; + goto close_library; + } + (*rep_argv)[2] = pBlkUrl; + } + } + +close_library: + // Compose the return value. + // Convert iRes to String. + szRes = (char *) malloc(sizeof(char) * RETURN_STATUS_STR_LEN); + if (szRes == NULL) + { + DERR("%s", "malloc returns error\n"); + goto err; + } + snprintf(szRes, RETURN_STATUS_STR_LEN, "%d", iRes); + + if (*rep_argc == 1) + { + *rep_argv = (char **) malloc (sizeof(char*) * 1); + if (*rep_argv == NULL) + goto err; + } + //Assign Result code + (*rep_argv)[0] = szRes; + + TWPUninitLibrary(hLib); + return 0; + +err: + if (*rep_argv != NULL) + { + free((*rep_argv)[1]); + free((*rep_argv)[2]); + } + *rep_argc = 0; + free(*rep_argv); + *rep_argv = NULL; + rep_argv = NULL; + free(szRes); + TWPUninitLibrary(hLib); + return -1; +} + +int +main(int argc, char **argv) +{ +#ifndef DEBUG + fork_daemon(); +#endif + + TSC_SERVER_HANDLE hServer; + + if ((hServer = IpcServerOpen(TSC_DBUS_SERVER_WP_CHANNEL)) != NULL) + { + DINFO("%s", "successfully opened server \n"); + + // Register methods for get url reputation + IpcServerMethod method_1; + snprintf(method_1.szMethod, sizeof(method_1.szMethod), "%s", "TWPSerGetURLReputation"); + method_1.method = (METHODFUNC) TWPSerGetURLReputation; + method_1.pData = NULL; + + if (IpcServerAddMethod(hServer, &method_1) != 0) + { + DERR("%s", "unable to add method TWPSerGetURLReputation\n"); + goto close_server; + } + + // Register methods for getversion + IpcServerMethod method_2; + snprintf(method_2.szMethod, sizeof(method_2.szMethod), "%s", "TWPSerGetVersion"); + method_2.method = (METHODFUNC) TWPSerGetVersion; + method_2.pData = NULL; + + if (IpcServerAddMethod(hServer, &method_2) != 0) + { + DERR("%s", "unable to add method TWPSerGetVersion\n"); + goto close_server; + } + + // Daemon waits here for request from clients. + IpcServerMainLoop(hServer); + + IpcServerClose(&hServer); + } + else + { + DFATAL("%s", "unable to open server connection \n"); + goto err; + } + + return 0; + +close_server: + IpcServerClose(&hServer); + +err: + DFATAL("%s", "Unable to start the Daemon \n"); + return -1; +} diff --git a/framework/TWPSerDaemon.h b/framework/TWPSerDaemon.h new file mode 100644 index 0000000..9211ce0 --- /dev/null +++ b/framework/TWPSerDaemon.h @@ -0,0 +1,95 @@ +/* + Copyright (c) 2014, McAfee, Inc. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + Neither the name of McAfee, Inc. nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef TWPSERDAEMON_H +#define TWPSERDAEMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file TWPSerDaemon.h + * \brief TWP Server Daemon Header file. + * + * This file has the function prototypes. + * These functions should not be called directly but instead through IpcClient.h APIs + */ + +#include "IpcServer.h" + +#define TWP_DAEMON_VERSION "1.0.0" + +/*================================================================================================== + FUNCTION PROTOTYPES +==================================================================================================*/ +/** + * \brief handler method to get the version information. + * This will be called by IpcServer library with the following input/output params. + * This can be both synchronous and asynchronous API. + * + * \param[in] pData - contextual data. + * \param[in] req_argc - set to 0. + * \param[in] req_argv - set to null. + * \param[out] rep_argc - set to 0, 1 or 4. + * \param[out] rep_argv - contains 0, 1 or 4 strings for result code, framework version, plugin version, daemon version. + * \param[in] callback - method callback. + * \param[in] handle - handler. + * \return Return Type (int) \n + */ +int TWPSerGetVersion(void *pData, int req_argc, char **req_argv, char ***rep_argv, int *rep_argc, + CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle); + +/** + * \brief handler method to get the URL Reputation. + * This will be called by IpcServer library with the following input/output params. + * This can be both synchronous and asynchronous API. + * + * \param[in] pData - contextual data. + * \param[in] req_argc - set to 1. + * \param[in] req_argv - set to the URL required to check reputation. + * + * \param[out] rep_argc - set to 0, 1, 2 or 3. + * \param[out] rep_argv - contains 0, 1, 2 or 3 strings, first is the result code, second is the risklevel, third is the redirect URL. + * redirect URL is returned only if risk level is greater than or equal to TWP_Medium. + * \param[in] callback - method callback. + * \param[in] handle - handler. + * \return Return Type (int) \n + */ +int TWPSerGetURLReputation(void *pData, int req_argc, char **req_argv, char ***rep_argv, int *rep_argc, + CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle); + + +#ifdef __cplusplus +} +#endif + +#endif /* TWPSERDAEMON_H */ diff --git a/packaging/com.tsc.ipc.server.plugin.conf b/packaging/com.tsc.ipc.server.plugin.conf new file mode 100644 index 0000000..0be2c8d --- /dev/null +++ b/packaging/com.tsc.ipc.server.plugin.conf @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/packaging/com.tsc.ipc.server.wp.conf b/packaging/com.tsc.ipc.server.wp.conf new file mode 100644 index 0000000..a97c7d6 --- /dev/null +++ b/packaging/com.tsc.ipc.server.wp.conf @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/packaging/csf-framework.spec b/packaging/csf-framework.spec index dc42cc3..df1e688 100644 --- a/packaging/csf-framework.spec +++ b/packaging/csf-framework.spec @@ -7,8 +7,14 @@ Group: Security/Libraries URL: http://tizen.org Source: %{name}-%{version}.tar.gz Source1001: csf-framework.manifest +Source1002: com.tsc.ipc.server.plugin.conf +Source1003: com.tsc.ipc.server.wp.conf +Source1004: tpcsserdaemon.service +Source1005: twpserdaemon.service BuildRequires: pkgconfig(libtzplatform-config) +BuildRequires: pkgconfig(dbus-glib-1) BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(libxml-2.0) %description A general purpose content screening and reputation solution. @@ -24,12 +30,43 @@ Development files %prep %setup -q cp %{SOURCE1001} . +cp %{SOURCE1002} . +cp %{SOURCE1003} . +cp %{SOURCE1004} . +cp %{SOURCE1005} . %build + +# Build Framework Library make -C framework -f Makefile all VERSION=%version PREFIX=%_prefix +# Build IPC Client Library +make -C framework -f Makefile_channel_client all + +# Build IPC Server Library +make -C framework -f Makefile_channel_server all + +# Build Plugin Control Service +make -C framework -f Makefile_TPCSSerDaemon all + +# Build Web Protection Control Service +make -C framework -f Makefile_TWPSerDaemon all + %install rm -rf %{buildroot} +mkdir -p %{buildroot}%{_bindir} +mkdir -p %{buildroot}%{_libdir} +mkdir -p %{buildroot}%{_unitdir} +mkdir -p %{buildroot}/%{_sysconfdir}/dbus-1/system.d +install -D framework/lib/libscclient.so %{buildroot}%{_libdir}/ +install -D framework/lib/libscserver.so %{buildroot}%{_libdir}/ +install -D framework/bin/TPCSSerDaemon %{buildroot}%{_bindir}/ +install -D framework/bin/TWPSerDaemon %{buildroot}%{_bindir}/ +install -m0644 %{SOURCE1002} %{buildroot}%{_sysconfdir}/dbus-1/system.d/ +install -m0644 %{SOURCE1003} %{buildroot}%{_sysconfdir}/dbus-1/system.d/ +install -m0644 %{SOURCE1004} %{buildroot}%{_unitdir} +install -m0644 %{SOURCE1005} %{buildroot}%{_unitdir} + mkdir -p %buildroot%_includedir/csf mkdir -p %buildroot%_libdir/pkgconfig @@ -38,14 +75,47 @@ make install -C framework \ HEADER_DESTDIR=%buildroot%_includedir/csf \ VERSION=%version -%post -p /sbin/ldconfig +%post +/sbin/ldconfig +systemctl daemon-reload +if [ $1 = 1 ]; then + systemctl restart tpcsserdaemon.service + systemctl restart twpserdaemon.service + systemctl enable tpcsserdaemon.service -q + systemctl enable twpserdaemon.service -q +fi + +%preun +if [ $1 = 0 ]; then + systemctl stop tpcsserdaemon.service + systemctl stop twpserdaemon.service + systemctl disable tpcsserdaemon.service -q + systemctl disable twpserdaemon.service -q +fi -%postun -p /sbin/ldconfig +%postun +/sbin/ldconfig +if [ $1 = 0 ]; then + systemctl daemon-reload +fi +rm -fr /usr/bin/tpcs_config.dtd +rm -fr /usr/bin/tpcs_config.xml %files %manifest %{name}.manifest %license LICENSE +%defattr(-,root,root,-) %{_libdir}/libsecfw.so.* +%{_libdir}/libscclient.so +%{_libdir}/libscserver.so +%defattr(0755,root,root) +%{_bindir}/TPCSSerDaemon +%{_bindir}/TWPSerDaemon +%defattr(0644,root,root) +%config %{_sysconfdir}/dbus-1/system.d/com.tsc.ipc.server.plugin.conf +%config %{_sysconfdir}/dbus-1/system.d/com.tsc.ipc.server.wp.conf +%{_unitdir}/tpcsserdaemon.service +%{_unitdir}/twpserdaemon.service %files devel %_includedir/csf/TCSErrorCodes.h diff --git a/packaging/tpcsserdaemon.service b/packaging/tpcsserdaemon.service new file mode 100644 index 0000000..db91ec1 --- /dev/null +++ b/packaging/tpcsserdaemon.service @@ -0,0 +1,11 @@ +[Unit] +Description=CSF Tizen Plugin Control Service Daemon (TPCSSerDaemon) + +[Service] +Type=dbus +ExecStart=/usr/bin/TPCSSerDaemon +BusName=com.tsc.ipc.server.plugin +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/packaging/twpserdaemon.service b/packaging/twpserdaemon.service new file mode 100644 index 0000000..815da09 --- /dev/null +++ b/packaging/twpserdaemon.service @@ -0,0 +1,11 @@ +[Unit] +Description=CSF Tizen Web Protection Service Daemon (TWPSerDaemon) + +[Service] +Type=dbus +ExecStart=/usr/bin/TWPSerDaemon +BusName=com.tsc.ipc.server.wp +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/test/scripts/MfeTPCSSerDaemonToEmul.sh b/test/scripts/MfeTPCSSerDaemonToEmul.sh new file mode 100755 index 0000000..6d047a2 --- /dev/null +++ b/test/scripts/MfeTPCSSerDaemonToEmul.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +. ./scripts/PrepareForEmul.sh +#export TCS_CFG="debug" + +echo -e "\nbuilding security channel CLIENT..." +pushd ../framework +make -f Makefile_channel_client clean +make -f Makefile_channel_client + +echo -e "\nbuilding security channel SERVER..." +make -f Makefile_channel_server clean +make -f Makefile_channel_server + +echo -e "\nbuilding TPCS Ser Daemon..." +make -f Makefile_TPCSSerDaemon clean +make -f Makefile_TPCSSerDaemon +popd + +echo -e "\nbuilding test cases..." +pushd test_cases/tpcsserdaemon +make clean +make +popd + +echo -e "\ncleanup test files on device ..." +sdb -e root on +sdb -e shell rm -rf /tmp/tsc_test + +echo -e "\ncopying test files to device ..." +mkdir -p tsc_test/ +cp ../framework/lib/libscclient.so tsc_test/ +cp ../framework/lib/libscserver.so tsc_test/ +cp scripts/TPCSSerDaemonTest.sh tsc_test/Test.sh +cp test_cases/tpcsserdaemon/bin/tpcsserdaemontest tsc_test/ +cp ../framework/bin/TPCSSerDaemon tsc_test/TPCSSerDaemon + +sdb -e push tsc_test /tmp/tsc_test +sdb -e push test_cases/q7097a278m /opt/usr/apps/q7097a278m +sdb -e push test_cases/u7097a278m /opt/usr/apps/u7097a278m +sdb -e push test_cases/n7097a278m /opt/usr/apps/n7097a278m +sdb -e push tsc_test/Test.sh /usr/bin/Test.sh + +echo -e "\n@@@@@@@@@@@@@@@@@@@@@@@@@@@" +echo "preparation is done, please login to your device and perform following instructions" +echo "sdb -e shell" +echo "cd /usr/bin" +echo "chmod +x Test.sh (optional)" +echo "./Test.sh" diff --git a/test/scripts/MfeTWPSerDaemonToEmul.sh b/test/scripts/MfeTWPSerDaemonToEmul.sh new file mode 100755 index 0000000..78ee2bb --- /dev/null +++ b/test/scripts/MfeTWPSerDaemonToEmul.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +. ./scripts/PrepareForEmul.sh +#export TCS_CFG="debug" + +echo -e "\nbuilding libsecfw.so..." +pushd ../framework +make clean; +make + +echo -e "\nbuilding security channel CLIENT..." +make -f Makefile_channel_client clean +make -f Makefile_channel_client + +echo -e "\nbuilding security channel SERVER..." +make -f Makefile_channel_server clean +make -f Makefile_channel_server + +echo -e "\nbuilding TWPSerDaemon..." +make -f Makefile_TWPSerDaemon clean +make -f Makefile_TWPSerDaemon +popd + +echo -e "\nbuilding libwpengine.so..." +pushd ../plugin +make clean +make +popd + +echo -e "\nbuilding test cases ..." +pushd test_cases/twpserdaemon +make clean +make +popd + +echo -e "\ncleanup test files on emulator ..." +sdb -e root on +sdb -e shell rm -rf /tmp/twpserdaemon_test + +echo -e "\ncopying test files to emulator ..." +mkdir -p twpserdaemon_test/ +cp ../framework/lib/libscclient.so twpserdaemon_test/ +cp ../framework/lib/libscserver.so twpserdaemon_test/ +cp ../framework/lib/libsecfw.so twpserdaemon_test/ +cp scripts/TWPSerDaemonTest.sh twpserdaemon_test/Test.sh +cp ../framework/bin/TWPSerDaemon twpserdaemon_test/ +cp test_cases/twpserdaemon/bin/twpserdaemontest twpserdaemon_test/ +cp test_cases/mfe-testcontents/.tcs.cfg twpserdaemon_test/ + +cp ../plugin/plugin_i386_release/libwpengine.so twpserdaemon_test/ + +sdb -e push twpserdaemon_test /tmp/twpserdaemon_test + +# push Test.sh to /usr/bin +sdb -e push scripts/TWPSerDaemonTest.sh /usr/bin/Test.sh + +echo -e "\n@@@@@@@@@@@@@@@@@@@@@@@@@@@" +echo "preparation is done, please login to the emulator and perform following instructions" +echo "sdb -e shell" +echo "cd /usr/bin/" +echo "chmod +x Test.sh (optional)" +echo "./Test.sh" \ No newline at end of file diff --git a/test/scripts/TPCSSerDaemonTest.sh b/test/scripts/TPCSSerDaemonTest.sh new file mode 100755 index 0000000..d54fb43 --- /dev/null +++ b/test/scripts/TPCSSerDaemonTest.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +#echo EmbkcJFK7q > /proc/$$/attr/current +killall TPCSSerDaemon +killall tpcsserdaemontest +killall TWPSerDaemon +killall twpserdaemontest + +echo "copying test plug-in ..." +#export LD_LIBRARY_PATH=$PWD +cp -f /tmp/tsc_test/libscclient.so /usr/lib/ +cp -f /tmp/tsc_test/libscserver.so /usr/lib/ +cp -f /tmp/tsc_test/TPCSSerDaemon /usr/bin/ +cp -f /tmp/tsc_test/tpcsserdaemontest /usr/bin/ + +echo "setup environment ..." +#mkdir testcontents-1 +#export TWP_CONTENT_PATH=testcontents-1 + +echo "Do following to run the test cases ..." +echo "cd /usr/bin/" +echo "./tpcsserdaemontest" + + +#echo "cleanup test contents ..." +#rm -rf testcontents-1 + diff --git a/test/scripts/TWPSerDaemonTest.sh b/test/scripts/TWPSerDaemonTest.sh new file mode 100755 index 0000000..88f5860 --- /dev/null +++ b/test/scripts/TWPSerDaemonTest.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +#echo EmbkcJFK7q > /proc/$$/attr/current + +killall TWPSerDaemon +killall twpserdaemontest +killall TPCSSerDaemon +killall tpcsserdaemontest + +echo "copying test plug-in ..." +#export LD_LIBRARY_PATH=$PWD +cp -f /tmp/twpserdaemon_test/libscclient.so /usr/lib/ +cp -f /tmp/twpserdaemon_test/libscserver.so /usr/lib/ +cp -f /tmp/twpserdaemon_test/libsecfw.so /usr/lib/ +cp -f /tmp/twpserdaemon_test/TWPSerDaemon /usr/bin/ +cp -f /tmp/twpserdaemon_test/twpserdaemontest /usr/bin/ + +mkdir -p /opt/usr/share/sec_plugin +cp -f /tmp/twpserdaemon_test/libwpengine.so /opt/usr/share/sec_plugin/ +mkdir -p /opt/usr/apps/EmbkcJFK7q/data/database +cp -f /tmp/twpserdaemon_test/.tcs.cfg /opt/usr/apps/EmbkcJFK7q/data/ +echo "setup environment ..." +#mkdir testcontents-1 +#export TWP_CONTENT_PATH=testcontents-1 + +echo "Do following to run the test cases ..." +echo "cd /usr/bin/" +echo "./twpserdaemontest" +#echo "end of test cases ..." + +#echo "cleanup test contents ..." +#rm -rf testcontents-1 +