2 Copyright (c) 2014, McAfee, Inc.
6 Redistribution and use in source and binary forms, with or without modification,
7 are permitted provided that the following conditions are met:
9 Redistributions of source code must retain the above copyright notice, this list
10 of conditions and the following disclaimer.
12 Redistributions in binary form must reproduce the above copyright notice, this
13 list of conditions and the following disclaimer in the documentation and/or other
14 materials provided with the distribution.
16 Neither the name of McAfee, Inc. nor the names of its contributors may be used
17 to endorse or promote products derived from this software without specific prior
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 OF THE POSSIBILITY OF SUCH DAMAGE.
34 * \brief Ipc Server Source File
36 * This file implements the IPC Server API functions used by Security framework.
48 #include "IpcMacros.h"
49 #include "IpcServerError.h"
50 #include "IpcServerHdr.h"
51 #include "TSCErrorCodes.h"
55 #define DBUS_D_LOG(_dbusErr_, _fmt_, _param_...) \
57 DDBG("%s:%s; " _fmt_, _dbusErr_.name, _dbusErr_.message, _param_); \
60 #define DBUS_D_LOG(_dbusErr_, _fmt_, _param_...)
63 static void IterateList(IpcMethodHandle* pHandle)
67 for(ph = pHandle; ph != NULL; ph = ph->pNext)
71 DDBG(".....total count: %d\n", count);
74 inline DBusHandlerResult _IpcSendMessageAndUnref(DBusConnection *pConn, DBusMessage *pMsg)
77 dbus_connection_send(pConn, pMsg, NULL);
78 dbus_message_unref(pMsg);
80 return DBUS_HANDLER_RESULT_HANDLED;
83 void _FreeHandleMethods(IpcServerInfo *pInfo)
89 IpcServerMethodList *pCurr = pInfo->pMethodList;
90 IpcServerMethodList *pPrev = NULL;
92 pthread_mutex_lock(&(pInfo->Lock));
100 /* TODO: Explain why its not leak for non-cancel methods. */
101 //if (pPrev->pMethod->method == (METHODFUNC)IpcCancelMethod || pPrev->pMethod->method == (METHODFUNC)IpcGetProgressMethod)
102 free(pPrev->pMethod);
104 pPrev->pMethod = NULL;
108 pInfo->pMethodList = NULL;
109 pInfo->pRunningMethods = NULL;
110 pthread_mutex_unlock(&(pInfo->Lock));
114 void _FreeHandlePool(IpcServerInfo *pInfo)
119 while(IpcThrPoolIdleCount(pInfo->pHandlePool) != TSC_THREAD_POOL_NUMBERS && IpcThrPoolIdleCount(pInfo->pHandlePool) != -1) //wait till no detachable thread is running
121 // TODO: Use condition instead of infinite loop
124 pthread_mutex_lock(&(pInfo->Lock));
126 if (pInfo->pHandlePool)
128 IpcThrPoolFree(&pInfo->pHandlePool);
131 pthread_mutex_unlock(&(pInfo->Lock));
134 void _FreeHandleTable(IpcServerInfo *pInfo)
139 pthread_mutex_lock(&(pInfo->Lock));
143 pInfo->pTable = NULL;
145 pthread_mutex_unlock(&(pInfo->Lock));
148 void _FreeHandleConn(IpcServerInfo *pInfo)
153 pthread_mutex_lock(&(pInfo->Lock));
156 dbus_connection_remove_filter(pInfo->pConn, _IpcServerMsgFilter, pInfo);
159 pthread_mutex_unlock(&(pInfo->Lock));
163 void _WaitForListenThreadClose(IpcServerInfo *pInfo)
165 if (pInfo && pInfo->lDbus_listen_thread)
167 pthread_mutex_lock(&(pInfo->Lock));
168 pInfo->start_server_flag = false;
169 pthread_mutex_unlock(&(pInfo->Lock));
171 if (pInfo->lDbus_listen_thread)
172 pthread_join(pInfo->lDbus_listen_thread, NULL);
176 int IpcServerAddMethod(TSC_SERVER_HANDLE hServer, IpcServerMethod *pMethod)
178 IpcServerInfo *pInfo = NULL;
179 IpcServerMethodList *pList = NULL;
180 int r = TSC_ERROR_ADD_METHOD_FAILED;
182 if (INVALID_TSC_SERVER_HANDLE == hServer)
185 pList = calloc(1, sizeof(IpcServerMethodList));
189 IpcServerMethod* tpMethod = calloc(1, sizeof(IpcServerMethod));
190 if (tpMethod == NULL)
198 tpMethod->method = pMethod->method;
199 strncpy(tpMethod->szMethod, pMethod->szMethod, TSC_METHOD_NAME_LEN-1);
200 tpMethod->pData = pMethod->pData;
202 pInfo = (IpcServerInfo *) hServer;
204 pthread_mutex_lock(&(pInfo->Lock));
205 pList->pNext = pInfo->pMethodList;
207 //pList->pMethod = pMethod;
208 pList->pMethod = tpMethod;
210 pInfo->pMethodList = pList;
211 pthread_mutex_unlock(&(pInfo->Lock));
217 int IpcServerRemoveMethod(TSC_SERVER_HANDLE hServer, METHODFUNC method)
219 IpcServerInfo *pInfo = NULL;
220 IpcServerMethodList **pPrev = NULL;
221 IpcServerMethodList *pCurr = NULL;
222 int r = TSC_ERROR_REMOVE_METHOD_NOT_FOUND;
224 DDBG("%s\n", "IpcServerRemoveMethod");
225 if (INVALID_TSC_SERVER_HANDLE == hServer)
228 pInfo = (IpcServerInfo *) hServer;
230 // Change the head to next node, if deleted.
231 pthread_mutex_lock(&(pInfo->Lock));
232 for (pPrev = &pInfo->pMethodList; *pPrev; pPrev = &(*pPrev)->pNext)
234 DDBG("REMOVE method list name :%s\n", (*pPrev)->pMethod->szMethod);
235 if ((*pPrev)->pMethod->method == method)
237 DDBG("==== FIND REVMOE MOETHOD %s\n", " ");
239 *pPrev = (*pPrev)->pNext;
244 pthread_mutex_unlock(&(pInfo->Lock));
246 // Release the found method now.
247 if (r == 0 && pCurr->pMethod)
249 free(pCurr->pMethod);
250 pCurr->pMethod = NULL;
257 TSC_SERVER_HANDLE IpcServerOpen(char *service_name)
259 DDBG("IpcServerOpen: %s\n", service_name);
262 if (!dbus_threads_init_default())
264 DDBG("failed dbus_threads_init_default %s\n", "");
268 dbus_error_init(&dberr);
270 if (!dbus_validate_bus_name(service_name, &dberr) && dbus_error_is_set(&dberr))
272 DDBG("it is invalid request name %s\n", "");
276 IpcServerInfo *pInfo;
277 if ((pInfo = (IpcServerInfo *) calloc(1, sizeof(IpcServerInfo))) == NULL)
280 pInfo->pMethodList = NULL;
282 if ((pInfo->pTable = (DBusObjectPathVTable *) calloc(1, sizeof(DBusObjectPathVTable))) == NULL)
285 pInfo->lDbus_listen_thread = 0;
286 strncpy(pInfo->name, service_name, TSC_SERVER_NAME_LEN - 1);
288 if (_IpcServerInit(pInfo, service_name))
290 DDBG("IpcServerInit failed: %s\n", service_name);
294 //DDBG("IpcServerOpen success conn:%s\n", pInfo->name);
295 dbus_error_free(&dberr);
296 return (TSC_SERVER_HANDLE) pInfo;
299 SAFE_FREE(pInfo->pTable);
302 DDBG("IpcServerOpen free_info, conn:%s\n", pInfo->name);
306 dbus_error_free(&dberr);
309 return INVALID_TSC_SERVER_HANDLE;
312 int IpcServerMainLoop(TSC_SERVER_HANDLE hServer)
314 IpcServerInfo *pInfo = (IpcServerInfo*) hServer;
317 if (pInfo->lDbus_listen_thread)
319 pthread_join(pInfo->lDbus_listen_thread, NULL);
320 DDBG("finsihed main loop:%s\n", "==========");
326 void IpcServerClose(TSC_SERVER_HANDLE *hServer)
328 IpcServerInfo *pInfo = (IpcServerInfo *) *hServer;
329 if (pInfo != (IpcServerInfo*)INVALID_TSC_SERVER_HANDLE)
331 DDBG("IpcServerClose:%s\n", pInfo->name);
332 _WaitForListenThreadClose(pInfo);
334 // Wait till no detachable thread is running
335 while (IpcThrPoolIdleCount(pInfo->pHandlePool) != TSC_THREAD_POOL_NUMBERS && IpcThrPoolIdleCount(pInfo->pHandlePool) != -1)
337 // TODO: Use conditional mutex.
341 _FreeHandleTable(pInfo);
342 _FreeHandleMethods(pInfo);
343 _FreeHandlePool(pInfo);
344 _FreeHandleConn(pInfo);
345 pthread_mutex_destroy(&(pInfo->Lock));
348 *hServer = INVALID_TSC_SERVER_HANDLE;
353 int _IpcServerInit(IpcServerInfo *pInfo, char *szServiceName)
355 IpcServerMethod *pMethodCancel = NULL;
362 pInfo->pMethodList = NULL;
363 pInfo->pRunningMethods = NULL;
364 pInfo->start_server_flag = false;
366 dbus_error_init(&dberr);
368 pInfo->pConn = dbus_bus_get(DBUS_BUS_SYSTEM, &dberr);
369 if (pInfo->pConn == NULL && dbus_error_is_set(&dberr))
371 DBUS_D_LOG(dberr, "%s\n", "Server failed: connection NULL.");
375 ret = dbus_bus_request_name(pInfo->pConn, szServiceName, DBUS_NAME_FLAG_REPLACE_EXISTING, &dberr);
376 if (ret == -1 && dbus_error_is_set(&dberr))
378 DBUS_D_LOG(dberr, "%s\n", "server failed: request name.");
382 // TODO: Why not allow DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER also?
383 if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
385 DDBG("server failed: Not primary owner :%d\n", ret);
389 if (0 > snprintf(pInfo->rule, sizeof(pInfo->rule), "type='method_call', interface='%s'",
392 DDBG("%s\n", "server failed: Unable to write rule");
396 dbus_bus_add_match(pInfo->pConn, pInfo->rule, &dberr);
397 if (dbus_error_is_set(&dberr))
399 DBUS_D_LOG(dberr, "%s\n", "Match add failed.");
403 if (!dbus_connection_try_register_object_path(pInfo->pConn, TSC_DBUS_PATH, pInfo->pTable,
405 && dbus_error_is_set(&dberr))
407 DBUS_D_LOG(dberr, "%s\n", "server failed: register object path");
411 dbus_connection_set_exit_on_disconnect(pInfo->pConn, false);
413 if (!dbus_connection_add_filter(pInfo->pConn, _IpcServerMsgFilter, pInfo, NULL))
415 DDBG("%s\n", "server failed: add filter.");
419 if (!dbus_connection_get_unix_fd(pInfo->pConn, &pInfo->fd) || pInfo->fd < 0)
421 DDBG("%s\n", "server failed: get fd.");
425 pInfo->pHandlePool = calloc(1, sizeof(IpcHandlePool));
426 if (pInfo->pHandlePool == NULL)
428 DDBG("%s\n", "Thread pool alloc failed.");
432 ret = IpcThrPoolInit(pInfo->pHandlePool, TSC_THREAD_POOL_NUMBERS);
435 DDBG("%s\n", "*****Failed in IpcThrPoolInit");
439 ret = pthread_mutex_init(&(pInfo->Lock), NULL);
442 DDBG("Failed to init IpcServerInfo lock %d\n", ret);
446 // Add default two methods: Cancel and GetStatus
447 pMethodCancel = calloc(1, sizeof(IpcServerMethod));
448 if (pMethodCancel == NULL)
450 DDBG("%s\n", "Cancel alloc failed.");
454 ret = snprintf(pMethodCancel->szMethod, sizeof(pMethodCancel->szMethod), "%s", TSC_FN_CANCELMETHOD);
457 DDBG("%s\n", "Cancel create failed.");
458 goto free_method_cancel;
461 pMethodCancel->method = (METHODFUNC) IpcCancelMethod;
462 pMethodCancel->pData = NULL;
463 ret = IpcServerAddMethod((TSC_SERVER_HANDLE) pInfo, pMethodCancel);
466 DDBG("%s\n", "Cancel add failed.");
467 goto free_method_cancel;
470 IpcServerMethod *pMethodProgress = calloc(1, sizeof(IpcServerMethod));
471 if (pMethodProgress == NULL)
473 DDBG("%s\n", "Progress alloc failed.");
474 goto free_method_cancel;
477 ret = snprintf(pMethodProgress->szMethod, sizeof(pMethodProgress->szMethod), "%s", TSC_FN_PROGRESSMETHOD);
480 DDBG("%s\n", "Progress create failed.");
481 goto free_method_progress;
484 pMethodProgress->method = (METHODFUNC) IpcGetProgressMethod;
485 pMethodProgress->pData = NULL;
487 ret = IpcServerAddMethod((TSC_SERVER_HANDLE) pInfo, pMethodProgress);
490 DDBG("%s\n", "Progress add failed.");
491 goto free_method_progress;
494 IpcServerMethod *pMethodShutdown = calloc(1, sizeof(IpcServerMethod));
495 if (pMethodShutdown == NULL)
497 DDBG("%s\n", "shutdown alloc failed.");
498 goto free_method_progress;
501 ret = snprintf(pMethodShutdown->szMethod, sizeof(pMethodShutdown->szMethod), "%s", TSC_FN_SHUTDOWN);
504 DDBG("%s\n", "Shutdown create failed.");
505 goto free_method_shutdown;
508 pMethodShutdown->method = (METHODFUNC) IpcShutdown;
509 pMethodShutdown->pData = NULL;
511 ret = IpcServerAddMethod((TSC_SERVER_HANDLE) pInfo, pMethodShutdown);
514 DDBG("%s\n", "Shutdown add failed.");
515 goto free_method_shutdown;
517 SAFE_FREE(pMethodShutdown);
518 SAFE_FREE(pMethodProgress);
519 SAFE_FREE(pMethodCancel);
521 pthread_mutex_lock(&(pInfo->Lock));
523 ret = pthread_create(&(pInfo->lDbus_listen_thread), NULL, _IpcPopMessage, (void *)pInfo);
524 DDBG("Creating thrd for Server: %s\n", pInfo->name);
528 DDBG("%s(%d)\n", "** FAILED to launch thread", ret);
529 pInfo->start_server_flag = false;
530 pthread_mutex_unlock(&(pInfo->Lock));
533 pInfo->start_server_flag = true;
535 pthread_mutex_unlock(&(pInfo->Lock));
538 free_method_shutdown:
539 SAFE_FREE(pMethodShutdown);
540 free_method_progress:
541 SAFE_FREE(pMethodProgress);
543 SAFE_FREE(pMethodCancel);
545 pthread_mutex_destroy(&(pInfo->Lock));
548 if (pInfo->pHandlePool)
549 IpcThrPoolFree(&pInfo->pHandlePool);
551 //dbus_connection_remove_filter(pInfo->pConn, _IpcServerMsgFilter, pInfo);
553 //dbus_connection_unregister_object_path(pInfo->pConn, TSC_DBUS_PATH);
555 //dbus_bus_remove_match(pInfo->pConn, pInfo->rule, &dberr);
557 //dbus_connection_close(pInfo->pConn); TODO: Why not????
559 dbus_error_free(&dberr);
560 DDBG("%s", "_IpcServerInit free_err before return -1\n");
565 void _IpcServerDeInit(TSC_SERVER_HANDLE hServer)
567 DDBG("%s\n", "IpcServerDeInit========");
568 IpcServerInfo *pInfo = (IpcServerInfo *) hServer;
571 if (pInfo->lDbus_listen_thread)
573 pthread_join(pInfo->lDbus_listen_thread, NULL);
575 FreeIpcServerHandle((TSC_SERVER_HANDLE) pInfo);
577 //dbus_shutdown(); // for valgrind only
578 DDBG("%s\n", "*_*_*_*_*_*_* Server is disconnected *_*_*_*_*_*_*_*_*");
582 DBusHandlerResult _IpcServerReplyMessage(DBusConnection *pConn, DBusMessage *pMsg,
583 char **pReply, int size)
585 DDBG("%s %d\n", "ReplyMessage size: ", size);
586 DBusMessage *pReplyMsg = NULL;
587 DBusMessageIter iter;
591 return DBUS_HANDLER_RESULT_HANDLED;
593 pReplyMsg = dbus_message_new_method_return(pMsg);
595 if (pReplyMsg == NULL)
596 return DBUS_HANDLER_RESULT_NEED_MEMORY;
598 dbus_message_iter_init_append(pReplyMsg, &iter);
600 for (i = 0; i < size; i++)
602 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &(pReply[i])))
604 DDBG("----- Replied string :%s\n", pReply[i]);
605 dbus_message_unref(pReplyMsg);
606 return DBUS_HANDLER_RESULT_NEED_MEMORY;
610 return _IpcSendMessageAndUnref(pConn, pReplyMsg);
613 DBusHandlerResult _IpcServerReplyError(DBusConnection *pConn, DBusMessage *pMsg,
616 DDBG("%s\n", "IpcServerReplyError");
617 DBusMessage *pErrMsg = NULL;
620 return DBUS_HANDLER_RESULT_HANDLED;
622 pErrMsg = dbus_message_new_error(pMsg, GetErrorName(iErrCode), GetErrorDescription(iErrCode));
624 return DBUS_HANDLER_RESULT_NEED_MEMORY;
626 return _IpcSendMessageAndUnref(pConn, pErrMsg);
630 DBusHandlerResult _IpcServerMsgFilter(DBusConnection *pConn, DBusMessage *pMsg, void *pData)
632 DDBG("%s\n", "IpcServerMsgFilter");
633 IpcServerInfo *pInfo = (IpcServerInfo*) pData;
636 DDBG("%s\n", "not handled the server info");
637 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
639 else if (dbus_message_is_signal(pMsg, DBUS_INTERFACE_LOCAL, "Disconnected"))
641 DDBG("%s\n", "server is disconnected by signal");
642 IpcServerClose((TSC_SERVER_HANDLE*) pInfo);
643 //return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
644 return DBUS_HANDLER_RESULT_HANDLED;
647 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
651 DBusHandlerResult _IpcServerMsgHandler(void *user_data)
653 DBusHandlerResult ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
654 IpcAsyncInfo *pAsync = user_data;
658 DBusMessage *pMsg = pAsync->pMsg;
659 IpcServerInfo *pInfo = pAsync->pInfo;
661 bool handle_flag = false;
664 DDBG("==IpcServerMsgHandler:%s\n", pInfo->name);
665 IpcServerMethodList **pPrev;
666 pthread_mutex_lock(&(pInfo->Lock));
667 for (pPrev = &pInfo->pMethodList; *pPrev; pPrev = &(*pPrev)->pNext)
669 if ((*pPrev) && (*pPrev)->pMethod)
671 if (dbus_message_is_method_call(pMsg, TSC_DBUS_INTERFACE, (*pPrev)->pMethod->szMethod)){
672 DDBG("FOUND method: %s\n", (*pPrev)->pMethod->szMethod);
674 pAsync->pMethod = (*pPrev)->pMethod;
679 pthread_mutex_unlock(&(pInfo->Lock));
682 return _IpcServerProcessMessage(pAsync);
685 if (ret == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
687 if (pAsync->pInfo->pHandlePool)
689 IpcThrPoolPut(pAsync->pInfo->pHandlePool, pAsync->pHandle);
691 CleanupAsync(pAsync);
699 int _ParseDBusMessage(DBusMessage *pMsg, int *pargc, char ***argv)
701 DBusBasicValue temp = {{0}};
703 int iSize = TSC_REPLY_MSG_COUNT_AVERAGE;
704 DBusMessageIter iter;
705 int iRet = TSC_ERROR_NOT_IMPLEMENTED; // Return as result of method requested by client.
707 if (dbus_message_iter_init(pMsg, &iter))
711 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
713 DDBG("%s\n", "wrong type");
716 iRet = TSC_ERROR_NOT_IMPLEMENTED;
719 dbus_message_iter_get_basic(&iter, &temp);
722 DDBG("%s\n", "no string");
723 iRet = TSC_ERROR_INTERNAL;
729 iSize += TSC_REPLY_MSG_COUNT_AVERAGE;
730 (*argv) = realloc((*argv), sizeof(char*) * iSize);
734 DDBG("PARSE message, insufficient: 7-1, argc:%d iSize:%d\n", argc, iSize);
735 iRet = TSC_ERROR_INSUFFICIENT_RES;
736 iSize = iSize - TSC_REPLY_MSG_COUNT_AVERAGE;
742 (*argv) = calloc(1, iSize * sizeof(char *));
745 iRet = TSC_ERROR_INSUFFICIENT_RES;
746 iSize = 0; //reset iSize, used to free the memory
751 (*argv)[argc] = strdup((const char*)temp.str);
755 DDBG("not engough memory: %s\n", "4");
756 iRet = TSC_ERROR_INSUFFICIENT_RES;
760 } while (dbus_message_iter_next(&iter));
762 iRet = 0; // TODO: Is this the right place & code?
766 DDBG("%s\n", "Request message has no arguments");
779 for (i = 0; i < iSize; i++)
791 // Everything went well till now...
799 DBusHandlerResult _IpcServerProcessMessage(void *user_data)
801 DDBG("%s\n", "IpcServerProcessMessage");
802 IpcAsyncInfo *pAsync = user_data;
805 int iFreeMtdHandle = 0;
807 // int iErr = DBUS_HANDLER_RESULT_HANDLED; // Return the result to caller of this function.
808 int iRet = TSC_ERROR_MODULE_GENERIC; // Return as result of method requested by client.
809 IpcMethodHandle *pMtdHandle = NULL;
811 dbus_error_init(&dberr);
812 if (pAsync->pConn == NULL)
816 // Here when calling method, pass the callback function
817 pMtdHandle = calloc(1, sizeof(IpcMethodHandle));
819 if (pMtdHandle == NULL)
824 pMtdHandle->pMethod = pAsync->pMethod;
825 iRet = pthread_mutex_init(&(pMtdHandle->Lock), NULL);
834 if ((pAsync->pMethod)->method)
836 // insert to RunningMethods
837 if (pAsync->argv[0] == NULL)
842 strncpy(pMtdHandle->unique_id, pAsync->async_unique_id, MSGHANDLE_LEN);
843 (pMtdHandle->unique_id)[MSGHANDLE_LEN] = '\0';
845 pthread_mutex_lock(&pAsync->pInfo->Lock);
846 (pAsync->pInfo->count)++;
847 pMtdHandle->pNext = pAsync->pInfo->pRunningMethods;
848 pAsync->pInfo->pRunningMethods = pMtdHandle;
850 DDBG("============== after adding running method:%s\n", "------");
851 IterateList(pMtdHandle);
853 pthread_mutex_unlock(&pAsync->pInfo->Lock);
855 pMtdHandle->pInfo = pAsync->pInfo;
856 pMtdHandle->cStatus = "1";
857 pMtdHandle->iCancel = TSC_NON_CANCEL;
859 // Skip the first params which is for unique_id
860 DDBG("method to run:%s, argv[0]:%s\n", pAsync->pMethod->szMethod, pAsync->argv[0]);
862 iRet = (pAsync->pMethod)->method((pAsync->pMethod)->pData, pAsync->argc - 1,
863 &(pAsync->argv[1]), &reply, &len,
864 (CALLBACKFUNC) IpcServerCallbackMethod, pMtdHandle);
865 iRet = 0; //till here, able to run the method, it is success
871 _IpcServerReplyError(pAsync->pConn, pAsync->pMsg, TSC_ERROR_INTERNAL);
874 // Everything went well till now...
875 _IpcServerReplyMessage(pAsync->pConn, pAsync->pMsg, reply, len);
878 dbus_connection_flush(pAsync->pConn);
879 CleanupArray(&reply, len);
881 // Method finished, remove it from pInfo, running methods list
882 IpcMethodHandle **pmpPrev;
883 pthread_mutex_lock(&(pAsync->pInfo->Lock));
884 for (pmpPrev = &(pAsync->pInfo->pRunningMethods); *pmpPrev; pmpPrev = &((*pmpPrev)->pNext))
886 if (strncmp((*pmpPrev)->unique_id, pAsync->async_unique_id, MSGHANDLE_LEN) == 0)
888 *pmpPrev = (*pmpPrev)->pNext;
890 DDBG("FOUND method, and remove from running one, method:%s, uniquid:%s\n",
891 pAsync->pMethod->szMethod, pAsync->async_unique_id);
892 IterateList(pAsync->pInfo->pRunningMethods);
896 pthread_mutex_unlock(&(pAsync->pInfo->Lock));
898 IpcThrPoolPut(pAsync->pInfo->pHandlePool, pAsync->pHandle);
899 CleanupAsync(pAsync);
900 dbus_error_free(&dberr);
902 if (pMtdHandle && iFreeMtdHandle)
911 void *_IpcPopMessage(void *hServer)
913 IpcServerInfo *pInfo = (IpcServerInfo *) hServer;
914 DDBG("=IpcPopMessage:%s\n", pInfo->name);
917 while (pInfo != NULL && pInfo->pConn != NULL && pInfo->start_server_flag) {
919 // non blocking read of the next available message
920 dbus_connection_read_write(pInfo->pConn, 0);
921 DBusMessage *pMsg = dbus_connection_pop_message(pInfo->pConn);
924 sleep(TSC_READ_WRITE_DISPATCH_SLEEP_SECONDS);
929 // TODO: Strangely, first message needs to be processed, for the next N pending msgs
930 // to be picked up for asynchronous processing.
931 IpcHandles *pIpcHandle = IpcThrPoolGet(pInfo->pHandlePool);
932 IpcAsyncInfo *pAsync = calloc(1, sizeof(IpcAsyncInfo));
935 pAsync->pConn = pInfo->pConn;
936 pAsync->pInfo = pInfo;
940 pAsync->pHandle = pIpcHandle;
942 iRet = _ParseDBusMessage(pMsg, &(pAsync->argc), &(pAsync->argv));
946 iRet = snprintf(pAsync->async_unique_id, MSGHANDLE_LEN, TSC_MID_SVR_FORMAT, pAsync->argv[0],
947 dbus_message_get_serial(pAsync->pMsg));
948 //DDBG("ASYNC_UNQIEU-DI: %s\n", pAsync->async_unique_id);
952 iRet = _RunDetachedThread(_IpcServerMsgHandler, pAsync);
953 DDBG("====RunDetachedThread ret:%d\n", iRet);
958 IpcThrPoolPut(pInfo->pHandlePool, pIpcHandle);
959 CleanupAsync(pAsync);
965 DDBG("popmessage ended :%s\n", "============");
971 void CleanupArray(char*** pArr, int len)
985 void CleanupAsync(IpcAsyncInfo *pAsync)
989 CleanupArray(&(pAsync->argv), pAsync->argc);
991 dbus_message_unref(pAsync->pMsg);
1001 * reason_params is cleaned up within this method
1003 int IpcServerCallbackMethod(TSC_METHOD_HANDLE *pMHandle, TSC_METHOD_REASON_CODE iReason, void *reason_params)
1005 IpcMethodHandle *p_MHandle = (IpcMethodHandle *) pMHandle;
1006 char *data = reason_params;
1009 if (iReason == TSC_CANCEL)
1011 pthread_mutex_lock(&(p_MHandle->Lock));
1012 if (p_MHandle->iCancel == TSC_IS_CANCEL)
1015 DDBG("%s", "callback check, it is cancel true\n");
1017 pthread_mutex_unlock(&(p_MHandle->Lock));
1019 else if (iReason == TSC_PROGRESS)
1021 pthread_mutex_lock(&(p_MHandle->Lock));
1022 p_MHandle->cStatus = strdup(data); // TODO: any better way to update data?
1024 pthread_mutex_unlock(&(p_MHandle->Lock));
1033 /*void IpcCancelMethod(TSC_SERVER_HANDLE hServer, char *method_unique_id)*/
1034 int IpcCancelMethod(void *pData, int argc, char **argv, char ***szReply, int *len, CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
1040 DDBG("IpcCancelMethod unique_id %s\n", argv[0]);
1044 DDBG("%s\n", "Error params in cancel method");
1047 //TODO :error checking
1048 IpcMethodHandle *pMHandle = (IpcMethodHandle*) handle;
1049 IpcServerInfo *pInfo = (IpcServerInfo*) pMHandle->pInfo;
1050 // Get the running method by the method_unique_id, then set its cancel flag
1051 IpcMethodHandle **pmpPrev;
1055 //the argc should be 2, the second param is unique id of to cancel method
1058 pthread_mutex_lock(&(pInfo->Lock));
1060 for (pmpPrev = &(pInfo->pRunningMethods); *pmpPrev; pmpPrev = &((*pmpPrev)->pNext))
1062 DDBG("Method to cancel: %s, list method:%s\n", argv[0], (*pmpPrev)->unique_id);
1063 if (strcmp((*pmpPrev)->unique_id, argv[0]) == 0)
1065 DDBG("%s\n", "found the running method to cancel");
1066 pthread_mutex_lock(&(pMHandle->Lock));
1067 (*pmpPrev)->iCancel = TSC_IS_CANCEL;
1068 DDBG("%s %s\n", "set is cancel to true for this method: ", (*pmpPrev)->unique_id);
1069 //TODO: should we return something?
1071 *szReply = calloc(1, sizeof(char*) *(*len));
1072 (*szReply)[0] = strdup("0");
1073 pthread_mutex_unlock(&(pMHandle->Lock));
1077 pthread_mutex_unlock(&(pInfo->Lock));
1079 DDBG("%s\n", "END OF cancel method");
1086 IpcGetProgressMethod(void *pData, int argc, char **argv, char ***szReply, int *len, CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
1088 DDBG("%s\n", "IpcGetProgressMethod");
1089 IpcMethodHandle *pMHandle = (IpcMethodHandle*) handle;
1090 IpcServerInfo *pInfo = (IpcServerInfo*) pMHandle->pInfo;
1092 //TODO: Error handling, check argv argc
1093 //Here the running method finished, either end or cancelled.
1094 IpcMethodHandle **pmpPrev;
1095 for (pmpPrev = &(pInfo->pRunningMethods); *pmpPrev; pmpPrev = &((*pmpPrev)->pNext))
1097 DDBG("running methods unique id :%s, passing id :%s \n", (*pmpPrev)->unique_id, argv[0]);
1099 if (!strcmp((*pmpPrev)->unique_id, argv[0]))
1101 DDBG("=== found running method to get progress %s\n", argv[0]);
1102 // get the running method, update its status
1104 *szReply = calloc(1, sizeof(char*) * 10);
1105 DDBG("-- status to reply :%s\n",(*pmpPrev)->cStatus);
1106 (*szReply)[0] = strdup((*pmpPrev)->cStatus);
1114 IpcShutdown(void *pData, int argc, char **argv, char ***szReply, int *len, CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
1116 DDBG("==============%s\n", "IpcShutdownMethod");
1117 IpcMethodHandle *pMHandle = (IpcMethodHandle*) handle;
1118 IpcServerInfo *pInfo = (IpcServerInfo*) pMHandle->pInfo;
1120 pthread_mutex_lock(&(pInfo->Lock));
1121 pInfo->start_server_flag = false;
1122 pthread_mutex_unlock(&(pInfo->Lock));
1123 DDBG("end of shutdown:%s\n", "===================");
1128 void FreeIpcServerHandle(TSC_SERVER_HANDLE hServer)
1130 DDBG("%s\n", "FreeIpcServerHandle");
1131 IpcServerInfo *pInfo = (IpcServerInfo*) hServer;
1135 pthread_mutex_lock(&(pInfo->Lock));
1137 IpcServerMethodList *pCurr = pInfo->pMethodList;
1138 IpcServerMethodList *pPrev;
1143 pCurr = pCurr->pNext;
1144 DDBG("*****pPrev method is 0 :%s\n", pPrev->pMethod->szMethod);
1150 if (pPrev->pMethod->method == (METHODFUNC) IpcCancelMethod
1151 || pPrev->pMethod->method == (METHODFUNC) IpcGetProgressMethod
1152 || pPrev->pMethod->method == (METHODFUNC) IpcShutdown)
1154 free(pPrev->pMethod);
1156 pPrev->pMethod = NULL;
1160 pPrev->pNext = NULL;
1168 pInfo->pMethodList = NULL;
1169 pInfo->pRunningMethods = NULL;
1171 if (pInfo->pHandlePool)
1172 IpcThrPoolFree(&pInfo->pHandlePool);
1174 pthread_mutex_unlock(&(pInfo->Lock));
1176 pthread_mutex_destroy(&(pInfo->Lock));
1179 free(pInfo->pTable);
1180 pInfo->pTable = NULL;
1185 dbus_error_init(&dberr);
1187 dbus_connection_remove_filter(pInfo->pConn, _IpcServerMsgFilter, pInfo);
1188 dbus_connection_unregister_object_path(pInfo->pConn, TSC_DBUS_PATH);
1189 dbus_bus_remove_match(pInfo->pConn, pInfo->rule, &dberr);
1191 dbus_bus_release_name(pInfo->pConn, TSC_DBUS_SERVER, &dberr);
1193 dbus_connection_unref(pInfo->pConn);
1194 dbus_error_free(&dberr);
1196 pInfo->pConn = NULL;
1206 * Creates a thread for asynchronous task.
1207 * TODO: Merge with TCS module.
1209 int _RunDetachedThread(void *pfWorkerFunc, void *pThreadData)
1212 pthread_attr_t attr;
1217 if (pthread_attr_init(&attr) != 0)
1220 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
1224 if (pthread_create(&thread, &attr, pfWorkerFunc, pThreadData) != 0)
1227 if (pthread_attr_destroy(&attr) != 0)
1229 // As the thread is already running, return different error code.