Revert "Remove TPCS and TWPServer features"
[platform/upstream/csf-framework.git] / framework / IpcServer.c
1 /*
2     Copyright (c) 2014, McAfee, Inc.
3
4     All rights reserved.
5
6     Redistribution and use in source and binary forms, with or without modification,
7     are permitted provided that the following conditions are met:
8
9     Redistributions of source code must retain the above copyright notice, this list
10     of conditions and the following disclaimer.
11
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.
15
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
18     written permission.
19
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.
30 */
31
32 /**
33  * \file IpcServer.c
34  * \brief Ipc Server Source File
35  *
36  * This file implements the IPC Server API functions used by Security framework.
37  */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdbool.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <pthread.h>
45 #include <signal.h>
46
47 #include "Debug.h"
48 #include "IpcMacros.h"
49 #include "IpcServerError.h"
50 #include "IpcServerHdr.h"
51 #include "TSCErrorCodes.h"
52
53
54 #ifdef DEBUG
55 #define DBUS_D_LOG(_dbusErr_, _fmt_, _param_...)    \
56     { \
57         DDBG("%s:%s; " _fmt_, _dbusErr_.name, _dbusErr_.message, _param_); \
58     }
59 #else
60 #define DBUS_D_LOG(_dbusErr_, _fmt_, _param_...)
61 #endif
62
63 static void IterateList(IpcMethodHandle* pHandle)
64 {
65     IpcMethodHandle *ph;
66     int count = 0;
67     for(ph = pHandle; ph != NULL; ph = ph->pNext)
68     {
69         count++;
70     }
71     DDBG(".....total count: %d\n", count);
72 }
73
74 inline DBusHandlerResult _IpcSendMessageAndUnref(DBusConnection *pConn, DBusMessage *pMsg)
75 {
76     if (pMsg) {
77         dbus_connection_send(pConn, pMsg, NULL);
78         dbus_message_unref(pMsg);
79     }
80     return DBUS_HANDLER_RESULT_HANDLED;
81 }
82
83 void _FreeHandleMethods(IpcServerInfo *pInfo)
84 {
85     if (!pInfo)
86         return;
87
88     // Free MethodList
89     IpcServerMethodList *pCurr = pInfo->pMethodList;
90     IpcServerMethodList *pPrev = NULL;
91
92     pthread_mutex_lock(&(pInfo->Lock));
93     while (pCurr)
94     {
95         pPrev = pCurr;
96         pCurr = pCurr->pNext;
97
98         if (pPrev->pMethod)
99         {
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);
103
104             pPrev->pMethod = NULL;
105         }
106         free(pPrev);
107     }
108     pInfo->pMethodList = NULL;
109     pInfo->pRunningMethods = NULL;
110     pthread_mutex_unlock(&(pInfo->Lock));
111
112 }
113
114 void _FreeHandlePool(IpcServerInfo *pInfo)
115 {
116     if (!pInfo)
117         return;
118
119     while(IpcThrPoolIdleCount(pInfo->pHandlePool) != TSC_THREAD_POOL_NUMBERS && IpcThrPoolIdleCount(pInfo->pHandlePool) != -1)  //wait till no detachable thread is running
120     {
121         // TODO: Use condition instead of infinite loop
122         sleep(1);
123     }
124     pthread_mutex_lock(&(pInfo->Lock));
125
126     if (pInfo->pHandlePool)
127     {
128         IpcThrPoolFree(&pInfo->pHandlePool);
129     }
130
131     pthread_mutex_unlock(&(pInfo->Lock));
132 }
133
134 void _FreeHandleTable(IpcServerInfo *pInfo)
135 {
136     if (!pInfo)
137         return;
138
139     pthread_mutex_lock(&(pInfo->Lock));
140     if (pInfo->pTable)
141     {
142         free(pInfo->pTable);
143         pInfo->pTable = NULL;
144     }
145     pthread_mutex_unlock(&(pInfo->Lock));
146 }
147
148 void _FreeHandleConn(IpcServerInfo *pInfo)
149 {
150     if (!pInfo)
151         return;
152
153     pthread_mutex_lock(&(pInfo->Lock));
154     if (pInfo->pConn)
155     {
156         dbus_connection_remove_filter(pInfo->pConn, _IpcServerMsgFilter, pInfo);
157             pInfo->pConn = NULL;
158     }
159     pthread_mutex_unlock(&(pInfo->Lock));
160
161 }
162
163 void _WaitForListenThreadClose(IpcServerInfo *pInfo)
164 {
165     if (pInfo && pInfo->lDbus_listen_thread)
166     {
167         pthread_mutex_lock(&(pInfo->Lock));
168         pInfo->start_server_flag = false;
169         pthread_mutex_unlock(&(pInfo->Lock));
170
171         if (pInfo->lDbus_listen_thread)
172             pthread_join(pInfo->lDbus_listen_thread, NULL);
173     }
174 }
175
176 int IpcServerAddMethod(TSC_SERVER_HANDLE hServer, IpcServerMethod *pMethod)
177 {
178     IpcServerInfo *pInfo = NULL;
179     IpcServerMethodList *pList = NULL;
180     int r = TSC_ERROR_ADD_METHOD_FAILED;
181
182     if (INVALID_TSC_SERVER_HANDLE == hServer)
183         return r;
184
185         pList = calloc(1, sizeof(IpcServerMethodList));
186         if (!pList)
187             return r;
188
189         IpcServerMethod* tpMethod = calloc(1, sizeof(IpcServerMethod));
190         if (tpMethod == NULL)
191         {
192                 free(pList);
193                 pList = NULL;
194             return r;
195         }
196         // Copy method
197
198         tpMethod->method = pMethod->method;
199         strncpy(tpMethod->szMethod, pMethod->szMethod, TSC_METHOD_NAME_LEN-1);
200         tpMethod->pData = pMethod->pData;
201
202     pInfo = (IpcServerInfo *) hServer;
203
204     pthread_mutex_lock(&(pInfo->Lock));
205     pList->pNext = pInfo->pMethodList;
206
207     //pList->pMethod = pMethod;
208     pList->pMethod = tpMethod;
209
210     pInfo->pMethodList = pList;
211     pthread_mutex_unlock(&(pInfo->Lock));
212
213     r = 0;
214     return r;
215 }
216
217 int IpcServerRemoveMethod(TSC_SERVER_HANDLE hServer, METHODFUNC method)
218 {
219     IpcServerInfo *pInfo = NULL;
220     IpcServerMethodList **pPrev = NULL;
221     IpcServerMethodList *pCurr = NULL;
222     int r = TSC_ERROR_REMOVE_METHOD_NOT_FOUND;
223
224     DDBG("%s\n", "IpcServerRemoveMethod");
225     if (INVALID_TSC_SERVER_HANDLE == hServer)
226         return r;
227
228     pInfo = (IpcServerInfo *) hServer;
229
230     // Change the head to next node, if deleted.
231     pthread_mutex_lock(&(pInfo->Lock));
232         for (pPrev = &pInfo->pMethodList; *pPrev; pPrev = &(*pPrev)->pNext)
233         {
234                 DDBG("REMOVE method list name :%s\n", (*pPrev)->pMethod->szMethod);
235                 if ((*pPrev)->pMethod->method == method)
236                 {
237                         DDBG("==== FIND REVMOE MOETHOD %s\n", " ");
238                         pCurr = *pPrev;
239                         *pPrev = (*pPrev)->pNext;
240             r = 0;
241             break;
242                 }
243         }
244     pthread_mutex_unlock(&(pInfo->Lock));
245
246     // Release the found method now.
247     if (r == 0 && pCurr->pMethod)
248     {
249         free(pCurr->pMethod);
250         pCurr->pMethod = NULL;
251     }
252     free(pCurr);
253
254     return r;
255 }
256
257 TSC_SERVER_HANDLE IpcServerOpen(char *service_name)
258 {
259     DDBG("IpcServerOpen: %s\n", service_name);
260         DBusError dberr;
261
262     if (!dbus_threads_init_default())
263     {
264         DDBG("failed dbus_threads_init_default %s\n", "");
265         goto err_ret;
266     }
267
268         dbus_error_init(&dberr);
269
270     if (!dbus_validate_bus_name(service_name, &dberr) && dbus_error_is_set(&dberr))
271     {
272         DDBG("it is invalid request name %s\n", "");
273         goto err;
274     }
275
276         IpcServerInfo *pInfo;
277         if ((pInfo = (IpcServerInfo *) calloc(1, sizeof(IpcServerInfo))) == NULL)
278             goto err;
279
280         pInfo->pMethodList = NULL;
281         pInfo->count = 0;
282         if ((pInfo->pTable = (DBusObjectPathVTable *) calloc(1, sizeof(DBusObjectPathVTable))) == NULL)
283             goto free_info;
284
285         pInfo->lDbus_listen_thread = 0;
286         strncpy(pInfo->name, service_name, TSC_SERVER_NAME_LEN - 1);
287
288         if (_IpcServerInit(pInfo, service_name))
289         {
290             DDBG("IpcServerInit failed: %s\n", service_name);
291             goto free_table;
292         }
293
294     //DDBG("IpcServerOpen  success conn:%s\n", pInfo->name);
295     dbus_error_free(&dberr);
296     return (TSC_SERVER_HANDLE) pInfo;
297
298 free_table:
299     SAFE_FREE(pInfo->pTable);
300
301 free_info:
302     DDBG("IpcServerOpen free_info, conn:%s\n", pInfo->name);
303     FREE(pInfo);
304
305 err:
306     dbus_error_free(&dberr);
307
308 err_ret:
309     return INVALID_TSC_SERVER_HANDLE;
310 }
311
312 int IpcServerMainLoop(TSC_SERVER_HANDLE hServer)
313 {
314     IpcServerInfo *pInfo = (IpcServerInfo*) hServer;
315     if (pInfo)
316     {
317         if (pInfo->lDbus_listen_thread)
318         {
319             pthread_join(pInfo->lDbus_listen_thread, NULL);
320             DDBG("finsihed main loop:%s\n", "==========");
321         }
322
323     }
324     return 0;
325 }
326 void IpcServerClose(TSC_SERVER_HANDLE *hServer)
327 {
328         IpcServerInfo *pInfo = (IpcServerInfo *) *hServer;
329         if (pInfo != (IpcServerInfo*)INVALID_TSC_SERVER_HANDLE)
330         {
331             DDBG("IpcServerClose:%s\n", pInfo->name);
332             _WaitForListenThreadClose(pInfo);
333
334             // Wait till no detachable thread is running
335         while (IpcThrPoolIdleCount(pInfo->pHandlePool) != TSC_THREAD_POOL_NUMBERS && IpcThrPoolIdleCount(pInfo->pHandlePool) != -1)
336         {
337             // TODO: Use conditional mutex.
338             sleep(1);
339         }
340
341         _FreeHandleTable(pInfo);
342         _FreeHandleMethods(pInfo);
343         _FreeHandlePool(pInfo);
344         _FreeHandleConn(pInfo);
345         pthread_mutex_destroy(&(pInfo->Lock));
346
347         free(pInfo);
348         *hServer = INVALID_TSC_SERVER_HANDLE;
349         }
350 }
351
352
353 int _IpcServerInit(IpcServerInfo *pInfo, char *szServiceName)
354 {
355     IpcServerMethod *pMethodCancel = NULL;
356     DBusError dberr;
357     int ret;
358
359     if (!pInfo)
360         goto err;
361
362     pInfo->pMethodList = NULL;
363     pInfo->pRunningMethods = NULL;
364     pInfo->start_server_flag = false;
365
366     dbus_error_init(&dberr);
367
368     pInfo->pConn = dbus_bus_get(DBUS_BUS_SYSTEM, &dberr);
369     if (pInfo->pConn == NULL && dbus_error_is_set(&dberr))
370     {
371         DBUS_D_LOG(dberr, "%s\n", "Server failed: connection NULL.");
372         goto free_err;
373     }
374
375     ret = dbus_bus_request_name(pInfo->pConn, szServiceName, DBUS_NAME_FLAG_REPLACE_EXISTING, &dberr);
376     if (ret == -1 && dbus_error_is_set(&dberr))
377     {
378         DBUS_D_LOG(dberr, "%s\n", "server failed: request name.");
379         goto free_conn;
380     }
381
382     // TODO: Why not allow DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER also?
383     if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
384     {
385         DDBG("server failed: Not primary owner :%d\n", ret);
386         goto free_conn;
387     }
388
389     if (0 > snprintf(pInfo->rule, sizeof(pInfo->rule), "type='method_call', interface='%s'",
390                      TSC_DBUS_INTERFACE))
391     {
392         DDBG("%s\n", "server failed: Unable to write rule");
393         goto free_conn;
394     }
395
396     dbus_bus_add_match(pInfo->pConn, pInfo->rule, &dberr);
397     if (dbus_error_is_set(&dberr))
398     {
399         DBUS_D_LOG(dberr, "%s\n", "Match add failed.");
400         goto free_conn;
401     }
402
403     if (!dbus_connection_try_register_object_path(pInfo->pConn, TSC_DBUS_PATH, pInfo->pTable,
404                                                    pInfo, &dberr)
405                 && dbus_error_is_set(&dberr))
406     {
407         DBUS_D_LOG(dberr, "%s\n", "server failed: register object path");
408         goto free_match;
409     }
410
411     dbus_connection_set_exit_on_disconnect(pInfo->pConn, false);
412
413     if (!dbus_connection_add_filter(pInfo->pConn, _IpcServerMsgFilter, pInfo, NULL))
414     {
415         DDBG("%s\n", "server failed: add filter.");
416         goto free_register;
417     }
418
419     if (!dbus_connection_get_unix_fd(pInfo->pConn, &pInfo->fd) || pInfo->fd < 0)
420     {
421         DDBG("%s\n", "server failed: get fd.");
422         goto free_filter;
423     }
424
425     pInfo->pHandlePool = calloc(1, sizeof(IpcHandlePool));
426     if (pInfo->pHandlePool == NULL)
427     {
428         DDBG("%s\n", "Thread pool alloc failed.");
429         goto free_filter;
430     }
431
432     ret = IpcThrPoolInit(pInfo->pHandlePool, TSC_THREAD_POOL_NUMBERS);
433     if (ret)
434     {
435         DDBG("%s\n", "*****Failed in IpcThrPoolInit");
436         goto free_handle;
437     }
438
439     ret = pthread_mutex_init(&(pInfo->Lock), NULL);
440     if (ret)
441     {
442         DDBG("Failed to init IpcServerInfo lock %d\n", ret);
443         goto free_pool;
444     }
445
446     // Add default two methods: Cancel and GetStatus
447     pMethodCancel = calloc(1, sizeof(IpcServerMethod));
448     if (pMethodCancel == NULL)
449     {
450         DDBG("%s\n", "Cancel alloc failed.");
451         goto free_mutex;
452     }
453
454     ret = snprintf(pMethodCancel->szMethod, sizeof(pMethodCancel->szMethod), "%s", TSC_FN_CANCELMETHOD);
455     if (ret < 0)
456     {
457         DDBG("%s\n", "Cancel create failed.");
458         goto free_method_cancel;
459     }
460
461     pMethodCancel->method = (METHODFUNC) IpcCancelMethod;
462     pMethodCancel->pData = NULL;
463     ret = IpcServerAddMethod((TSC_SERVER_HANDLE) pInfo,  pMethodCancel);
464     if (ret)
465     {
466         DDBG("%s\n", "Cancel add failed.");
467         goto free_method_cancel;
468     }
469
470     IpcServerMethod *pMethodProgress = calloc(1, sizeof(IpcServerMethod));
471     if (pMethodProgress == NULL)
472     {
473         DDBG("%s\n", "Progress alloc failed.");
474         goto free_method_cancel;
475     }
476
477     ret = snprintf(pMethodProgress->szMethod, sizeof(pMethodProgress->szMethod), "%s", TSC_FN_PROGRESSMETHOD);
478     if (ret < 0)
479     {
480         DDBG("%s\n", "Progress create failed.");
481         goto free_method_progress;
482     }
483
484     pMethodProgress->method = (METHODFUNC) IpcGetProgressMethod;
485     pMethodProgress->pData = NULL;
486
487     ret = IpcServerAddMethod((TSC_SERVER_HANDLE) pInfo, pMethodProgress);
488     if (ret)
489     {
490         DDBG("%s\n", "Progress add failed.");
491         goto free_method_progress;
492     }
493
494     IpcServerMethod *pMethodShutdown = calloc(1, sizeof(IpcServerMethod));
495     if (pMethodShutdown == NULL)
496     {
497         DDBG("%s\n", "shutdown alloc failed.");
498         goto free_method_progress;
499     }
500
501     ret = snprintf(pMethodShutdown->szMethod, sizeof(pMethodShutdown->szMethod), "%s", TSC_FN_SHUTDOWN);
502     if (ret < 0)
503     {
504         DDBG("%s\n", "Shutdown create failed.");
505         goto free_method_shutdown;
506     }
507
508     pMethodShutdown->method = (METHODFUNC) IpcShutdown;
509     pMethodShutdown->pData = NULL;
510
511     ret = IpcServerAddMethod((TSC_SERVER_HANDLE) pInfo, pMethodShutdown);
512     if (ret)
513     {
514         DDBG("%s\n", "Shutdown add failed.");
515         goto free_method_shutdown;
516     }
517     SAFE_FREE(pMethodShutdown);
518     SAFE_FREE(pMethodProgress);
519     SAFE_FREE(pMethodCancel);
520
521     pthread_mutex_lock(&(pInfo->Lock));
522
523     ret = pthread_create(&(pInfo->lDbus_listen_thread), NULL, _IpcPopMessage, (void *)pInfo);
524     DDBG("Creating thrd for Server: %s\n", pInfo->name);
525
526     if (ret)
527     {
528         DDBG("%s(%d)\n", "** FAILED to launch thread", ret);
529         pInfo->start_server_flag = false;
530         pthread_mutex_unlock(&(pInfo->Lock));
531         goto free_mutex;
532     }
533     pInfo->start_server_flag = true;
534
535     pthread_mutex_unlock(&(pInfo->Lock));
536
537     return 0;
538 free_method_shutdown:
539     SAFE_FREE(pMethodShutdown);
540 free_method_progress:
541     SAFE_FREE(pMethodProgress);
542 free_method_cancel:
543     SAFE_FREE(pMethodCancel);
544 free_mutex:
545     pthread_mutex_destroy(&(pInfo->Lock));
546 free_pool:
547 free_handle:
548     if (pInfo->pHandlePool)
549         IpcThrPoolFree(&pInfo->pHandlePool);
550 free_filter:
551     //dbus_connection_remove_filter(pInfo->pConn, _IpcServerMsgFilter, pInfo);
552 free_register:
553     //dbus_connection_unregister_object_path(pInfo->pConn, TSC_DBUS_PATH);
554 free_match:
555     //dbus_bus_remove_match(pInfo->pConn, pInfo->rule, &dberr);
556 free_conn:
557     //dbus_connection_close(pInfo->pConn); TODO: Why not????
558 free_err:
559     dbus_error_free(&dberr);
560     DDBG("%s", "_IpcServerInit free_err before return -1\n");
561 err:
562     return -1;
563 }
564
565 void _IpcServerDeInit(TSC_SERVER_HANDLE hServer)
566 {
567     DDBG("%s\n", "IpcServerDeInit========");
568         IpcServerInfo *pInfo = (IpcServerInfo *) hServer;
569     if (pInfo)
570     {
571         if (pInfo->lDbus_listen_thread)
572         {
573             pthread_join(pInfo->lDbus_listen_thread, NULL);
574         }
575         FreeIpcServerHandle((TSC_SERVER_HANDLE) pInfo);
576     }
577     //dbus_shutdown(); // for valgrind only
578     DDBG("%s\n", "*_*_*_*_*_*_* Server is disconnected *_*_*_*_*_*_*_*_*");
579 }
580
581
582 DBusHandlerResult _IpcServerReplyMessage(DBusConnection *pConn, DBusMessage *pMsg,
583                                                 char **pReply, int size)
584 {
585     DDBG("%s %d\n", "ReplyMessage size: ", size);
586     DBusMessage *pReplyMsg = NULL;
587     DBusMessageIter    iter;
588     int i;
589
590     if (pConn == NULL)
591         return DBUS_HANDLER_RESULT_HANDLED;
592
593     pReplyMsg = dbus_message_new_method_return(pMsg);
594
595     if (pReplyMsg == NULL)
596         return DBUS_HANDLER_RESULT_NEED_MEMORY;
597
598     dbus_message_iter_init_append(pReplyMsg, &iter);
599
600     for (i = 0; i < size; i++)
601     {
602         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &(pReply[i])))
603         {
604             DDBG("----- Replied string :%s\n", pReply[i]);
605             dbus_message_unref(pReplyMsg);
606             return DBUS_HANDLER_RESULT_NEED_MEMORY;
607         }
608     }
609
610     return _IpcSendMessageAndUnref(pConn, pReplyMsg);
611 }
612
613 DBusHandlerResult _IpcServerReplyError(DBusConnection *pConn, DBusMessage *pMsg,
614                                               int iErrCode)
615 {
616     DDBG("%s\n", "IpcServerReplyError");
617     DBusMessage *pErrMsg = NULL;
618
619     if (!pConn || !pMsg)
620         return DBUS_HANDLER_RESULT_HANDLED;
621
622     pErrMsg = dbus_message_new_error(pMsg, GetErrorName(iErrCode), GetErrorDescription(iErrCode));
623     if (!pErrMsg)
624         return DBUS_HANDLER_RESULT_NEED_MEMORY;
625
626     return _IpcSendMessageAndUnref(pConn, pErrMsg);
627 }
628
629
630 DBusHandlerResult _IpcServerMsgFilter(DBusConnection *pConn, DBusMessage *pMsg, void *pData)
631 {
632     DDBG("%s\n", "IpcServerMsgFilter");
633     IpcServerInfo *pInfo = (IpcServerInfo*) pData;
634     if (!pInfo)
635     {
636         DDBG("%s\n", "not handled the server info");
637         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
638     }
639     else if (dbus_message_is_signal(pMsg, DBUS_INTERFACE_LOCAL, "Disconnected"))
640     {
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;
645     }
646
647     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
648 }
649
650
651 DBusHandlerResult _IpcServerMsgHandler(void *user_data)
652 {
653     DBusHandlerResult ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
654     IpcAsyncInfo *pAsync = user_data;
655
656     if (pAsync)
657     {
658         DBusMessage *pMsg = pAsync->pMsg;
659         IpcServerInfo *pInfo = pAsync->pInfo;
660
661         bool handle_flag = false;
662         if (pInfo)
663         {
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)
668             {
669                 if ((*pPrev) && (*pPrev)->pMethod)
670                 {
671                     if (dbus_message_is_method_call(pMsg, TSC_DBUS_INTERFACE, (*pPrev)->pMethod->szMethod)){
672                         DDBG("FOUND method: %s\n", (*pPrev)->pMethod->szMethod);
673                         handle_flag = true;
674                         pAsync->pMethod = (*pPrev)->pMethod;
675                         break;
676                     }
677                 }
678             }
679             pthread_mutex_unlock(&(pInfo->Lock));
680             if (handle_flag)
681             {
682                 return _IpcServerProcessMessage(pAsync);
683             }
684         }
685         if (ret == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
686         {
687             if (pAsync->pInfo->pHandlePool)
688             {
689                 IpcThrPoolPut(pAsync->pInfo->pHandlePool, pAsync->pHandle);
690             }
691             CleanupAsync(pAsync);
692         }
693
694     }
695
696     return ret;
697 }
698
699 int _ParseDBusMessage(DBusMessage *pMsg, int *pargc, char ***argv)
700 {
701     DBusBasicValue temp = {{0}};
702     int argc = 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.
706
707     if (dbus_message_iter_init(pMsg, &iter))
708     {
709         do
710         {
711             if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
712             {
713                 DDBG("%s\n", "wrong type");
714                 if (argc == 0)
715                     iSize = 0;
716                 iRet = TSC_ERROR_NOT_IMPLEMENTED;
717                 goto clean_up;
718             }
719             dbus_message_iter_get_basic(&iter, &temp);
720             if (!temp.str)
721             {
722                 DDBG("%s\n", "no string");
723                 iRet = TSC_ERROR_INTERNAL;
724                 goto clean_up;
725             }
726
727             if (argc >= iSize)
728             {
729                 iSize += TSC_REPLY_MSG_COUNT_AVERAGE;
730                 (*argv) = realloc((*argv), sizeof(char*) * iSize);
731
732                 if (!(*argv))
733                 {
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;
737                     goto clean_up;
738                 }
739             }
740             else if (argc == 0)
741             {
742                 (*argv) = calloc(1, iSize * sizeof(char *));
743                 if (!(*argv))
744                 {
745                     iRet = TSC_ERROR_INSUFFICIENT_RES;
746                     iSize = 0;  //reset iSize, used to free the memory
747                     goto clean_up;
748                 }
749             }
750
751             (*argv)[argc] = strdup((const char*)temp.str);
752
753             if (!(*argv)[argc])
754             {
755                 DDBG("not engough memory: %s\n", "4");
756                  iRet = TSC_ERROR_INSUFFICIENT_RES;
757                  goto clean_up;
758             }
759             argc++;
760         } while (dbus_message_iter_next(&iter));
761
762         iRet = 0;   // TODO: Is this the right place & code?
763     }
764     else
765     {
766         DDBG("%s\n", "Request message has no arguments");
767         *pargc = argc;
768         return iRet;
769     }
770
771 clean_up:
772
773     if (iRet)
774     {
775         //Error code here
776         int i = 0;
777         if (*argv)
778         {
779                 for (i = 0; i < iSize; i++)
780                 {
781                         if ((*argv)[i])
782                                 free((*argv)[i]);
783                         (*argv)[i] = NULL;
784                 }
785                     free(*argv);
786                     *argv = NULL;
787         }
788     }
789     else
790     {
791         // Everything went well till now...
792         *pargc = argc;
793     }
794
795     return iRet;
796 }
797
798
799 DBusHandlerResult _IpcServerProcessMessage(void *user_data)
800 {
801     DDBG("%s\n", "IpcServerProcessMessage");
802     IpcAsyncInfo *pAsync = user_data;
803     DBusError dberr;
804     char **reply = NULL;
805     int iFreeMtdHandle = 0;
806     int len = 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;
810
811     dbus_error_init(&dberr);
812     if (pAsync->pConn == NULL)
813     {
814         goto clean_up;
815     }
816     // Here when calling method, pass the callback function
817     pMtdHandle = calloc(1, sizeof(IpcMethodHandle));
818
819     if (pMtdHandle == NULL)
820     {
821         goto clean_up;
822     }
823
824     pMtdHandle->pMethod = pAsync->pMethod;
825     iRet = pthread_mutex_init(&(pMtdHandle->Lock), NULL);
826     if (iRet)
827     {
828         if (pMtdHandle)
829             free(pMtdHandle);
830         pMtdHandle = NULL;
831         goto clean_up;
832     }
833
834     if ((pAsync->pMethod)->method)
835     {
836         // insert to RunningMethods
837         if (pAsync->argv[0] == NULL)
838         {
839             goto clean_up;
840         }
841
842         strncpy(pMtdHandle->unique_id, pAsync->async_unique_id, MSGHANDLE_LEN);
843         (pMtdHandle->unique_id)[MSGHANDLE_LEN] = '\0';
844
845         pthread_mutex_lock(&pAsync->pInfo->Lock);
846         (pAsync->pInfo->count)++;
847         pMtdHandle->pNext = pAsync->pInfo->pRunningMethods;
848         pAsync->pInfo->pRunningMethods = pMtdHandle;
849 /*
850         DDBG("============== after adding running method:%s\n", "------");
851         IterateList(pMtdHandle);
852 */
853         pthread_mutex_unlock(&pAsync->pInfo->Lock);
854
855         pMtdHandle->pInfo = pAsync->pInfo;
856         pMtdHandle->cStatus = "1";
857         pMtdHandle->iCancel = TSC_NON_CANCEL;
858
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]);
861
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
866     }
867
868 clean_up:
869
870     if (iRet)
871         _IpcServerReplyError(pAsync->pConn, pAsync->pMsg, TSC_ERROR_INTERNAL);
872     else
873     {
874         // Everything went well till now...
875         _IpcServerReplyMessage(pAsync->pConn, pAsync->pMsg, reply, len);
876     }
877
878     dbus_connection_flush(pAsync->pConn);
879     CleanupArray(&reply, len);
880
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))
885     {
886         if (strncmp((*pmpPrev)->unique_id, pAsync->async_unique_id,  MSGHANDLE_LEN) == 0)
887         {
888             *pmpPrev = (*pmpPrev)->pNext;
889             iFreeMtdHandle = 1;
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);
893             break;
894         }
895     }
896     pthread_mutex_unlock(&(pAsync->pInfo->Lock));
897
898     IpcThrPoolPut(pAsync->pInfo->pHandlePool, pAsync->pHandle);
899     CleanupAsync(pAsync);
900     dbus_error_free(&dberr);
901
902     if (pMtdHandle && iFreeMtdHandle)
903     {
904         free(pMtdHandle);
905         pMtdHandle = NULL;
906     }
907
908     return iRet;
909 }
910
911 void *_IpcPopMessage(void *hServer)
912 {
913     IpcServerInfo *pInfo = (IpcServerInfo *) hServer;
914     DDBG("=IpcPopMessage:%s\n", pInfo->name);
915     int iRet = 0;
916
917     while (pInfo != NULL && pInfo->pConn != NULL && pInfo->start_server_flag) {
918
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);
922
923         if (NULL == pMsg) {
924             sleep(TSC_READ_WRITE_DISPATCH_SLEEP_SECONDS);
925             continue;
926         }
927         else
928         {
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));
933                 if (pAsync != NULL)
934                 {
935                 pAsync->pConn = pInfo->pConn;
936                 pAsync->pInfo = pInfo;
937                 pAsync->pMsg = pMsg;
938                 pAsync->argc = 0;
939                 pAsync->argv = NULL;
940                 pAsync->pHandle = pIpcHandle;
941
942                 iRet = _ParseDBusMessage(pMsg, &(pAsync->argc), &(pAsync->argv));
943
944                 if (iRet == 0)
945                 {
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);
949                     if (iRet < 0)
950                         break;
951
952                     iRet = _RunDetachedThread(_IpcServerMsgHandler, pAsync);
953                     DDBG("====RunDetachedThread ret:%d\n", iRet);
954                 }
955
956                 if (iRet)
957                 {
958                     IpcThrPoolPut(pInfo->pHandlePool, pIpcHandle);
959                     CleanupAsync(pAsync);
960                 }
961
962                 }
963         }
964     }
965     DDBG("popmessage ended :%s\n", "============");
966
967     return NULL;
968 }
969
970
971 void CleanupArray(char*** pArr, int len)
972 {
973     if (pArr) {
974         while (len > 0)
975         {
976             len--;
977             free ((*pArr)[len]);
978             (*pArr)[len] = NULL;
979         }
980         free(*pArr);
981         *pArr = NULL;
982     }
983 }
984
985 void CleanupAsync(IpcAsyncInfo *pAsync)
986 {
987     if (pAsync)
988     {
989         CleanupArray(&(pAsync->argv), pAsync->argc);
990         if (pAsync->pMsg)
991             dbus_message_unref(pAsync->pMsg);
992
993         if (pAsync)
994             free(pAsync);
995         pAsync = NULL;
996
997     }
998 }
999
1000 /***
1001  * reason_params is cleaned up within this method
1002  */
1003 int IpcServerCallbackMethod(TSC_METHOD_HANDLE *pMHandle, TSC_METHOD_REASON_CODE iReason, void *reason_params)
1004 {
1005     IpcMethodHandle  *p_MHandle = (IpcMethodHandle *) pMHandle;
1006     char *data = reason_params;
1007     int iRet = -1;
1008
1009     if (iReason == TSC_CANCEL)
1010     {
1011         pthread_mutex_lock(&(p_MHandle->Lock));
1012         if (p_MHandle->iCancel == TSC_IS_CANCEL)
1013         {
1014             iRet = 0;
1015             DDBG("%s", "callback check, it is cancel true\n");
1016         }
1017         pthread_mutex_unlock(&(p_MHandle->Lock));
1018     }
1019     else if (iReason == TSC_PROGRESS)
1020     {
1021         pthread_mutex_lock(&(p_MHandle->Lock));
1022         p_MHandle->cStatus = strdup(data);  // TODO: any better way to update data?
1023         iRet = 0;
1024         pthread_mutex_unlock(&(p_MHandle->Lock));
1025
1026         if (data)
1027             free(data);
1028         data = NULL;
1029     }
1030     return iRet;
1031 }
1032
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)
1035 {
1036
1037     int ret = 0;
1038     if (argc > 0)
1039     {
1040         DDBG("IpcCancelMethod unique_id %s\n", argv[0]);
1041     }
1042     else
1043     {
1044         DDBG("%s\n", "Error params in cancel method");
1045     }
1046
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;
1052
1053     if (argc != 1)
1054     {
1055         //the argc should be 2, the second param is unique id of to cancel method
1056         ret = -1;
1057     }
1058     pthread_mutex_lock(&(pInfo->Lock));
1059
1060     for (pmpPrev = &(pInfo->pRunningMethods); *pmpPrev; pmpPrev = &((*pmpPrev)->pNext))
1061     {
1062         DDBG("Method to cancel: %s, list method:%s\n", argv[0], (*pmpPrev)->unique_id);
1063         if (strcmp((*pmpPrev)->unique_id, argv[0]) == 0)
1064         {
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?
1070             *len = 1;
1071             *szReply = calloc(1, sizeof(char*) *(*len));
1072             (*szReply)[0] = strdup("0");
1073             pthread_mutex_unlock(&(pMHandle->Lock));
1074             break;
1075         }
1076     }
1077     pthread_mutex_unlock(&(pInfo->Lock));
1078
1079     DDBG("%s\n", "END OF cancel method");
1080     return ret;
1081 }
1082
1083
1084
1085 int
1086 IpcGetProgressMethod(void *pData, int argc, char **argv, char ***szReply, int *len, CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
1087 {
1088     DDBG("%s\n", "IpcGetProgressMethod");
1089     IpcMethodHandle *pMHandle = (IpcMethodHandle*) handle;
1090     IpcServerInfo *pInfo = (IpcServerInfo*) pMHandle->pInfo;
1091
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))
1096     {
1097         DDBG("running methods unique id :%s,  passing id :%s \n", (*pmpPrev)->unique_id, argv[0]);
1098
1099         if (!strcmp((*pmpPrev)->unique_id, argv[0]))
1100         {
1101             DDBG("=== found running method to get progress %s\n", argv[0]);
1102             // get the running method, update its status
1103             *len = 1;
1104             *szReply = calloc(1, sizeof(char*) * 10);
1105             DDBG("-- status to reply :%s\n",(*pmpPrev)->cStatus);
1106             (*szReply)[0] = strdup((*pmpPrev)->cStatus);
1107             break;
1108         }
1109     }
1110     return 0;
1111 }
1112
1113 int
1114 IpcShutdown(void *pData, int argc, char **argv, char ***szReply, int *len, CALLBACKFUNC callback, TSC_METHOD_HANDLE *handle)
1115 {
1116     DDBG("==============%s\n", "IpcShutdownMethod");
1117     IpcMethodHandle *pMHandle = (IpcMethodHandle*) handle;
1118     IpcServerInfo *pInfo = (IpcServerInfo*) pMHandle->pInfo;
1119
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", "===================");
1124     return 0;
1125 }
1126
1127
1128 void FreeIpcServerHandle(TSC_SERVER_HANDLE hServer)
1129 {
1130     DDBG("%s\n", "FreeIpcServerHandle");
1131     IpcServerInfo *pInfo = (IpcServerInfo*) hServer;
1132
1133     if (pInfo)
1134     {
1135         pthread_mutex_lock(&(pInfo->Lock));
1136         // Free MethodList
1137         IpcServerMethodList *pCurr = pInfo->pMethodList;
1138         IpcServerMethodList *pPrev;
1139
1140         while (pCurr)
1141         {
1142             pPrev = pCurr;
1143             pCurr = pCurr->pNext;
1144             DDBG("*****pPrev method is 0 :%s\n", pPrev->pMethod->szMethod);
1145
1146             if (pPrev)
1147             {
1148                 if (pPrev->pMethod)
1149                 {
1150                     if (pPrev->pMethod->method == (METHODFUNC) IpcCancelMethod
1151                             || pPrev->pMethod->method == (METHODFUNC) IpcGetProgressMethod
1152                             || pPrev->pMethod->method == (METHODFUNC) IpcShutdown)
1153                     {
1154                         free(pPrev->pMethod);
1155                     }
1156                     pPrev->pMethod = NULL;
1157                 }
1158                 if (pPrev->pNext)
1159                 {
1160                         pPrev->pNext = NULL;
1161                 }
1162
1163                 free(pPrev);
1164                 pPrev = NULL;
1165             }
1166         }
1167
1168         pInfo->pMethodList = NULL;
1169         pInfo->pRunningMethods = NULL;
1170
1171         if (pInfo->pHandlePool)
1172             IpcThrPoolFree(&pInfo->pHandlePool);
1173
1174         pthread_mutex_unlock(&(pInfo->Lock));
1175
1176         pthread_mutex_destroy(&(pInfo->Lock));
1177
1178         if (pInfo->pTable)
1179             free(pInfo->pTable);
1180         pInfo->pTable = NULL;
1181
1182         if (pInfo->pConn)
1183         {
1184             DBusError dberr;
1185             dbus_error_init(&dberr);
1186
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);
1190
1191             dbus_bus_release_name(pInfo->pConn, TSC_DBUS_SERVER, &dberr);
1192
1193             dbus_connection_unref(pInfo->pConn);
1194             dbus_error_free(&dberr);
1195         }
1196         pInfo->pConn = NULL;
1197
1198         free(pInfo);
1199         pInfo = NULL;
1200     }
1201 }
1202
1203
1204
1205 /**
1206  * Creates a thread for asynchronous task.
1207  * TODO: Merge with TCS module.
1208  */
1209 int _RunDetachedThread(void *pfWorkerFunc, void *pThreadData)
1210 {
1211     pthread_t thread;
1212     pthread_attr_t attr;
1213
1214     int rc = -1;
1215     do
1216     {
1217         if (pthread_attr_init(&attr) != 0)
1218             break;
1219
1220         if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
1221             break;
1222
1223
1224         if (pthread_create(&thread, &attr, pfWorkerFunc, pThreadData) != 0)
1225             break;
1226
1227         if (pthread_attr_destroy(&attr) != 0)
1228         {
1229             // As the thread is already running, return different error code.
1230             rc = -2;
1231             break;
1232         }
1233
1234         rc = 0;
1235     }
1236     while (0);
1237     return rc;
1238 }
1239