b0a9650954b87505e26d70ecb127bd2176b3f452
[platform/core/pim/pims-ipc.git] / src / pims-ipc-svc.c
1 /*
2  * PIMS IPC
3  *
4  * Copyright (c) 2012 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an AS IS BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <glib.h>
24 #include <pthread.h>
25 #include <stdint.h>
26 #include <poll.h>                               // pollfds
27 #include <fcntl.h>                              //fcntl
28 #include <unistd.h>
29 #include <systemd/sd-daemon.h>
30 #include <errno.h>
31
32 #include <sys/stat.h>
33 #include <sys/un.h>                     // sockaddr_un
34 #include <sys/ioctl.h>          // ioctl
35 #include <sys/epoll.h>          // epoll
36 #include <sys/eventfd.h>        // eventfd
37 #include <sys/socket.h>         //socket
38 #include <sys/types.h>
39
40 #include <cynara-client.h>
41 #include <cynara-session.h>
42 #include <cynara-creds-socket.h>
43
44 #include "pims-internal.h"
45 #include "pims-debug.h"
46 #include "pims-socket.h"
47 #include "pims-ipc-data.h"
48 #include "pims-ipc-data-internal.h"
49 #include "pims-ipc-svc.h"
50
51 #define PIMS_IPC_WORKERS_DEFAULT_MAX_COUNT  2
52
53 typedef struct {
54         char *service;
55         gid_t group;
56         mode_t mode;
57
58         // callback functions
59         GHashTable *cb_table;                   // call_id, cb_data
60
61         // Global socket info and epoll thread
62         int sockfd;
63         bool epoll_stop_thread;
64
65         /////////////////////////////////////////////
66         // router inproc eventfd
67         int router;
68         int delay_count;  // not need mutex
69         // epoll thread add client_fd, when receive, router read requests
70         GList *request_queue;    // client_id lists to send request
71         pthread_mutex_t request_data_queue_mutex;
72         GHashTable *request_data_queue;  // key : client id, data : GList pims_ipc_raw_data_s (client_fd, seq_no, request(command), additional data...)
73         // router add client when receive connecting request, remove client when disconneting request in router thread
74         // manager remove client when terminating client without disconnect request in router thread
75         GHashTable *client_worker_map;           // key : client_id, worker_fd, not need mutex
76         GList *client_id_fd_map;                 // pims_ipc_client_map_s
77         //key :client_id(pid:seq_no), data : client_fd
78
79         /////////////////////////////////////////////
80         pthread_mutex_t task_fds_mutex;
81         // when starting worker thread, register fd
82         // when endting worker thread, deregister fd
83         GHashTable *task_fds;    // worker_fd - worker data (worker fd, client_fd, request queue(GList), stop_thread)
84         int workers_max_count;
85
86         /////////////////////////////////////////////
87         // manager inproc eventfd
88         int manager;
89         // write by new worker thread, read by manager in router thread, need mutex
90         pthread_mutex_t manager_queue_from_worker_mutex;
91         GList *manager_queue_from_worker;        // worker_fd => add to workers
92         // write in epoll thread(for dead client), read by manager in router thread, need mutex
93         pthread_mutex_t manager_queue_from_epoll_mutex;
94         GList *manager_queue_from_epoll; // cliend_fd => find worker_fd => add to idle workers
95         // managed by manager, router find idle worker when connecting new client in router thread => remove from idle workers
96         GList *workers;          // worker_fd list, not need mutex
97         /////////////////////////////////////////////
98         cynara *cynara;
99         pthread_mutex_t cynara_mutex;
100
101         int unique_sequence_number;
102         pthread_mutex_t client_info_mutex;
103         GHashTable *worker_client_info_map; // key : worker_id, data : pims_ipc_client_info_s*
104         GHashTable *client_info_map; // key : client_id, data : pims_ipc_client_info_s*
105 } pims_ipc_svc_s;
106
107 typedef struct {
108         char *smack;
109         char *uid;
110         char *client_session;
111 } pims_ipc_client_info_s ;
112
113 typedef struct {
114         char *service;
115         gid_t group;
116         mode_t mode;
117
118         int publish_sockfd;
119         bool epoll_stop_thread;
120         pthread_mutex_t subscribe_fds_mutex;
121         GList *subscribe_fds;           // cliend fd list
122 } pims_ipc_svc_for_publish_s;
123
124 typedef struct {
125         int fd;
126         char *id;
127 }pims_ipc_client_map_s;
128
129 typedef struct {
130         pims_ipc_svc_call_cb callback;
131         void * user_data;
132 } pims_ipc_svc_cb_s;
133
134 typedef struct {
135         pims_ipc_svc_client_disconnected_cb callback;
136         void * user_data;
137 } pims_ipc_svc_client_disconnected_cb_t;
138
139 typedef struct {
140         int fd;
141         int worker_id;  // pthrad_self()
142         int client_fd;
143         bool stop_thread;
144         GList *queue;           // pims_ipc_raw_data_s list
145         pthread_mutex_t queue_mutex;
146 } pims_ipc_worker_data_s;
147
148 typedef struct{
149         char *client_id;
150         unsigned int client_id_len;
151         unsigned int seq_no;
152         char *call_id;
153         unsigned int call_id_len;
154         unsigned int is_data;
155         unsigned int data_len;
156         char *data;
157 }pims_ipc_raw_data_s;
158
159 typedef struct {
160         int client_fd;
161         int request_count;
162         GList *raw_data;                // pims_ipc_raw_data_s list
163         pthread_mutex_t raw_data_mutex;
164 }pims_ipc_request_s;
165
166 static pims_ipc_svc_s *_g_singleton = NULL;
167 static pims_ipc_svc_for_publish_s *_g_singleton_for_publish = NULL;
168
169 static __thread pims_ipc_svc_client_disconnected_cb_t _client_disconnected_cb = {NULL, NULL};
170
171 static void __free_raw_data(pims_ipc_raw_data_s *data)
172 {
173         if (!data) return;
174
175         free(data->client_id);
176         free(data->call_id);
177         free(data->data);
178         free(data);
179 }
180
181 static void __worker_data_free(gpointer data)
182 {
183         pims_ipc_worker_data_s *worker_data = (pims_ipc_worker_data_s*)data;
184
185         pthread_mutex_lock(&worker_data->queue_mutex);
186         if (worker_data->queue) {
187                 GList *cursor = g_list_first(worker_data->queue);
188                 while(cursor) {
189                         GList *l = cursor;
190                         pims_ipc_raw_data_s *data = l->data;
191                         cursor = g_list_next(cursor);
192                         worker_data->queue = g_list_remove_link(worker_data->queue, l);
193                         g_list_free(l);
194                         __free_raw_data(data);
195                 }
196         }
197         pthread_mutex_unlock(&worker_data->queue_mutex);
198         free(worker_data);
199 }
200
201 static void _destroy_client_info(gpointer p)
202 {
203         pims_ipc_client_info_s *client_info = p;
204
205         if (NULL == client_info)
206                 return;
207         free(client_info->smack);
208         free(client_info->uid);
209         free(client_info->client_session);
210         free(client_info);
211 }
212
213 API int pims_ipc_svc_init(char *service, gid_t group, mode_t mode)
214 {
215         if (_g_singleton) {
216                 ERROR("Already exist");
217                 return -1;
218         }
219
220         _g_singleton = g_new0(pims_ipc_svc_s, 1);
221         ASSERT(_g_singleton);
222
223         _g_singleton->service = g_strdup(service);
224         _g_singleton->group = group;
225         _g_singleton->mode = mode;
226         _g_singleton->workers_max_count = PIMS_IPC_WORKERS_DEFAULT_MAX_COUNT;
227         _g_singleton->cb_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
228         ASSERT(_g_singleton->cb_table);
229
230         pthread_mutex_init(&_g_singleton->request_data_queue_mutex, 0);
231         _g_singleton->request_queue = NULL;
232         _g_singleton->request_data_queue = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);        // client_id - pims_ipc_raw_data_s
233         ASSERT(_g_singleton->request_data_queue);
234         _g_singleton->client_worker_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);         // client id - worker_fd mapping
235         ASSERT(_g_singleton->client_worker_map);
236         _g_singleton->delay_count = 0;
237
238         pthread_mutex_init(&_g_singleton->task_fds_mutex, 0);
239         _g_singleton->task_fds = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, __worker_data_free);                // pims_ipc_worker_data_s
240         ASSERT(_g_singleton->task_fds);
241
242         pthread_mutex_init(&_g_singleton->manager_queue_from_epoll_mutex, 0);
243         _g_singleton->manager_queue_from_epoll = NULL;
244
245         pthread_mutex_init(&_g_singleton->manager_queue_from_worker_mutex, 0);
246         _g_singleton->manager_queue_from_worker = NULL;
247         _g_singleton->workers = NULL;
248
249         _g_singleton->unique_sequence_number = 0;
250
251         _g_singleton->worker_client_info_map = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, _destroy_client_info);
252         _g_singleton->client_info_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _destroy_client_info);
253         pthread_mutex_init(&_g_singleton->client_info_mutex, 0);
254
255         pthread_mutex_init(&_g_singleton->cynara_mutex, 0);
256         _g_singleton->epoll_stop_thread = false;
257
258         int ret = cynara_initialize(&_g_singleton->cynara, NULL);
259         if (CYNARA_API_SUCCESS != ret) {
260                 char errmsg[1024] = {0};
261                 cynara_strerror(ret, errmsg, sizeof(errmsg));
262                 ERROR("cynara_initialize() Fail(%d,%s)", ret, errmsg);
263                 return -1;
264         }
265         return 0;
266 }
267
268 API int pims_ipc_svc_deinit(void)
269 {
270         if (!_g_singleton)
271                 return -1;
272
273         g_free(_g_singleton->service);
274         g_hash_table_destroy(_g_singleton->cb_table);
275
276         pthread_mutex_destroy(&_g_singleton->request_data_queue_mutex);
277         g_hash_table_destroy(_g_singleton->client_worker_map);
278         g_hash_table_destroy(_g_singleton->request_data_queue);
279         g_list_free_full(_g_singleton->request_queue, g_free);
280
281         pthread_mutex_destroy(&_g_singleton->task_fds_mutex);
282         g_hash_table_destroy(_g_singleton->task_fds);
283
284         pthread_mutex_destroy(&_g_singleton->manager_queue_from_epoll_mutex);
285         g_list_free_full(_g_singleton->manager_queue_from_epoll, g_free);
286         pthread_mutex_destroy(&_g_singleton->manager_queue_from_worker_mutex);
287         g_list_free(_g_singleton->manager_queue_from_worker);
288
289         GList *cursor = g_list_first(_g_singleton->client_id_fd_map);
290         while(cursor) {
291                 pims_ipc_client_map_s *client = cursor->data;
292                 _g_singleton->client_id_fd_map = g_list_remove_link(_g_singleton->client_id_fd_map, cursor);                    //free(client_id);
293                 free(client->id);
294                 free(client);
295                 g_list_free(cursor);
296                 cursor = g_list_first(_g_singleton->client_id_fd_map);
297         }
298         g_list_free(_g_singleton->client_id_fd_map);
299
300         pthread_mutex_destroy(&_g_singleton->client_info_mutex);
301         g_hash_table_destroy(_g_singleton->worker_client_info_map);
302         g_hash_table_destroy(_g_singleton->client_info_map);
303
304         pthread_mutex_lock(&_g_singleton->cynara_mutex);
305         int ret = cynara_finish(_g_singleton->cynara);
306         if (CYNARA_API_SUCCESS != ret) {
307                 char errmsg[1024] = {0};
308                 cynara_strerror(ret, errmsg, sizeof(errmsg));
309                 ERROR("cynara_finish() Fail(%d,%s)", ret, errmsg);
310         }
311         pthread_mutex_unlock(&_g_singleton->cynara_mutex);
312         pthread_mutex_destroy(&_g_singleton->cynara_mutex);
313
314         g_list_free(_g_singleton->workers);
315         g_free(_g_singleton);
316         _g_singleton = NULL;
317
318         return 0;
319 }
320
321 API int pims_ipc_svc_register(char *module, char *function, pims_ipc_svc_call_cb callback, void *userdata)
322 {
323         pims_ipc_svc_cb_s *cb_data = NULL;
324         gchar *call_id = NULL;
325
326         if (!module || !function || !callback) {
327                 ERROR("Invalid argument");
328                 return -1;
329         }
330         cb_data = g_new0(pims_ipc_svc_cb_s, 1);
331         call_id = PIMS_IPC_MAKE_CALL_ID(module, function);
332
333         VERBOSE("register cb id[%s]", call_id);
334         cb_data->callback = callback;
335         cb_data->user_data = userdata;
336         g_hash_table_insert(_g_singleton->cb_table, call_id, cb_data);
337
338         return 0;
339 }
340
341 API int pims_ipc_svc_init_for_publish(char *service, gid_t group, mode_t mode)
342 {
343         if (_g_singleton_for_publish) {
344                 ERROR("Already exist");
345                 return -1;
346         }
347
348         _g_singleton_for_publish = g_new0(pims_ipc_svc_for_publish_s, 1);
349         _g_singleton_for_publish->service = g_strdup(service);
350         _g_singleton_for_publish->group = group;
351         _g_singleton_for_publish->mode = mode;
352         _g_singleton_for_publish->subscribe_fds = NULL;
353
354         pthread_mutex_init(&_g_singleton_for_publish->subscribe_fds_mutex, 0);
355
356         return 0;
357 }
358
359 API int pims_ipc_svc_deinit_for_publish(void)
360 {
361         if (!_g_singleton_for_publish)
362                 return -1;
363
364         pthread_mutex_destroy(&_g_singleton_for_publish->subscribe_fds_mutex);
365         g_list_free(_g_singleton_for_publish->subscribe_fds);
366
367         g_free(_g_singleton_for_publish->service);
368         g_free(_g_singleton_for_publish);
369         _g_singleton_for_publish = NULL;
370
371         return 0;
372 }
373
374 API int pims_ipc_svc_publish(char *module, char *event, pims_ipc_data_h data)
375 {
376         pims_ipc_svc_for_publish_s *ipc_svc = _g_singleton_for_publish;
377         gboolean is_valid = FALSE;
378         gchar *call_id = PIMS_IPC_MAKE_CALL_ID(module, event);
379         pims_ipc_data_s *data_in = (pims_ipc_data_s*)data;
380         unsigned int call_id_len = strlen(call_id);
381         unsigned int is_data = FALSE;
382
383         do {
384                 // make publish data
385                 unsigned int len = sizeof(unsigned int)                                         // total size
386                         + call_id_len + sizeof(unsigned int)                    // call_id
387                         + sizeof(unsigned int);                                                 // is data
388                 unsigned int total_len = len;
389
390                 if (data_in) {
391                         is_data = TRUE;
392                         len += sizeof(unsigned int);
393                         total_len = len + data_in->buf_size;                    // data
394                 }
395
396                 char buf[len+1];
397                 int length = 0;
398                 memset(buf, 0x0, len+1);
399
400                 // total_size
401                 memcpy(buf, (void*)&total_len, sizeof(unsigned int));
402                 length += sizeof(unsigned int);
403
404                 // call_id
405                 memcpy(buf+length, (void*)&(call_id_len), sizeof(unsigned int));
406                 length += sizeof(unsigned int);
407                 memcpy(buf+length, (void*)(call_id), call_id_len);
408                 length += call_id_len;
409                 g_free(call_id);
410
411                 // is_data
412                 memcpy(buf+length, (void*)&(is_data), sizeof(unsigned int));
413                 length += sizeof(unsigned int);
414
415                 // data
416                 if (is_data) {
417                         memcpy(buf+length, (void*)&(data_in->buf_size), sizeof(unsigned int));
418                         length += sizeof(unsigned int);
419                 }
420
421                 // Publish to clients
422                 pthread_mutex_lock(&ipc_svc->subscribe_fds_mutex);
423                 GList *cursor = g_list_first(ipc_svc->subscribe_fds);
424                 int ret = 0;
425                 while(cursor) {
426                         int fd = (int)cursor->data;
427                         pthread_mutex_unlock(&ipc_svc->subscribe_fds_mutex);
428                         ret = socket_send(fd, buf, length);
429                         if (ret < 0) {
430                                 ERROR("socket_send publish error : %d", ret);
431                         }
432
433                         if (is_data) {
434                                 ret = socket_send_data(fd, data_in->buf, data_in->buf_size);
435                                 if (ret < 0) {
436                                         ERROR("socket_send_data publish error : %d", ret);
437                                 }
438                         }
439                         pthread_mutex_lock(&ipc_svc->subscribe_fds_mutex);
440                         cursor = g_list_next(cursor);
441                 }
442                 pthread_mutex_unlock(&ipc_svc->subscribe_fds_mutex);
443
444                 is_valid = TRUE;
445         } while (0);
446
447         if (is_valid == FALSE)
448                 return -1;
449         return 0;
450 }
451
452 static void __run_callback(int worker_id, char *call_id, pims_ipc_data_h dhandle_in, pims_ipc_data_h *dhandle_out)
453 {
454         pims_ipc_svc_cb_s *cb_data = NULL;
455
456         VERBOSE("Call id [%s]", call_id);
457
458         cb_data = (pims_ipc_svc_cb_s*)g_hash_table_lookup(_g_singleton->cb_table, call_id);
459         if (cb_data == NULL) {
460                 VERBOSE("unable to find %s", call_id);
461                 return;
462         }
463
464         cb_data->callback((pims_ipc_h)worker_id, dhandle_in, dhandle_out, cb_data->user_data);
465 }
466
467 static void __make_raw_data(const char *call_id, int seq_no, pims_ipc_data_h data, pims_ipc_raw_data_s **out)
468 {
469         if (NULL == out) {
470                 ERROR("Invalid parameter:out is NULL");
471                 return;
472         }
473
474         pims_ipc_raw_data_s *raw_data = NULL;
475         raw_data = (pims_ipc_raw_data_s*)calloc(1, sizeof(pims_ipc_raw_data_s));
476         if (NULL == raw_data) {
477                 ERROR("calloc() Fail");
478                 return;
479         }
480         pims_ipc_data_s *data_in = (pims_ipc_data_s*)data;
481
482         raw_data->call_id = strdup(call_id);
483         raw_data->call_id_len = strlen(raw_data->call_id);
484         raw_data->seq_no = seq_no;
485
486         if (data_in && data_in->buf_size > 0) {
487                 raw_data->is_data = TRUE;
488                 raw_data->data = calloc(1, data_in->buf_size+1);
489                 if (NULL == raw_data->data) {
490                         ERROR("calloc() Fail");
491                         free(raw_data->call_id);
492                         free(raw_data);
493                         return;
494                 }
495                 memcpy(raw_data->data, data_in->buf, data_in->buf_size);
496                 raw_data->data_len = data_in->buf_size;
497         }
498         else {
499                 raw_data->is_data = FALSE;
500                 raw_data->data_len = 0;
501                 raw_data->data = NULL;
502         }
503         *out = raw_data;
504         return;
505 }
506
507 static int __send_raw_data(int fd, const char *client_id, pims_ipc_raw_data_s *data)
508 {
509         int ret = 0;
510         unsigned int client_id_len = strlen(client_id);
511
512         if (!data) {
513                 INFO("No data to send NULL\n");
514                 return -1;
515         }
516
517         unsigned int len = sizeof(unsigned int)                 // total size
518                 + client_id_len + sizeof(unsigned int)          // client_id
519                 + sizeof(unsigned int)                                                  // seq_no
520                 + data->call_id_len + sizeof(unsigned int)      // call_id
521                 + sizeof(unsigned int);                                                 // is data
522         unsigned int total_len = len;
523
524         if (data->is_data) {
525                 len += sizeof(unsigned int); // data
526                 total_len = len + data->data_len;               // data
527         }
528
529         INFO("client_id: %s, call_id : %s, seq no :%d, len:%d, total len :%d", client_id, data->call_id, data->seq_no, len, total_len);
530
531         char buf[len+1];
532
533         int length = 0;
534         memset(buf, 0x0, len+1);
535
536         // total_len
537         memcpy(buf, (void*)&total_len, sizeof(unsigned int));
538         length += sizeof(unsigned int);
539
540         // client_id
541         memcpy(buf+length, (void*)&(client_id_len), sizeof(unsigned int));
542         length += sizeof(unsigned int);
543         memcpy(buf+length, (void*)(client_id), client_id_len);
544         length += client_id_len;
545
546         // seq_no
547         memcpy(buf+length, (void*)&(data->seq_no), sizeof(unsigned int));
548         length += sizeof(unsigned int);
549
550         // call id
551         memcpy(buf+length, (void*)&(data->call_id_len), sizeof(unsigned int));
552         length += sizeof(unsigned int);
553         memcpy(buf+length, (void*)(data->call_id), data->call_id_len);
554         length += data->call_id_len;
555
556         // is_data
557         memcpy(buf+length, (void*)&(data->is_data), sizeof(unsigned int));
558         length += sizeof(unsigned int);
559
560         if (data->is_data) {
561                 memcpy(buf+length, (void*)&(data->data_len), sizeof(unsigned int));
562                 length += sizeof(unsigned int);
563                 ret = socket_send(fd, buf, length);
564
565                 // send data
566                 if (ret > 0)
567                         ret += socket_send_data(fd, data->data, data->data_len);
568         }
569         else
570                 ret = socket_send(fd, buf, length);
571
572         return ret;
573 }
574
575 static gboolean __worker_raw_data_pop(pims_ipc_worker_data_s *worker, pims_ipc_raw_data_s **data)
576 {
577         if (!worker)
578                 return FALSE;
579
580         pthread_mutex_lock(&worker->queue_mutex);
581         if (!worker->queue) {
582                 pthread_mutex_unlock(&worker->queue_mutex);
583                 *data = NULL;
584                 return FALSE;
585         }
586
587         *data = g_list_first(worker->queue)->data;
588         worker->queue = g_list_delete_link(worker->queue, g_list_first(worker->queue));
589         pthread_mutex_unlock(&worker->queue_mutex);
590
591         return TRUE;
592 }
593
594 static void* __worker_loop(void *data)
595 {
596         int ret;
597         int worker_id;
598         int worker_fd;
599         pims_ipc_svc_s *ipc_svc = (pims_ipc_svc_s*)data;
600         pims_ipc_worker_data_s *worker_data;
601         bool disconnected = false;
602
603         worker_fd = eventfd(0, 0);
604         if (worker_fd == -1)
605                 return NULL;
606         worker_id = (int)pthread_self();
607
608         worker_data = calloc(1, sizeof(pims_ipc_worker_data_s));
609         if (NULL == worker_data) {
610                 ERROR("calloc() Fail");
611                 close(worker_fd);
612                 return NULL;
613         }
614         worker_data->fd = worker_fd;
615         worker_data->worker_id = worker_id;
616         worker_data->client_fd = -1;
617         worker_data->stop_thread = false;
618         pthread_mutex_init(&worker_data->queue_mutex, 0);
619
620         pthread_mutex_lock(&ipc_svc->task_fds_mutex);
621         g_hash_table_insert(ipc_svc->task_fds, GINT_TO_POINTER(worker_fd), worker_data);
622         pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
623
624         pthread_mutex_lock(&ipc_svc->manager_queue_from_worker_mutex);
625         ipc_svc->manager_queue_from_worker = g_list_append(ipc_svc->manager_queue_from_worker, (void*)worker_fd);
626         pthread_mutex_unlock(&ipc_svc->manager_queue_from_worker_mutex);
627
628         write_command(ipc_svc->manager, 1);
629         DEBUG("worker register to manager : worker_id(%08x00), worker_fd(%d)\n", worker_id, worker_fd);
630
631         struct pollfd *pollfds = (struct pollfd*)calloc(1, sizeof(struct pollfd));
632         if (NULL == pollfds) {
633                 ERROR("calloc() Fail");
634                 g_hash_table_remove(ipc_svc->task_fds, GINT_TO_POINTER(worker_fd));
635                 free(worker_data);
636                 close(worker_fd);
637                 return NULL;
638         }
639         pollfds[0].fd = worker_fd;
640         pollfds[0].events = POLLIN;
641
642         while (!worker_data->stop_thread) {
643                 while(1) {
644                         if (worker_data->stop_thread)
645                                 break;
646                         ret = poll(pollfds, 1, 3000);   // waiting command from router
647                         if (ret == -1 && errno == EINTR) {
648                                 continue;
649                         }
650                         break;
651                 }
652
653                 if (worker_data->stop_thread)
654                         break;
655
656                 if (ret > 0) {
657                         pims_ipc_raw_data_s *raw_data = NULL;
658                         pims_ipc_raw_data_s *result = NULL;
659
660                         if (pollfds[0].revents & POLLIN) {
661                                 uint64_t dummy;
662                                 read_command(pollfds[0].fd, &dummy);
663                                 if (__worker_raw_data_pop(worker_data, &raw_data)) {
664                                         pims_ipc_data_h data_in = NULL;
665                                         pims_ipc_data_h data_out = NULL;
666                                         if (strcmp(PIMS_IPC_CALL_ID_CREATE, raw_data->call_id) == 0) {
667
668                                         }
669                                         else if (strcmp(PIMS_IPC_CALL_ID_DESTROY, raw_data->call_id) == 0) {
670                                                 disconnected = true;
671                                         }
672                                         else {
673                                                 data_in = pims_ipc_data_steal_unmarshal(raw_data->data, raw_data->data_len);
674                                                 raw_data->data = NULL;
675                                                 raw_data->data_len = 0;
676                                                 raw_data->is_data = false;
677                                                 __run_callback(worker_id, raw_data->call_id, data_in, &data_out);
678                                                 pims_ipc_data_destroy(data_in);
679                                         }
680
681                                         if (data_out) {
682                                                 __make_raw_data(raw_data->call_id, raw_data->seq_no, data_out, &result);
683                                                 pims_ipc_data_destroy(data_out);
684                                         }
685                                         else
686                                                 __make_raw_data(raw_data->call_id, raw_data->seq_no, NULL, &result);
687
688                                         if (worker_data->client_fd != -1)
689                                                 __send_raw_data(worker_data->client_fd, raw_data->client_id, result);
690                                         __free_raw_data(raw_data);
691                                         __free_raw_data(result);
692                                 }
693                         }
694                 }
695         }
696
697         if (!disconnected)
698                 ERROR("client fd closed, worker_fd : %d", worker_fd);
699         INFO("task thread terminated --------------------------- (worker_fd : %d)", worker_fd);
700
701         pthread_mutex_lock(&ipc_svc->client_info_mutex);
702         g_hash_table_remove(ipc_svc->worker_client_info_map, GINT_TO_POINTER(worker_id));
703         pthread_mutex_unlock(&ipc_svc->client_info_mutex);
704
705         pthread_mutex_lock(&ipc_svc->task_fds_mutex);
706         g_hash_table_remove(ipc_svc->task_fds, GINT_TO_POINTER(worker_fd));             // __worker_data_free will be called
707         pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
708
709         close(worker_fd);
710         free ((void*)pollfds);
711
712         if (_client_disconnected_cb.callback)
713                 _client_disconnected_cb.callback((pims_ipc_h)worker_id, _client_disconnected_cb.user_data);
714
715         return NULL;
716 }
717
718 static void __launch_thread(void *(*start_routine) (void *), void *data)
719 {
720         int ret = 0;
721
722         pthread_t worker;
723         pthread_attr_t attr;
724
725         // set kernel thread
726         ret = pthread_attr_init(&attr);
727         if (0 != ret) {
728                 ERROR("pthread_attr_init() Fail(%d)", ret);
729                 return;
730         }
731         ret = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
732         if (0 != ret) {
733                 ERROR("pthread_attr_setscope() Fail(%d)", ret);
734                 return;
735         }
736         ret = pthread_create(&worker, &attr, start_routine, data);
737         if (0 != ret) {
738                 ERROR("pthread_create() Fail(%d)", ret);
739                 return;
740         }
741         pthread_detach(worker);
742 }
743
744 static gboolean __is_worker_available()
745 {
746         if (_g_singleton->workers)
747                 return TRUE;
748         else
749                 return FALSE;
750 }
751
752 static int __get_worker(const char *client_id, int *worker_fd)
753 {
754         ASSERT(client_id);
755         ASSERT(worker_fd);
756
757         if (!__is_worker_available()) {
758                 ERROR("There is no idle worker");
759                 return -1;
760         }
761         *worker_fd = (int)(g_list_first(_g_singleton->workers)->data);
762         _g_singleton->workers = g_list_delete_link(_g_singleton->workers,
763                         g_list_first(_g_singleton->workers));
764
765         g_hash_table_insert(_g_singleton->client_worker_map, g_strdup(client_id), GINT_TO_POINTER(*worker_fd));
766
767         return 0;
768 }
769
770 static int __find_worker(const char *client_id, int *worker_fd)
771 {
772         char *orig_pid = NULL;
773         int fd;
774
775         ASSERT(client_id);
776         ASSERT(worker_fd);
777
778         if (FALSE == g_hash_table_lookup_extended(_g_singleton->client_worker_map, client_id,
779                                 (gpointer*)&orig_pid, (gpointer*)&fd)) {
780                 VERBOSE("unable to find worker id for %s", client_id);
781                 return -1;
782         }
783
784         *worker_fd = GPOINTER_TO_INT(fd);
785         return 0;
786 }
787
788 static bool __request_pop(pims_ipc_request_s *data_queue, pims_ipc_raw_data_s **data)
789 {
790         bool ret = false;
791         GList *cursor;
792
793         pthread_mutex_lock(&data_queue->raw_data_mutex);
794         cursor = g_list_first(data_queue->raw_data);
795         if (cursor) {
796                 *data = cursor->data;
797                 data_queue->raw_data = g_list_delete_link(data_queue->raw_data, cursor);
798                 (data_queue->request_count)--;
799
800                 ret = true;
801         }
802         else
803                 *data = NULL;
804
805         pthread_mutex_unlock(&data_queue->raw_data_mutex);
806         return ret;
807 }
808
809 static bool __worker_raw_data_push(pims_ipc_worker_data_s *worker_data, int client_fd, pims_ipc_raw_data_s *data)
810 {
811         pthread_mutex_lock(&worker_data->queue_mutex);
812         worker_data->queue = g_list_append(worker_data->queue, data);
813         worker_data->client_fd = client_fd;
814         pthread_mutex_unlock(&worker_data->queue_mutex);
815
816         return true;
817 }
818
819 static int _find_worker_id(pims_ipc_svc_s *ipc_svc, int worker_fd)
820 {
821         int worker_id = 0;
822         pims_ipc_worker_data_s *worker_data = NULL;
823         pthread_mutex_lock(&ipc_svc->task_fds_mutex);
824         worker_data = g_hash_table_lookup(ipc_svc->task_fds, GINT_TO_POINTER(worker_fd));
825         if (NULL == worker_data) {
826                 ERROR("g_hash_table_lookup(%d) return NULL", worker_fd);
827                 pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
828                 return -1;
829         }
830         worker_id = worker_data->worker_id;
831         pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
832         return worker_id;
833 }
834
835 static int _create_client_info(int fd, pims_ipc_client_info_s **p_client_info)
836 {
837         int ret;
838         pid_t pid;
839         char errmsg[1024] = {0};
840
841         pims_ipc_client_info_s *client_info = calloc(1, sizeof(pims_ipc_client_info_s));
842         if (NULL == client_info) {
843                 ERROR("calloc() return NULL");
844                 return -1;
845         }
846
847         ret = cynara_creds_socket_get_client(fd, CLIENT_METHOD_SMACK, &(client_info->smack));
848         if (CYNARA_API_SUCCESS != ret) {
849                 cynara_strerror(ret, errmsg, sizeof(errmsg));
850                 ERROR("cynara_creds_socket_get_client() Fail(%d,%s)", ret, errmsg);
851                 _destroy_client_info(client_info);
852                 return -1;
853         }
854
855         ret = cynara_creds_socket_get_user(fd, USER_METHOD_UID, &(client_info->uid));
856         if (CYNARA_API_SUCCESS != ret) {
857                 cynara_strerror(ret, errmsg, sizeof(errmsg));
858                 ERROR("cynara_creds_socket_get_user() Fail(%d,%s)", ret, errmsg);
859                 _destroy_client_info(client_info);
860                 return -1;
861         }
862
863         ret = cynara_creds_socket_get_pid(fd, &pid);
864         if (CYNARA_API_SUCCESS != ret) {
865                 cynara_strerror(ret, errmsg, sizeof(errmsg));
866                 ERROR("cynara_creds_socket_get_pid() Fail(%d,%s)", ret, errmsg);
867                 _destroy_client_info(client_info);
868                 return -1;
869         }
870
871         client_info->client_session = cynara_session_from_pid(pid);
872         if (NULL == client_info->client_session) {
873                 ERROR("cynara_session_from_pid() return NULL");
874                 _destroy_client_info(client_info);
875                 return -1;
876         }
877         *p_client_info = client_info;
878
879         return 0;
880 }
881
882 static pims_ipc_client_info_s* _clone_client_info(pims_ipc_client_info_s *client_info)
883 {
884         if (NULL == client_info) {
885                 ERROR("client_info is NULL");
886                 return NULL;
887         }
888
889         pims_ipc_client_info_s *clone = calloc(1, sizeof(pims_ipc_client_info_s));
890         if (NULL == clone) {
891                 ERROR("calloc() Fail");
892                 return NULL;
893         }
894
895         if (client_info->smack) {
896                 clone->smack = strdup(client_info->smack);
897                 if (NULL == clone->smack) {
898                         ERROR("strdup() Fail");
899                         _destroy_client_info(clone);
900                         return NULL;
901                 }
902         }
903
904         if (client_info->uid) {
905                 clone->uid = strdup(client_info->uid);
906                 if (NULL == clone->uid) {
907                         ERROR("strdup() Fail");
908                         _destroy_client_info(clone);
909                         return NULL;
910                 }
911         }
912
913         if (client_info->client_session) {
914                 clone->client_session = strdup(client_info->client_session);
915                 if (NULL == clone->client_session) {
916                         ERROR("strdup() Fail");
917                         _destroy_client_info(clone);
918                         return NULL;
919                 }
920         }
921
922         return clone;
923 }
924
925
926 static int __process_router_event(pims_ipc_svc_s *ipc_svc, gboolean for_queue)
927 {
928         gboolean is_valid = FALSE;
929         pims_ipc_request_s *data_queue = NULL;
930         GList *queue_cursor = NULL;
931         int worker_fd = 0;
932         char *client_id = NULL;
933         int *org_fd;
934         int ret;
935
936         do {
937                 pthread_mutex_lock(&ipc_svc->request_data_queue_mutex);
938                 queue_cursor = g_list_first(ipc_svc->request_queue);
939                 if (NULL == queue_cursor) {
940                         pthread_mutex_unlock(&ipc_svc->request_data_queue_mutex);
941                         return 0;
942                 }
943                 client_id = (char *)(queue_cursor->data);
944                 ASSERT(client_id != NULL);
945                 pthread_mutex_unlock(&ipc_svc->request_data_queue_mutex);
946
947                 ret = g_hash_table_lookup_extended(ipc_svc->request_data_queue, (void*)client_id, (gpointer*)&org_fd, (gpointer*)&data_queue);
948
949                 if (for_queue)
950                         ipc_svc->delay_count--;
951
952                 if (ret == TRUE && data_queue) {
953                         int *org_fd;
954                         pims_ipc_worker_data_s *worker_data = NULL;
955
956                         pthread_mutex_lock(&data_queue->raw_data_mutex);
957                         GList *cursor = g_list_first(data_queue->raw_data);
958                         if (!cursor) {
959                                 pthread_mutex_unlock(&data_queue->raw_data_mutex);
960                                 break;
961                         }
962
963                         pims_ipc_raw_data_s *data = (pims_ipc_raw_data_s*)(cursor->data);
964                         if (NULL == data) {
965                                 ERROR("data is NULL");
966                                 pthread_mutex_unlock(&data_queue->raw_data_mutex);
967                                 break;
968                         }
969                         char *call_id = data->call_id;
970                         int client_fd = data_queue->client_fd;
971
972                         ASSERT(call_id != NULL);
973
974                         VERBOSE("call_id = [%s]", call_id);
975                         if (strcmp(PIMS_IPC_CALL_ID_CREATE, call_id) == 0) {
976                                 // Get a worker. If cannot get a worker, create a worker and enqueue a current request
977                                 __launch_thread(__worker_loop, ipc_svc);
978                                 if (__get_worker((const char*)client_id, &worker_fd) != 0) {
979                                         ipc_svc->delay_count++;
980                                         pthread_mutex_unlock(&data_queue->raw_data_mutex);
981                                         is_valid = TRUE;
982                                         break;
983                                 }
984                                 int worker_id = _find_worker_id(ipc_svc, worker_fd);
985                                 pthread_mutex_lock(&ipc_svc->client_info_mutex);
986                                 pims_ipc_client_info_s *client_info = g_hash_table_lookup(ipc_svc->client_info_map, client_id);
987                                 pims_ipc_client_info_s *client_info_clone = _clone_client_info(client_info);
988                                 g_hash_table_insert(ipc_svc->worker_client_info_map, GINT_TO_POINTER(worker_id), client_info_clone);
989                                 pthread_mutex_unlock(&ipc_svc->client_info_mutex);
990                         }
991                         else {
992                                 // Find a worker
993                                 if (__find_worker((const char*)client_id, &worker_fd) != 0) {
994                                         ERROR("unable to find a worker");
995                                         pthread_mutex_unlock(&data_queue->raw_data_mutex);
996                                         break;
997                                 }
998                         }
999                         pthread_mutex_unlock(&data_queue->raw_data_mutex);
1000
1001                         VERBOSE("routing client_id : %s, seq_no: %d, client_fd = %d, worker fd = %d", client_id, data->seq_no, client_fd, worker_fd);
1002
1003                         if (worker_fd <= 0)
1004                                 break;
1005
1006                         pthread_mutex_lock(&ipc_svc->task_fds_mutex);
1007                         if (FALSE == g_hash_table_lookup_extended(ipc_svc->task_fds,
1008                                                 GINT_TO_POINTER(worker_fd), (gpointer*)&org_fd, (gpointer*)&worker_data)) {
1009                                 ERROR("hash lookup fail : worker_fd (%d)", worker_fd);
1010                                 pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
1011                                 break;
1012                         }
1013
1014                         if (__request_pop(data_queue, &data)) {
1015                                 __worker_raw_data_push(worker_data, client_fd, data);
1016                                 write_command(worker_fd, 1);
1017                         }
1018
1019                         pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
1020                 }
1021
1022                 pthread_mutex_lock(&ipc_svc->request_data_queue_mutex);
1023                 free(client_id);
1024                 ipc_svc->request_queue = g_list_delete_link(ipc_svc->request_queue, queue_cursor);
1025                 pthread_mutex_unlock(&ipc_svc->request_data_queue_mutex);
1026
1027                 is_valid = TRUE;
1028         } while (0);
1029
1030         if (is_valid == FALSE)
1031                 return -1;
1032
1033         return 1;
1034 }
1035
1036 static int __process_manager_event(pims_ipc_svc_s *ipc_svc)
1037 {
1038         GList *cursor = NULL;
1039         int worker_fd;
1040
1041         // client socket terminated without disconnect request
1042         pthread_mutex_lock(&ipc_svc->manager_queue_from_epoll_mutex);
1043         if (ipc_svc->manager_queue_from_epoll) {
1044                 cursor = g_list_first(ipc_svc->manager_queue_from_epoll);
1045                 char *client_id = (char*)cursor->data;
1046                 __find_worker(client_id, &worker_fd);
1047
1048                 ipc_svc->manager_queue_from_epoll = g_list_delete_link(ipc_svc->manager_queue_from_epoll, cursor);
1049                 pthread_mutex_unlock(&ipc_svc->manager_queue_from_epoll_mutex);
1050
1051                 // remove client_fd
1052                 g_hash_table_remove(ipc_svc->client_worker_map, client_id);
1053                 free(client_id);
1054
1055                 // stop worker thread
1056                 if (worker_fd) {
1057                         int *org_fd;
1058                         pims_ipc_worker_data_s *worker_data;
1059
1060                         pthread_mutex_lock(&ipc_svc->task_fds_mutex);
1061                         if (FALSE == g_hash_table_lookup_extended(ipc_svc->task_fds,
1062                                                 GINT_TO_POINTER(worker_fd), (gpointer*)&org_fd, (gpointer*)&worker_data)) {
1063                                 ERROR("g_hash_table_lookup_extended fail : worker_fd (%d)", worker_fd);
1064                                 pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
1065                                 return -1;
1066                         }
1067                         worker_data->stop_thread = true;
1068                         worker_data->client_fd = -1;
1069                         pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
1070
1071                         write_command(worker_fd, 1);
1072                         VERBOSE("write command to worker terminate (worker_fd : %d)", worker_fd);
1073                 }
1074                 return 0;
1075         }
1076         pthread_mutex_unlock(&ipc_svc->manager_queue_from_epoll_mutex);
1077
1078         // create new worker
1079         pthread_mutex_lock(&ipc_svc->manager_queue_from_worker_mutex);
1080         if (ipc_svc->manager_queue_from_worker) {
1081
1082                 cursor = g_list_first(ipc_svc->manager_queue_from_worker);
1083                 while (cursor) {
1084                         worker_fd = (int)cursor->data;
1085                         ipc_svc->manager_queue_from_worker = g_list_delete_link(ipc_svc->manager_queue_from_worker, cursor);
1086
1087                         if (worker_fd) {
1088                                 DEBUG("add idle worker_fd : %d", worker_fd);
1089                                 ipc_svc->workers = g_list_append(ipc_svc->workers, (void*)worker_fd);
1090                         }
1091                         cursor = g_list_first(ipc_svc->manager_queue_from_worker);
1092                 }
1093                 pthread_mutex_unlock(&ipc_svc->manager_queue_from_worker_mutex);
1094                 return 0;
1095         }
1096         pthread_mutex_unlock(&ipc_svc->manager_queue_from_worker_mutex);
1097
1098         return 0;
1099 }
1100
1101 // if delete = true, steal client_id, then free(client_id)
1102 // if delete = false, return client_id pointer, then do no call free(client_id
1103 static int __find_client_id(pims_ipc_svc_s *ipc_svc, int client_fd, bool delete, char **client_id)
1104 {
1105         pims_ipc_client_map_s *client;
1106         GList *cursor = NULL;
1107         cursor = g_list_first(ipc_svc->client_id_fd_map);
1108         while(cursor) {
1109                 client = cursor->data;
1110                 if (client->fd == client_fd) {
1111                         *client_id = client->id;
1112                         if (delete) {
1113                                 client->id = NULL;
1114                                 ipc_svc->client_id_fd_map = g_list_delete_link(ipc_svc->client_id_fd_map, cursor);                      //free(client);
1115                                 free(client);
1116                         }
1117                         return 0;
1118                 }
1119                 cursor = g_list_next(cursor);
1120         }
1121         return -1;
1122 }
1123
1124 static void __request_push(pims_ipc_svc_s *ipc_svc, char *client_id, int client_fd, pims_ipc_raw_data_s *data)
1125 {
1126         int ret;
1127         int *org_fd;
1128         pims_ipc_request_s *data_queue = NULL;
1129         if (NULL == data) {
1130                 ERROR("data is NULL");
1131                 return;
1132         }
1133
1134         pthread_mutex_lock(&ipc_svc->request_data_queue_mutex);
1135         ret = g_hash_table_lookup_extended(ipc_svc->request_data_queue, (void*)client_id, (gpointer*)&org_fd,(gpointer*)&data_queue);
1136         if (ret == TRUE && data_queue) {
1137         }
1138         else {
1139                 data_queue = calloc(1, sizeof(pims_ipc_request_s));
1140                 if (NULL == data_queue) {
1141                         ERROR("calloc() Fail");
1142                         pthread_mutex_unlock(&ipc_svc->request_data_queue_mutex);
1143                         return;
1144                 }
1145                 data_queue->request_count = 0;
1146                 pthread_mutex_init(&data_queue->raw_data_mutex, 0);
1147
1148                 g_hash_table_insert(ipc_svc->request_data_queue, g_strdup(client_id), data_queue);
1149         }
1150         ipc_svc->request_queue = g_list_append(ipc_svc->request_queue, g_strdup(client_id));
1151         pthread_mutex_unlock(&ipc_svc->request_data_queue_mutex);
1152
1153         pthread_mutex_lock(&data_queue->raw_data_mutex);
1154         data_queue->raw_data = g_list_append(data_queue->raw_data, data);
1155         data_queue->client_fd = client_fd;
1156         data_queue->request_count++;
1157         pthread_mutex_unlock(&data_queue->raw_data_mutex);
1158 }
1159
1160 static void __delete_request_queue(pims_ipc_svc_s *ipc_svc, char *client_id)
1161 {
1162         pims_ipc_request_s *data_queue = NULL;
1163         int ret;
1164         int *org_fd;
1165         GList *l;
1166         GList *cursor;
1167
1168         pthread_mutex_lock(&ipc_svc->request_data_queue_mutex);
1169         ret = g_hash_table_lookup_extended(ipc_svc->request_data_queue, (void*)client_id, (gpointer*)&org_fd,(gpointer*)&data_queue);
1170         if (ret == TRUE)
1171                 g_hash_table_remove(ipc_svc->request_data_queue, (void*)client_id);
1172
1173         cursor = g_list_first(ipc_svc->request_queue);
1174         while (cursor) {
1175                 l = cursor;
1176                 char *id = l->data;
1177                 cursor = g_list_next(cursor);
1178                 if (id && strcmp(id, client_id) == 0) {
1179                         free(id);
1180                         ipc_svc->request_queue = g_list_delete_link(ipc_svc->request_queue, l);
1181                 }
1182         }
1183         pthread_mutex_unlock(&ipc_svc->request_data_queue_mutex);
1184
1185         if (data_queue) {
1186                 pthread_mutex_lock(&data_queue->raw_data_mutex);
1187                 cursor = g_list_first(data_queue->raw_data);
1188                 pims_ipc_raw_data_s *data;
1189                 while(cursor) {
1190                         l = cursor;
1191                         data = (pims_ipc_raw_data_s *)cursor->data;
1192                         cursor = g_list_next(cursor);
1193                         data_queue->raw_data = g_list_delete_link(data_queue->raw_data, l);
1194                         __free_raw_data(data);
1195                 }
1196                 g_list_free(data_queue->raw_data);
1197                 pthread_mutex_unlock(&data_queue->raw_data_mutex);
1198                 pthread_mutex_destroy(&data_queue->raw_data_mutex);
1199                 free(data_queue);
1200         }
1201 }
1202
1203 static int __send_identify(int fd, unsigned int seq_no, char *id, int id_len)
1204 {
1205         int len = sizeof(unsigned int)                                  // total size
1206                 + id_len + sizeof(unsigned int)         // id
1207                 + sizeof(unsigned int);                         // seq_no
1208
1209         char buf[len+1];
1210
1211         int length = 0;
1212         memset(buf, 0x0, len+1);
1213
1214         // total len
1215         memcpy(buf, (void*)&len, sizeof(unsigned int));
1216         length += sizeof(unsigned int);
1217
1218         // id
1219         memcpy(buf+length, (void*)&(id_len), sizeof(unsigned int));
1220         length += sizeof(unsigned int);
1221         memcpy(buf+length, (void*)(id), id_len);
1222         length += id_len;
1223
1224         // seq_no
1225         memcpy(buf+length, (void*)&(seq_no), sizeof(unsigned int));
1226         length += sizeof(unsigned int);
1227
1228         return socket_send(fd, buf, length);
1229 }
1230
1231 static int __recv_raw_data(int fd, pims_ipc_raw_data_s **data, bool *identity)
1232 {
1233         int len = 0;
1234         pims_ipc_raw_data_s *temp;
1235
1236         /* read the size of message. note that ioctl is non-blocking */
1237         if (ioctl(fd, FIONREAD, &len)) {
1238                 ERROR("ioctl failed: %d", errno);
1239                 return -1;
1240         }
1241
1242         /* when server or client closed socket */
1243         if (len == 0) {
1244                 INFO("[IPC Socket] connection is closed");
1245                 return 0;
1246         }
1247
1248         temp = (pims_ipc_raw_data_s*)calloc(1, sizeof(pims_ipc_raw_data_s));
1249         if (NULL == temp) {
1250                 ERROR("calloc() Fail");
1251                 return -1;
1252         }
1253         temp->client_id = NULL;
1254         temp->client_id_len = 0;
1255         temp->call_id = NULL;
1256         temp->call_id_len = 0;
1257         temp->seq_no = 0;
1258         temp->is_data = FALSE;
1259         temp->data = NULL;
1260         temp->data_len = 0;
1261
1262         int ret = 0;
1263         int read_len = 0;
1264         unsigned int total_len = 0;
1265         unsigned int is_data = FALSE;
1266
1267         do {
1268                 // total length
1269                 ret = TEMP_FAILURE_RETRY(read(fd, (void *)&total_len, sizeof(unsigned int)));
1270                 if (ret < 0) {   ERROR("read error"); break;            }
1271                 read_len += ret;
1272
1273                 // client_id
1274                 ret  = TEMP_FAILURE_RETRY(read(fd, (void *)&(temp->client_id_len), sizeof(unsigned int)));
1275                 if (ret < 0) {   ERROR("read error"); break;            }
1276                 read_len += ret;
1277
1278                 temp->client_id = calloc(1, temp->client_id_len+1);
1279                 if (NULL == temp->client_id) {
1280                         ERROR("calloc() Fail");
1281                         ret = -1;
1282                         break;
1283                 }
1284                 ret = socket_recv(fd, (void *)&(temp->client_id), temp->client_id_len);
1285                 if (ret < 0) {
1286                         ERROR("socket_recv error(%d)", ret);
1287                         break;
1288                 }
1289                 read_len += ret;
1290
1291                 // sequnce no
1292                 ret = TEMP_FAILURE_RETRY(read(fd, (void *)&(temp->seq_no), sizeof(unsigned int)));
1293                 if (ret < 0) {   ERROR("read error"); break;            }
1294                 read_len += ret;
1295
1296                 if (total_len == read_len) {
1297                         *data = temp;
1298                         *identity = true;
1299                         return read_len;
1300                 }
1301
1302                 // call_id
1303                 ret  = TEMP_FAILURE_RETRY(read(fd, (void *)&(temp->call_id_len), sizeof(unsigned int)));
1304                 if (ret < 0)    { ERROR("read error"); break;           }
1305                 read_len += ret;
1306
1307                 temp->call_id = calloc(1, temp->call_id_len+1);
1308                 if (NULL == temp->call_id) {
1309                         ERROR("calloc() Fail");
1310                         ret = -1;
1311                         break;
1312                 }
1313                 ret = socket_recv(fd, (void *)&(temp->call_id), temp->call_id_len);
1314                 if (ret < 0) {
1315                         ERROR("socket_recv error(%d)", ret);
1316                         break;
1317                 }
1318                 read_len += ret;
1319
1320                 // is_data
1321                 ret = TEMP_FAILURE_RETRY(read(fd, (void *)&(is_data), sizeof(unsigned int)));
1322                 if (ret < 0) {   ERROR("read error"); break;            }
1323                 read_len += ret;
1324
1325                 // data
1326                 if (is_data) {
1327                         temp->is_data = TRUE;
1328                         ret = TEMP_FAILURE_RETRY(read(fd, (void *)&(temp->data_len), sizeof(unsigned int)));
1329                         if (ret < 0) {  ERROR("read error"); break;             }
1330                         read_len += ret;
1331
1332                         temp->data = calloc(1, temp->data_len+1);
1333                         if (NULL == temp->data) {
1334                                 ERROR("calloc() Fail");
1335                                 ret = -1;
1336                                 break;
1337                         }
1338                         ret = socket_recv(fd, (void *)&(temp->data), temp->data_len);
1339                         if (ret < 0) {
1340                                 ERROR("socket_recv error(%d)", ret);
1341                                 break;
1342                         }
1343                         read_len += ret;
1344                 }
1345
1346                 INFO("client_id : %s, call_id : %s, seq_no : %d", temp->client_id, temp->call_id, temp->seq_no);
1347
1348                 *data = temp;
1349                 *identity = false;
1350         } while(0);
1351
1352         if (ret < 0) {
1353                 ERROR("total_len(%d) client_id_len(%d)", total_len, temp->client_id_len);
1354                 __free_raw_data(temp);
1355                 *data = NULL;
1356                 *identity = false;
1357                 return -1;
1358         }
1359
1360         return read_len;
1361 }
1362
1363 static gboolean __request_handler(GIOChannel *src, GIOCondition condition, gpointer data)
1364 {
1365         int ret;
1366         int event_fd = g_io_channel_unix_get_fd(src);
1367         char *client_id = NULL;
1368         pims_ipc_svc_s *ipc_svc = (pims_ipc_svc_s*)data;
1369         if (NULL == ipc_svc) {
1370                 ERROR("ipc_svc is NULL");
1371                 return FALSE;
1372         }
1373
1374         if (G_IO_HUP & condition) {
1375                 INFO("client closed ------------------------client_fd : %d", event_fd);
1376
1377                 close(event_fd);
1378
1379                 // Find client_id
1380                 __find_client_id(ipc_svc, event_fd, true, &client_id);
1381
1382                 // Send client_id to manager to terminate worker thread
1383                 if (client_id) {
1384                         pthread_mutex_lock(&ipc_svc->client_info_mutex);
1385                         g_hash_table_remove(ipc_svc->client_info_map, client_id);
1386                         pthread_mutex_unlock(&ipc_svc->client_info_mutex);
1387
1388                         pthread_mutex_lock(&ipc_svc->manager_queue_from_epoll_mutex);
1389                         ipc_svc->manager_queue_from_epoll = g_list_append(ipc_svc->manager_queue_from_epoll, (void*)g_strdup(client_id));
1390                         pthread_mutex_unlock(&ipc_svc->manager_queue_from_epoll_mutex);
1391                         write_command(ipc_svc->manager, 1);
1392                         __delete_request_queue(ipc_svc, client_id);
1393                         free(client_id);
1394                 }
1395
1396                 return FALSE;
1397         }
1398
1399         // receive data from client
1400         int recv_len;
1401         bool identity = false;
1402         pims_ipc_raw_data_s *req = NULL;
1403
1404         recv_len = __recv_raw_data(event_fd, &req, &identity);
1405         if (recv_len > 0) {
1406                 // send command to router
1407                 if (identity) {
1408                         pims_ipc_client_map_s *client = (pims_ipc_client_map_s*)calloc(1, sizeof(pims_ipc_client_map_s));
1409                         if (NULL == client) {
1410                                 ERROR("calloc() Fail");
1411                                 close(event_fd);
1412                                 return FALSE;
1413                         }
1414
1415                         client->fd = event_fd;
1416
1417                         char temp[100];
1418                         snprintf(temp, sizeof(temp), "%d_%s", ipc_svc->unique_sequence_number++, req->client_id);
1419                         client->id = strdup(temp);
1420                         free(req->client_id);
1421                         req->client_id = NULL;
1422                         ipc_svc->client_id_fd_map = g_list_append(ipc_svc->client_id_fd_map, client);
1423
1424                         // send server pid to client
1425                         snprintf(temp, sizeof(temp), "%x", getpid());
1426                         ret = __send_identify(event_fd, req->seq_no, temp, strlen(temp));
1427
1428                         __free_raw_data(req);
1429                         if (ret < 0) {
1430                                 ERROR("__send_identify() Fail(%d)", ret);
1431                                 close(event_fd);
1432                                 return FALSE;
1433                         }
1434
1435                         pims_ipc_client_info_s *client_info = NULL;
1436                         if (0 != _create_client_info(event_fd, &client_info))
1437                                 ERROR("_create_client_info() Fail");
1438                         pthread_mutex_lock(&ipc_svc->client_info_mutex);
1439                         g_hash_table_insert(ipc_svc->client_info_map, g_strdup(client->id), client_info);
1440                         pthread_mutex_unlock(&ipc_svc->client_info_mutex);
1441
1442                         return TRUE;
1443                 }
1444
1445                 __find_client_id(ipc_svc, event_fd, false, &client_id);
1446
1447                 if (client_id) {
1448                         __request_push(ipc_svc, client_id, event_fd, req);
1449                         write_command(ipc_svc->router, 1);
1450                 }
1451                 else
1452                         ERROR("__find_client_id fail : event_fd (%d)", event_fd);
1453         }
1454         else {
1455                 ERROR("receive invalid : %d", event_fd);
1456                 close(event_fd);
1457                 return FALSE;
1458         }
1459
1460         return TRUE;
1461 }
1462
1463 static gboolean __socket_handler(GIOChannel *src, GIOCondition condition, gpointer data)
1464 {
1465         GIOChannel *channel;
1466         pims_ipc_svc_s *ipc_svc = (pims_ipc_svc_s*)data;
1467         int client_sockfd = -1;
1468         int sockfd = ipc_svc->sockfd;
1469         struct sockaddr_un clientaddr;
1470         socklen_t client_len = sizeof(clientaddr);
1471
1472         client_sockfd = accept(sockfd, (struct sockaddr *)&clientaddr, &client_len);
1473         if (-1 == client_sockfd) {
1474                 char *errmsg = NULL;
1475                 char buf[1024] = {0};
1476                 errmsg = strerror_r(errno, buf, sizeof(buf));
1477                 if (errmsg)
1478                         ERROR("accept error : %s", errmsg);
1479                 return TRUE;
1480         }
1481
1482         channel = g_io_channel_unix_new(client_sockfd);
1483         g_io_add_watch(channel, G_IO_IN|G_IO_HUP, __request_handler, data);
1484         g_io_channel_unref(channel);
1485
1486         return TRUE;
1487 }
1488
1489 static void* __main_loop(void *user_data)
1490 {
1491         int ret;
1492         struct sockaddr_un addr;
1493         GIOChannel *gio = NULL;
1494         pims_ipc_svc_s *ipc_svc = (pims_ipc_svc_s*)user_data;
1495
1496         if (sd_listen_fds(1) == 1 && sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_STREAM, -1, ipc_svc->service, 0) > 0) {
1497                  ipc_svc->sockfd = SD_LISTEN_FDS_START;
1498         }
1499         else {
1500                 unlink(ipc_svc->service);
1501                 ipc_svc->sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
1502
1503                 bzero(&addr, sizeof(addr));
1504                 addr.sun_family = AF_UNIX;
1505                 snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", ipc_svc->service);
1506
1507                 ret = bind(ipc_svc->sockfd, (struct sockaddr *)&addr, sizeof(addr));
1508                 if (ret != 0)
1509                         ERROR("bind error :%d", ret);
1510                 ret = listen(ipc_svc->sockfd, 30);
1511
1512                 ret = chown(ipc_svc->service, getuid(), ipc_svc->group);
1513                 ret = chmod(ipc_svc->service, ipc_svc->mode);
1514         }
1515
1516         gio = g_io_channel_unix_new(ipc_svc->sockfd);
1517
1518         g_io_add_watch(gio, G_IO_IN, __socket_handler, (gpointer)ipc_svc);
1519
1520         return NULL;
1521 }
1522
1523 static int __open_router_fd(pims_ipc_svc_s *ipc_svc)
1524 {
1525         int ret = -1;
1526         int flags;
1527         int router;
1528         int manager;
1529
1530         // router inproc eventfd
1531         router = eventfd(0,0);
1532         if (-1 == router) {
1533                 ERROR("eventfd error : %d", errno);
1534                 return -1;
1535         }
1536         VERBOSE("router :%d\n", router);
1537
1538         flags = fcntl(router, F_GETFL, 0);
1539         if (flags == -1)
1540                 flags = 0;
1541         ret = fcntl (router, F_SETFL, flags | O_NONBLOCK);
1542         if (0 != ret)
1543                 VERBOSE("rounter fcntl : %d\n", ret);
1544
1545         // manager inproc eventfd
1546         manager = eventfd(0,0);
1547         if (-1 == manager) {
1548                 ERROR("eventfd error : %d", errno);
1549                 close(router);
1550                 return -1;
1551         }
1552         VERBOSE("manager :%d\n", manager);
1553
1554         flags = fcntl(manager, F_GETFL, 0);
1555         if (flags == -1)
1556                 flags = 0;
1557         ret = fcntl (manager, F_SETFL, flags | O_NONBLOCK);
1558         if (0 != ret)
1559                 VERBOSE("manager fcntl : %d\n", ret);
1560
1561         ipc_svc->router = router;
1562         ipc_svc->manager = manager;
1563
1564         return 0;
1565 }
1566
1567 static void __close_router_fd(pims_ipc_svc_s *ipc_svc)
1568 {
1569         close(ipc_svc->router);
1570         close(ipc_svc->manager);
1571 }
1572
1573 static void* __publish_loop(void *user_data)
1574 {
1575         int ret;
1576         int epfd;
1577
1578         struct sockaddr_un addr;
1579         struct epoll_event ev = {0};
1580         pims_ipc_svc_for_publish_s *ipc_svc = (pims_ipc_svc_for_publish_s*)user_data;
1581
1582         unlink(ipc_svc->service);
1583         ipc_svc->publish_sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
1584
1585         bzero(&addr, sizeof(struct sockaddr_un));
1586         addr.sun_family = AF_UNIX;
1587         snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", ipc_svc->service);
1588
1589         int flags = fcntl (ipc_svc->publish_sockfd, F_GETFL, 0);
1590         if (flags == -1)
1591                 flags = 0;
1592         ret = fcntl (ipc_svc->publish_sockfd, F_SETFL, flags | O_NONBLOCK);
1593         VERBOSE("publish socketfd fcntl : %d\n", ret);
1594
1595         ret = bind(ipc_svc->publish_sockfd, (struct sockaddr *)&(addr), sizeof(struct sockaddr_un));
1596         if (ret != 0)
1597                 ERROR("bind error :%d", ret);
1598         ret = listen(ipc_svc->publish_sockfd, 30);
1599         WARN_IF(ret != 0, "listen error :%d", ret);
1600
1601         ret = chown(ipc_svc->service, getuid(), ipc_svc->group);
1602         WARN_IF(ret != 0, "chown error :%d", ret);
1603         ret = chmod(ipc_svc->service, ipc_svc->mode);
1604         WARN_IF(ret != 0, "chmod error :%d", ret);
1605
1606         epfd = epoll_create(MAX_EPOLL_EVENT);
1607
1608         ev.events = EPOLLIN | EPOLLHUP;
1609         ev.data.fd = ipc_svc->publish_sockfd;
1610
1611         ret = epoll_ctl(epfd, EPOLL_CTL_ADD, ipc_svc->publish_sockfd, &ev);
1612         WARN_IF(ret != 0, "listen error :%d", ret);
1613
1614         while (!ipc_svc->epoll_stop_thread) {
1615                 int i = 0;
1616                 struct epoll_event events[MAX_EPOLL_EVENT] = {{0}, };
1617                 int event_num = epoll_wait(epfd, events, MAX_EPOLL_EVENT, -1);
1618
1619                 if (ipc_svc->epoll_stop_thread)
1620                         break;
1621
1622                 if (event_num == -1) {
1623                         if (errno != EINTR) {
1624                                 ERROR("errno:%d\n", errno);
1625                                 break;
1626                         }
1627                 }
1628
1629                 for (i = 0; i < event_num; i++) {
1630                         int event_fd = events[i].data.fd;
1631
1632                         if (events[i].events & EPOLLHUP) {
1633                                 VERBOSE("client closed -----------------------------------------:%d", event_fd);
1634                                 if (epoll_ctl(epfd, EPOLL_CTL_DEL, event_fd, events) == -1) {
1635                                         ERROR("epoll_ctl (EPOLL_CTL_DEL) fail : errno(%d)", errno);
1636                                 }
1637                                 close(event_fd);
1638
1639                                 // Find client_id and delete
1640                                 GList *cursor = NULL;
1641
1642                                 pthread_mutex_lock(&ipc_svc->subscribe_fds_mutex);
1643                                 cursor = g_list_first(ipc_svc->subscribe_fds);
1644                                 while (cursor) {
1645                                         if (event_fd == (int)cursor->data) {
1646                                                 ipc_svc->subscribe_fds = g_list_delete_link(ipc_svc->subscribe_fds, cursor);
1647                                                 break;
1648                                         }
1649                                         cursor = g_list_next(cursor);
1650                                 }
1651                                 pthread_mutex_unlock(&ipc_svc->subscribe_fds_mutex);
1652                                 continue;
1653                         }
1654                         else if (event_fd == ipc_svc->publish_sockfd) {         // connect client
1655                                 struct sockaddr_un remote;
1656                                 int remote_len = sizeof(remote);
1657                                 int client_fd = accept(ipc_svc->publish_sockfd, (struct sockaddr *)&remote, (socklen_t*) &remote_len);
1658                                 if (client_fd == -1) {
1659                                         ERROR("accept fail : errno : %d", errno);
1660                                         continue;
1661                                 }
1662                                 VERBOSE("client subscriber connect: %d", client_fd);
1663
1664                                 pthread_mutex_lock(&ipc_svc->subscribe_fds_mutex);
1665                                 ipc_svc->subscribe_fds = g_list_append(ipc_svc->subscribe_fds, (void*)client_fd);
1666                                 pthread_mutex_unlock(&ipc_svc->subscribe_fds_mutex);
1667
1668                                 ev.events = EPOLLIN;
1669                                 ev.data.fd = client_fd;
1670                                 if (epoll_ctl(epfd, EPOLL_CTL_ADD, client_fd, &ev) == -1) {
1671                                         ERROR("epoll_ctl (EPOLL_CTL_ADD) fail : error(%d)\n", errno);
1672                                         continue;
1673                                 }
1674                         }
1675                 }
1676         }
1677
1678         close(ipc_svc->publish_sockfd);
1679         close(epfd);
1680
1681         return NULL;
1682 }
1683
1684 static void __stop_for_publish(pims_ipc_svc_for_publish_s *ipc_svc)
1685 {
1686         ipc_svc->epoll_stop_thread = true;
1687 }
1688
1689 static void* __router_loop(void *data)
1690 {
1691         pims_ipc_svc_s *ipc_svc = (pims_ipc_svc_s*)data;
1692         int fd_count = 2;
1693         struct pollfd *pollfds;
1694
1695         pollfds = (struct pollfd*)calloc(fd_count, sizeof(struct pollfd));
1696         if (NULL == pollfds) {
1697                 ERROR("calloc() Fail");
1698                 return NULL;
1699         }
1700         pollfds[0].fd = ipc_svc->router;
1701         pollfds[0].events = POLLIN;
1702         pollfds[1].fd = ipc_svc->manager;
1703         pollfds[1].events = POLLIN;
1704
1705         while (1) {
1706                 int ret = -1;
1707                 uint64_t dummy;
1708                 int check_router_queue = -1;
1709                 int check_manager_queue = -1;
1710
1711                 while (1) {
1712                         ret = poll(pollfds, fd_count, 1000);
1713                         if (ret == -1 && errno == EINTR) {
1714                                 //free (pollfds);
1715                                 continue;               //return NULL;
1716                         }
1717                         break;
1718                 }
1719
1720                 if (ret > 0) {
1721                         if (pollfds[0].revents & POLLIN) {
1722                                 // request router: send request to worker
1723                                 if (sizeof (dummy) == read_command(pollfds[0].fd, &dummy)) {
1724                                         check_router_queue = __process_router_event(ipc_svc, false);
1725                                 }
1726                         }
1727
1728                         if (pollfds[1].revents & POLLIN) {
1729                                 // worker manager
1730                                 if (sizeof (dummy) == read_command(pollfds[1].fd, &dummy)) {
1731                                         check_manager_queue = __process_manager_event(ipc_svc);
1732                                         if (ipc_svc->delay_count > 0)
1733                                                 check_router_queue = __process_router_event(ipc_svc, true);
1734                                 }
1735                         }
1736                 }
1737
1738                 // check queue
1739                 while(check_router_queue > 0 || check_manager_queue > 0) {
1740                         read_command(pollfds[0].fd, &dummy);
1741                         check_router_queue = __process_router_event(ipc_svc, false);
1742
1743                         read_command(pollfds[1].fd, &dummy);
1744                         check_manager_queue = __process_manager_event(ipc_svc);
1745                         if (ipc_svc->delay_count > 0)
1746                                 check_router_queue = __process_router_event(ipc_svc, true);
1747                 }
1748         }
1749
1750         free(pollfds);
1751
1752         return NULL;
1753 }
1754
1755 API void pims_ipc_svc_run_main_loop(GMainLoop* loop)
1756 {
1757         int ret = -1;
1758         GMainLoop* main_loop = loop;
1759
1760         if (main_loop == NULL) {
1761                 main_loop = g_main_loop_new(NULL, FALSE);
1762         }
1763
1764         if (_g_singleton_for_publish)
1765                 __launch_thread(__publish_loop, _g_singleton_for_publish);
1766
1767         if (_g_singleton) {
1768                 ret = __open_router_fd(_g_singleton);
1769                 ASSERT(ret == 0);
1770
1771                 int i;
1772                 // launch worker threads in advance
1773                 for (i = 0; i < _g_singleton->workers_max_count; i++)
1774                         __launch_thread(__worker_loop, _g_singleton);
1775
1776                 __launch_thread(__router_loop, _g_singleton);
1777                 __main_loop(_g_singleton);
1778         }
1779
1780         g_main_loop_run(main_loop);
1781
1782         if (_g_singleton)
1783                 __close_router_fd(_g_singleton);
1784
1785         if (_g_singleton_for_publish)
1786                 __stop_for_publish(_g_singleton_for_publish);
1787
1788 }
1789
1790 API void pims_ipc_svc_set_client_disconnected_cb(pims_ipc_svc_client_disconnected_cb callback, void *user_data)
1791 {
1792         if (_client_disconnected_cb.callback) {
1793                 ERROR("already registered");
1794                 return;
1795         }
1796         _client_disconnected_cb.callback = callback;
1797         _client_disconnected_cb.user_data = user_data;
1798 }
1799
1800 API bool pims_ipc_svc_check_privilege(pims_ipc_h ipc, char *privilege)
1801 {
1802         int ret;
1803         int worker_id = (int)ipc;
1804         pims_ipc_client_info_s *client_info = NULL;
1805         pims_ipc_client_info_s *client_info_clone = NULL;
1806
1807         if (NULL == privilege) {
1808                 ERROR("privilege is NULL");
1809                 return false;
1810         }
1811
1812         pthread_mutex_lock(&_g_singleton->client_info_mutex);
1813         client_info = g_hash_table_lookup(_g_singleton->worker_client_info_map, GINT_TO_POINTER(worker_id));
1814         if (NULL == client_info) {
1815                 ERROR("client_info is NULL");
1816                 pthread_mutex_unlock(&_g_singleton->client_info_mutex);
1817                 return false;
1818         }
1819         client_info_clone = _clone_client_info(client_info);
1820         pthread_mutex_unlock(&_g_singleton->client_info_mutex);
1821
1822         if (NULL == client_info_clone) {
1823                 ERROR("client_info_clone is NULL");
1824                 return false;
1825         }
1826
1827         pthread_mutex_lock(&_g_singleton->cynara_mutex);
1828         ret = cynara_check(_g_singleton->cynara, client_info_clone->smack, client_info_clone->client_session, client_info_clone->uid, privilege);
1829         pthread_mutex_unlock(&_g_singleton->cynara_mutex);
1830
1831         _destroy_client_info(client_info_clone);
1832
1833         if (CYNARA_API_ACCESS_ALLOWED == ret)
1834                 return true;
1835
1836         return false;
1837 }
1838
1839 API int pims_ipc_svc_get_smack_label(pims_ipc_h ipc, char **p_smack)
1840 {
1841         pims_ipc_client_info_s *client_info = NULL;
1842         int worker_id = (int)ipc;
1843
1844         pthread_mutex_lock(&_g_singleton->client_info_mutex);
1845         client_info = g_hash_table_lookup(_g_singleton->worker_client_info_map, GINT_TO_POINTER(worker_id));
1846         if (NULL == client_info) {
1847                 ERROR("g_hash_table_lookup(%d) return NULL", worker_id);
1848                 pthread_mutex_unlock(&_g_singleton->client_info_mutex);
1849                 return -1;
1850         }
1851
1852         if (client_info->smack) {
1853                 *p_smack = strdup(client_info->smack);
1854                 if (NULL == *p_smack) {
1855                         ERROR("strdup() return NULL");
1856                         pthread_mutex_unlock(&_g_singleton->client_info_mutex);
1857                         return -1;
1858                 }
1859         }
1860         pthread_mutex_unlock(&_g_singleton->client_info_mutex);
1861
1862         return 0;
1863 }
1864