sync with 2.4 37/36237/1 accepted/tizen/mobile/20150407.084723 accepted/tizen/tv/20150408.012751 accepted/tizen/wearable/20150407.093022 submit/tizen/20150305.070727 submit/tizen/20150403.102047 submit/tizen/20150403.113621 submit/tizen/20150407.053946 submit/tizen/20150407.065406 submit/tizen_common/20150407.131750 submit/tizen_common/20150408.102957
authorJeesun Kim <iamjs.kim@samsung.com>
Wed, 4 Mar 2015 05:37:34 +0000 (14:37 +0900)
committerJeesun Kim <iamjs.kim@samsung.com>
Wed, 4 Mar 2015 05:37:58 +0000 (14:37 +0900)
Change-Id: I9e35f85c00b080de00d598005e6ba77a6aaf79e2

21 files changed:
CMakeLists.txt
include/pims-ipc-data.h
include/pims-ipc-svc.h
include/pims-ipc-types.h
include/pims-ipc.h
packaging/pims-ipc.changes [deleted file]
packaging/pims-ipc.manifest [deleted file]
packaging/pims-ipc.spec
pims-ipc.manifest.in [new file with mode: 0644]
pims-ipc.pc.in
src/pims-debug.h
src/pims-internal.h
src/pims-ipc-data-internal.h [new file with mode: 0644]
src/pims-ipc-data.c
src/pims-ipc-svc.c
src/pims-ipc.c
src/pims-socket.c
src/pims-socket.h
test/CMakeLists.txt [deleted file]
test/sock-test.c [deleted file]
test/test.c [deleted file]

index af1a950..21863e1 100755 (executable)
@@ -15,17 +15,15 @@ SET(EXEC_PREFIX "\${prefix}")
 
 SET(INCLUDEDIR "\${prefix}/${DEST_INCLUDE_DIR}")
 SET(VERSION_MAJOR 0)
-SET(VERSION "${VERSION_MAJOR}.0.28")
+SET(VERSION "${VERSION_MAJOR}.1.6")
 
 INCLUDE_DIRECTORIES(${SRC_INCLUDE_DIR})
-#SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -I${CMAKE_SOURCE_DIR}/src -I${SRC_INCLUDE_DIR} -D_NON_SLP")
 SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -I${CMAKE_SOURCE_DIR}/src -I${SRC_INCLUDE_DIR}")
 
 FILE(GLOB SRCS src/*.c)
 
 INCLUDE(FindPkgConfig)
-#pkg_check_modules(pkgs REQUIRED glib-2.0 gthread-2.0 libzmq)
-pkg_check_modules(pkgs REQUIRED glib-2.0 gthread-2.0 dlog libsystemd-daemon libzmq)
+pkg_check_modules(pkgs REQUIRED glib-2.0 gthread-2.0 dlog libsystemd-daemon)
 
 FOREACH(flag ${pkgs_CFLAGS})
        SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
@@ -33,7 +31,8 @@ ENDFOREACH(flag)
 
 SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
 
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -Wall -g -fPIC -std=c++0x")
 
 ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"")
 
@@ -43,6 +42,7 @@ SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION})
 TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS})
 
 CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY)
+CONFIGURE_FILE(${PROJECT_NAME}.manifest.in ${PROJECT_NAME}.manifest @ONLY)
 SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PROJECT_NAME}.pc")
 
 INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR})
@@ -51,4 +51,3 @@ INSTALL(FILES ${PROJECT_NAME}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
 FILE(GLOB HEADER_FILES ${SRC_INCLUDE_DIR}/*.h)
 INSTALL(FILES ${HEADER_FILES} DESTINATION ${DEST_INCLUDE_DIR})
 
-ADD_SUBDIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/test)
index 5c8e0f4..8d664de 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <pims-ipc-types.h>
 
-#ifdef _cplusplus
+#ifdef __cplusplus
 extern "C"
 {
 #endif
@@ -31,21 +31,11 @@ extern "C"
 
 pims_ipc_data_h pims_ipc_data_create_with_size(unsigned int size, int flags);
 void pims_ipc_data_destroy(pims_ipc_data_h ipc);
-int pims_ipc_data_put(pims_ipc_data_h data, void *buf, unsigned int size);
 void* pims_ipc_data_get(pims_ipc_data_h data, unsigned int *size);
-void* pims_ipc_data_get_dup(pims_ipc_data_h data, unsigned int *size);
-int pims_ipc_data_put_with_type(pims_ipc_data_h data, pims_ipc_data_type_e type, void *buf, unsigned int size);
-void* pims_ipc_data_get_with_type(pims_ipc_data_h data, pims_ipc_data_type_e *type, unsigned int *size);
-void* pims_ipc_data_get_dup_with_type(pims_ipc_data_h data, pims_ipc_data_type_e *type, unsigned int *size);
-
-void* pims_ipc_data_marshal(pims_ipc_data_h data, unsigned int *size);
-int pims_ipc_data_marshal_with_zmq(pims_ipc_data_h data, zmq_msg_t *pzmsg);
-void* pims_ipc_data_marshal_dup(pims_ipc_data_h data, unsigned int *size);
-pims_ipc_data_h pims_ipc_data_unmarshal(void *buf, unsigned int size);
-pims_ipc_data_h pims_ipc_data_unmarshal_with_zmq(zmq_msg_t *pzmsg);
-pims_ipc_data_h pims_ipc_data_unmarshal_dup(void *buf, unsigned int size);
-
-#ifdef _cplusplus
+int pims_ipc_data_put(pims_ipc_data_h data, void *buf, unsigned int size);
+
+
+#ifdef __cplusplus
 }
 #endif
 
index 7946626..918d105 100644 (file)
@@ -23,7 +23,7 @@
 #include <pims-ipc-types.h>
 #include <sys/stat.h>
 
-#ifdef _cplusplus
+#ifdef __cplusplus
 extern "C"
 {
 #endif
@@ -38,7 +38,9 @@ int pims_ipc_svc_publish(char *module, char *event, pims_ipc_data_h data);
 
 void pims_ipc_svc_run_main_loop(GMainLoop* main_loop);
 
-#ifdef _cplusplus
+void pims_ipc_svc_set_client_disconnected_cb(pims_ipc_svc_client_disconnected_cb callback, void *userdata);
+
+#ifdef __cplusplus
 }
 #endif
 
index 54d4c2f..9ea5390 100644 (file)
 #ifndef __PIMS_IPC_TYPES_H__
 #define __PIMS_IPC_TYPES_H__
 
-#include <zmq.h>
 #include <glib.h>
 #include <stdbool.h>
 
 
-#ifdef _cplusplus
+#ifdef __cplusplus
 extern "C"
 {
 #endif
@@ -50,12 +49,15 @@ typedef enum {
     PIMS_IPC_DATA_TYPE_MEMORY,
 } pims_ipc_data_type_e;
 
-typedef void (*pims_ipc_svc_call_cb)(pims_ipc_h ipc, pims_ipc_data_h data_in, 
+typedef void (*pims_ipc_svc_call_cb)(pims_ipc_h ipc, pims_ipc_data_h data_in,
                                     pims_ipc_data_h *data_out, void *userdata);
+typedef void (*pims_ipc_svc_client_disconnected_cb)(pims_ipc_h ipc, void *userdata);
+
 typedef void (*pims_ipc_call_async_cb)(pims_ipc_h ipc, pims_ipc_data_h data_out, void *userdata);
 typedef void (*pims_ipc_subscribe_cb)(pims_ipc_h ipc, pims_ipc_data_h data, void *userdata);
 
-#ifdef _cplusplus
+
+#ifdef __cplusplus
 }
 #endif
 
index fe7837c..b8ba2a5 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <pims-ipc-types.h>
 
-#ifdef _cplusplus
+#ifdef __cplusplus
 extern "C"
 {
 #endif
@@ -40,7 +40,7 @@ void pims_ipc_destroy_for_subscribe(pims_ipc_h ipc);
 int pims_ipc_subscribe(pims_ipc_h ipc, char *module, char *event, pims_ipc_subscribe_cb callback, void *userdata);
 int pims_ipc_unsubscribe(pims_ipc_h ipc, char *module, char *event);
 
-#ifdef _cplusplus
+#ifdef __cplusplus
 }
 #endif
 
diff --git a/packaging/pims-ipc.changes b/packaging/pims-ipc.changes
deleted file mode 100644 (file)
index 5e671d3..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-* Thu Jul 11 2013 Patrick McCarty <patrick.mccarty@linux.intel.com> e96fbe5
-- Remove the manifest template file
-
diff --git a/packaging/pims-ipc.manifest b/packaging/pims-ipc.manifest
deleted file mode 100644 (file)
index 017d22d..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<manifest>
- <request>
-    <domain name="_"/>
- </request>
-</manifest>
index 20f2dec..48237d6 100644 (file)
@@ -1,17 +1,15 @@
 Name:       pims-ipc
 Summary:    library for PIMs IPC
-Version:    0.0.28
+Version:    0.1.6
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0
 Source0:    %{name}-%{version}.tar.gz
-Source1001:    pims-ipc.manifest
 
 BuildRequires: cmake
 BuildRequires: pkgconfig(glib-2.0)
 BuildRequires: pkgconfig(dlog)
 BuildRequires: pkgconfig(libsystemd-daemon)
-BuildRequires: pkgconfig(libzmq)
 
 %description
 library for PIMs IPC
@@ -26,31 +24,32 @@ library for PIMs IPC (developement files)
 
 %prep
 %setup -q
-cp %{SOURCE1001} .
 
 
 %build
+export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
+export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
 %cmake .
 make %{?jobs:-j%jobs}
 
 %install
 %make_install
-
+mkdir -p %{buildroot}/usr/share/license
+cp LICENSE.APLv2 %{buildroot}/usr/share/license/%{name}
 
 %post -p /sbin/ldconfig
 
 %postun -p /sbin/ldconfig
 
-
 %files
-%manifest %{name}.manifest
+%manifest pims-ipc.manifest
 %defattr(-,root,root,-)
 %{_libdir}/libpims-ipc.so.*
+/usr/share/license/%{name}
 
 %files devel
-%manifest %{name}.manifest
 %defattr(-,root,root,-)
 %{_includedir}/pims-ipc/*.h
 %{_libdir}/*.so
-%{_libdir}/pims_ipc_test
 %{_libdir}/pkgconfig/pims-ipc.pc
diff --git a/pims-ipc.manifest.in b/pims-ipc.manifest.in
new file mode 100644 (file)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
index 7528eb1..20e62ee 100755 (executable)
@@ -8,6 +8,6 @@ includedir=@INCLUDE_INSTALL_DIR@/pims-ipc
 Name: @PROJECT_NAME@
 Description: @PROJECT_NAME@ library
 Version: @VERSION@
-Requires: glib-2.0 libzmq
+Requires: glib-2.0
 Libs: -L${libdir} -l@PROJECT_NAME@
 Cflags: -I${includedir}
index 62b7076..d8eaa84 100644 (file)
 #ifndef __PIMS_DEBUG_H__
 #define __PIMS_DEBUG_H__
 
-#ifndef _NON_SLP
-#include <dlog.h>
-#endif
 #include <assert.h>
 
-#ifdef _cplusplus
+#define LOG_TAG     "PIMS_IPC"
+#include <dlog.h>
+
+#ifdef __cplusplus
 extern "C"
 {
 #endif
 
-/* Tag defines */
-#define TAG_IPC     "PIMS_IPC"
-
-/* debug base macro */
-#ifndef _NON_SLP
-#define __ug_log(logtype, tag, frmt, args...) \
-        do {LOG(logtype, tag, "%s:%s(%d) > "frmt"\n", __MODULE__, __FUNCTION__, __LINE__, ##args);} while (0)
-#else
-#define LOG_VERBOSE "VERBOSE"
-#define LOG_DEBUG   "DEBUG"
-#define LOG_INFO    "INFO"
-#define LOG_WARN    "WARN"
-#define LOG_ERROR   "ERROR"
-#define __ug_log(logtype, tag, frmt, args...) \
-        do {printf("[%s][%s][%08x] %s:%s(%d) > "frmt"\n", logtype, tag, (unsigned int)pthread_self(), __FILE__, __FUNCTION__, __LINE__, ##args);} while (0)
-#endif
-
-#define pims_verbose(tag, frmt, args...) __ug_log(LOG_VERBOSE, tag, frmt, ##args)
-#define pims_debug(tag, frmt, args...)   __ug_log(LOG_DEBUG,   tag, frmt, ##args)
-#define pims_info(tag, frmt, args...)    __ug_log(LOG_INFO,    tag, frmt, ##args)
-#define pims_warn(tag, frmt, args...)    __ug_log(LOG_WARN,    tag, frmt, ##args)
-#define pims_error(tag, frmt, args...)   __ug_log(LOG_ERROR,   tag, frmt, ##args)
+#define PIMS_VERBOSE_TAG(frmt, args...) SLOGV(frmt, ##args);
+#define PIMS_DEBUG_TAG(frmt, args...)   SLOGD(frmt, ##args);
+#define PIMS_INFO_TAG(frmt, args...)    SLOGI(frmt, ##args);
+#define PIMS_WARN_TAG(frmt, args...)    SLOGV(frmt, ##args);
+#define PIMS_ERROR_TAG(frmt, args...)   SLOGE(frmt, ##args);
 
-#ifndef TAG_NAME // SET default TAG
-#define TAG_NAME    TAG_IPC
-#endif
 
-#define PIMS_VERBOSE_TAG(frmt, args...) pims_verbose(TAG_NAME, frmt, ##args);
-#define PIMS_DEBUG_TAG(frmt, args...)   pims_debug  (TAG_NAME, frmt, ##args);
-#define PIMS_INFO_TAG(frmt, args...)    pims_info   (TAG_NAME, frmt, ##args);
-#define PIMS_WARN_TAG(frmt, args...)    pims_warn   (TAG_NAME, frmt, ##args);
-#define PIMS_ERROR_TAG(frmt, args...)   pims_error  (TAG_NAME, frmt, ##args);
+#define ENTER()        PIMS_DEBUG_TAG(">>>>>>>> called")
+#define LEAVE()        PIMS_DEBUG_TAG("<<<<<<<< ended")
 
 //#define VERBOSE(frmt, args...)  PIMS_VERBOSE_TAG(frmt, ##args)
 #define VERBOSE(frmt, args...)
@@ -70,14 +47,21 @@ extern "C"
 #define WARNING(frmt, args...)  PIMS_WARN_TAG(frmt, ##args)
 #define ERROR(frmt, args...)    PIMS_ERROR_TAG(frmt, ##args)
 
+#define WARN_IF(expr, fmt, arg...) do { \
+       if (expr) { \
+               ERROR(fmt, ##arg); \
+       } \
+} while (0)
+
+
 #define ASSERT(expr) \
-    if (!(expr)) \
-    {   \
-        ERROR("Assertion %s", #expr); \
-    } \
-    assert(expr)
+       if (!(expr)) \
+       {   \
+               ERROR("Assertion %s", #expr); \
+       } \
+       assert(expr)
 
-#ifdef _cplusplus
+#ifdef __cplusplus
 }
 #endif
 
index 03c5736..fbc2b42 100644 (file)
@@ -20,9 +20,7 @@
 #ifndef __PIMS_INTERNAL_H__
 #define __PIMS_INTERNAL_H__
 
-#include <zmq.h>
-
-#ifdef _cplusplus
+#ifdef __cplusplus
 extern "C"
 {
 #endif
@@ -31,10 +29,8 @@ extern "C"
 #define API __attribute__ ((visibility("default")))
 #endif
 
-#define PIMS_IPC_MONITOR_PATH       "monitor"
-#define PIMS_IPC_DEALER_PATH        "dealer"
-#define PIMS_IPC_MANAGER_PATH       "manager"
-#define PIMS_IPC_MONITOR2_PATH      "monitor2"
+#define MAX_EPOLL_EVENT 256
+
 #define PIMS_IPC_MODULE_INTERNAL    "pims_ipc_internal"
 #define PIMS_IPC_FUNCTION_CREATE    "create"
 #define PIMS_IPC_FUNCTION_DESTROY   "destroy"
@@ -42,35 +38,18 @@ extern "C"
 #define PIMS_IPC_CALL_ID_DESTROY    PIMS_IPC_MODULE_INTERNAL ":" PIMS_IPC_FUNCTION_DESTROY
 #define PIMS_IPC_MAKE_CALL_ID(module, function) g_strdup_printf("%s:%s", module, function)
 
-static inline int _pims_zmq_msg_recv(zmq_msg_t *msg, void *socket, int flags)
-{
-    int ret = -1;
-
-    while (1)
-    {
-        ret = zmq_msg_recv(msg, socket, flags);
-        if (ret == -1 && errno == EINTR)
-            continue;
-        break;
-    }
-    return ret;
-}
-
-static inline int _pims_zmq_msg_send(zmq_msg_t *msg, void *socket, int flags)
-{
-    int ret = -1;
-
-    while (1)
-    {
-        ret = zmq_msg_send(msg, socket, flags);
-        if (ret == -1 && errno == EINTR)
-            continue;
-        break;
-    }
-    return ret;
-}
-
-#ifdef _cplusplus
+typedef struct {
+       unsigned int alloc_size;
+       unsigned int buf_size;
+       unsigned int free_size;
+       char *pos;
+       char *buf;
+       int flags;
+       unsigned int created:1;
+       unsigned int buf_alloced:1;
+} pims_ipc_data_s;
+
+#ifdef __cplusplus
 }
 #endif
 
diff --git a/src/pims-ipc-data-internal.h b/src/pims-ipc-data-internal.h
new file mode 100644 (file)
index 0000000..ba947c0
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * PIMS IPC
+ *
+ * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef __PIMS_IPC_DATA_INTERNAL_H__
+#define __PIMS_IPC_DATA_INTERNAL_H__
+
+#include <pims-ipc-types.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+pims_ipc_data_h pims_ipc_data_steal_unmarshal(void *buf, unsigned int size);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PIMS_IPC_DATA_INTERNAL_H__ */
index fa0ee5d..9f1c487 100644 (file)
 #include <string.h>
 #include <glib.h>
 
-#include <pims-internal.h>
-#include <pims-debug.h>
-#include <pims-ipc-data.h>
-
-typedef struct
-{
-    unsigned int alloc_size;
-    unsigned int buf_size;
-    unsigned int free_size;
-    zmq_msg_t zmsg;
-    char *pos;
-    char *buf;
-    int flags;
-    unsigned int created:1;
-    unsigned int zmsg_alloced:1;
-    unsigned int buf_alloced:1;
-} pims_ipc_data_t;
+#include "pims-internal.h"
+#include "pims-debug.h"
+#include "pims-ipc-data.h"
 
 /*
-  Structure of data with type(4 bytes order)
-      +------------------------------------------------------------------+
-      | type | size | data        | pad | type | size | data       | pad |
-      +------------------------------------------------------------------+
-         4      4     size         0-3          (Size of bytes)
-
-  Structure of data without type(4 bytes order)
-      +----------------------------------------------------+
-      | size | data        | pad | size | data       | pad |
-      +----------------------------------------------------+
-         4     size         0-3        (Size of bytes)
-*/
+       Structure of data with type(4 bytes order)
+       +------------------------------------------------------------------+
+       | type | size | data        | pad | type | size | data       | pad |
+       +------------------------------------------------------------------+
+               4      4     size         0-3          (Size of bytes)
+
+       Structure of data without type(4 bytes order)
+       +----------------------------------------------------+
+       | size | data        | pad | size | data       | pad |
+       +----------------------------------------------------+
+               4     size         0-3        (Size of bytes)
+ */
 
 #define _get_used_size_with_type(data_size) \
-    (sizeof(int) + sizeof(int) + data_size + (sizeof(int) - (data_size % sizeof(int))))
+       (sizeof(int) + sizeof(int) + data_size + ((sizeof(int) - (data_size % sizeof(int)))%sizeof(int)))
 
 #define _get_used_size(data_size) \
-    (sizeof(int) + data_size + (sizeof(int) - (data_size % sizeof(int))))
+       (sizeof(int) + data_size + ((sizeof(int) - (data_size % sizeof(int)))%sizeof(int)))
 
 API pims_ipc_data_h pims_ipc_data_create_with_size(unsigned int size, int flags)
 {
-    int ret = -1;
-    pims_ipc_data_t *handle = NULL;
-
-    handle = g_new0(pims_ipc_data_t, 1);
-    handle->alloc_size = size;
-    handle->free_size = size;
-    handle->buf_size = 0;
-    handle->buf = g_malloc0(size);
-    handle->pos = handle->buf;
-    handle->created = 1;
-    handle->buf_alloced = 1;
-
-    ret = pims_ipc_data_put(handle, &flags, sizeof(int));
-    ASSERT(ret == 0);
-    handle->flags = flags;
-
-    return handle;
-}
-
-API void pims_ipc_data_destroy(pims_ipc_data_h data)
-{
-    pims_ipc_data_t *handle = (pims_ipc_data_t *)data;
-    if (handle->buf_alloced)
-    {
-        g_free(handle->buf);
-    }
-    if (handle->zmsg_alloced)
-    {
-        zmq_msg_close(&handle->zmsg);
-    }
-    g_free(handle);
-}
-
-API int pims_ipc_data_put(pims_ipc_data_h data, void *buf, unsigned int size)
-{
-    pims_ipc_data_t *handle = NULL;
-    unsigned int dsize = size;
-    unsigned int used_size = 0;
-    handle = (pims_ipc_data_t *)data;
-
-    if (handle->created == 0)
-    {
-        ERROR("This handle isn't create mode.");
-        return -1;
-    }
-    if (handle->flags & PIMS_IPC_DATA_FLAGS_WITH_TYPE)
-    {
-        ERROR("Not without-type mode");
-        return -1;
-    }
-    if (dsize > 0 && buf == NULL)
-    {
-        ERROR("Invalid argument");
-        return -1;
-    }
-
-    if (handle->free_size < _get_used_size(dsize))
-    {
-        int new_size = 0;
-        new_size = handle->alloc_size * 2;
-
-        while (new_size < handle->buf_size + _get_used_size(dsize))
-            new_size *= 2;
-        handle->buf = g_realloc(handle->buf, new_size);
-        handle->alloc_size = new_size;
-        handle->free_size = handle->alloc_size - handle->buf_size;
-
-        handle->pos = handle->buf;
-        handle->pos += handle->buf_size;
-
-        VERBOSE("free_size [%d] dsize [%d]", handle->free_size, dsize);
-    }
-
-    *(int*)(handle->pos) = dsize;
-    if (dsize > 0)
-        memcpy((handle->pos+sizeof(int)), buf, dsize);
-
-    used_size = _get_used_size(dsize);
-    handle->pos += used_size;
-    handle->buf_size += used_size;
-    handle->free_size -= used_size;
-    
-    VERBOSE("data put size [%u] data[%p]", dsize, buf);
-
-    return 0;
-}
-
-API void* pims_ipc_data_get(pims_ipc_data_h data, unsigned int *size)
-{
-    pims_ipc_data_t *handle = NULL;
-    unsigned int dsize = 0;
-    unsigned int used_size = 0;
-    void *buf = NULL;
-    handle = (pims_ipc_data_t *)data;
-
-    if (handle->created == 1)
-    {
-        ERROR("This handle is create mode.");
-        return NULL;
-    }
-    if (handle->buf_size == 0)
-    {
-        ERROR("Remain buffer size is 0.");
-        return NULL;
-    }
-    if (handle->flags & PIMS_IPC_DATA_FLAGS_WITH_TYPE)
-    {
-        ERROR("Not without-type mode");
-        return NULL;
-    }
-
-    dsize = *(int*)(handle->pos);
-    buf = (handle->pos+sizeof(int));
-
-    if (dsize == 0) // current position is next size field becasue data size is 0
-        buf = NULL;
-
-    used_size = _get_used_size(dsize);
-    handle->pos += used_size;
-    handle->buf_size -= used_size;
-    handle->free_size += used_size;
-
-    VERBOSE("data get size [%u] data[%p]", dsize, buf);
-    *size = dsize;
-    return buf;
-}
+       //      ENTER();
+       int ret = -1;
+       pims_ipc_data_s *handle = NULL;
 
-API void* pims_ipc_data_get_dup(pims_ipc_data_h data, unsigned int *size)
-{
-    void *buf = NULL;
-
-    buf = pims_ipc_data_get(data, size);
-    return g_memdup(buf, *size);
-}
-
-
-API int pims_ipc_data_put_with_type(pims_ipc_data_h data, pims_ipc_data_type_e type, void *buf, unsigned int size)
-{
-    pims_ipc_data_t *handle = NULL;
-    unsigned int dsize = 0;
-    unsigned int used_size = 0;
-    handle = (pims_ipc_data_t *)data;
-
-    if (handle->created == 0)
-    {
-        ERROR("This handle isn't create mode.");
-        return -1;
-    }
-    if (!(handle->flags & PIMS_IPC_DATA_FLAGS_WITH_TYPE))
-    {
-        ERROR("Not with-type mode");
-        return -1;
-    }
-
-    switch(type)
-    {
-    case PIMS_IPC_DATA_TYPE_CHAR:
-        dsize = sizeof(char);
-        break;
-    case PIMS_IPC_DATA_TYPE_UCHAR:
-        dsize = sizeof(unsigned char);
-        break;
-    case PIMS_IPC_DATA_TYPE_INT:
-        dsize = sizeof(int);
-        break;
-    case PIMS_IPC_DATA_TYPE_UINT:
-        dsize = sizeof(unsigned int);
-        break;
-    case PIMS_IPC_DATA_TYPE_LONG:
-        dsize = sizeof(long);
-        break;
-    case PIMS_IPC_DATA_TYPE_ULONG:
-        dsize = sizeof(unsigned long);
-        break;
-    case PIMS_IPC_DATA_TYPE_FLOAT:
-        dsize = sizeof(float);
-        break;
-    case PIMS_IPC_DATA_TYPE_DOUBLE:
-        dsize = sizeof(double);
-        break;
-    case PIMS_IPC_DATA_TYPE_STRING:
-        if (buf == NULL)
-        {
-            dsize = 0;
-        }
-        else
-        {
-            dsize = strlen(buf) +1;
-        }
-        break;
-    case PIMS_IPC_DATA_TYPE_MEMORY:
-        dsize = size;
-        break;
-    default:
-        dsize = 0;
-        break;
-    }
-
-    if (dsize != 0 && buf == NULL)
-        return -1;
-
-    if (buf == NULL && dsize == 0 && type != PIMS_IPC_DATA_TYPE_STRING)
-        return -1;
-
-    if (handle->free_size < _get_used_size_with_type(dsize))
-    {
-        int new_size = 0;
-        new_size = handle->alloc_size * 2;
-
-        while (new_size < handle->buf_size + _get_used_size_with_type(dsize))
-            new_size *= 2;
-        handle->buf = g_realloc(handle->buf, new_size);
-        handle->alloc_size = new_size;
-        handle->free_size = handle->alloc_size - handle->buf_size;
-
-        handle->pos = handle->buf;
-        handle->pos += handle->buf_size;
-
-        VERBOSE("free_size [%d] dsize [%d]", handle->free_size, dsize);
-    }
-
-    *(int*)(handle->pos) = type;
-    *(int*)(handle->pos+sizeof(int)) = dsize;
-    if (dsize > 0 && buf != NULL)
-        memcpy((handle->pos+sizeof(int)*2), buf, dsize);
-
-    used_size = _get_used_size_with_type(dsize);
-    handle->pos += used_size;
-    handle->buf_size += used_size;
-    handle->free_size -= used_size;
-    
-    VERBOSE("data put type [%d] size [%u] data[%p]", type, dsize, buf);
-
-    return 0;
-}
+       handle = calloc(1, sizeof(pims_ipc_data_s));
+       handle->alloc_size = size;
+       handle->free_size = size;
+       handle->buf_size = 0;
+       handle->buf = calloc(1, size);
+       handle->pos = handle->buf;
+       handle->created = 1;
+       handle->buf_alloced = 1;
 
-API void* pims_ipc_data_get_with_type(pims_ipc_data_h data, pims_ipc_data_type_e *type, unsigned int *size)
-{
-    pims_ipc_data_t *handle = NULL;
-    pims_ipc_data_type_e dtype = PIMS_IPC_DATA_TYPE_INVALID;
-    unsigned int dsize = 0;
-    unsigned int used_size = 0;
-    void *buf = NULL;
-    handle = (pims_ipc_data_t *)data;
-
-    if (handle->created == 1)
-    {
-        ERROR("This handle is create mode.");
-        *type = PIMS_IPC_DATA_TYPE_INVALID;
-        return NULL;
-    }
-    if (handle->buf_size == 0)
-    {
-        ERROR("Remain buffer size is 0.");
-        *type = PIMS_IPC_DATA_TYPE_INVALID;
-        return NULL;
-    }
-    if (!(handle->flags & PIMS_IPC_DATA_FLAGS_WITH_TYPE))
-    {
-        ERROR("Not with-type mode");
-        *type = PIMS_IPC_DATA_TYPE_INVALID;
-        return NULL;
-    }
-
-    dtype = *(int*)(handle->pos);
-    dsize = *(int*)(handle->pos+sizeof(int));
-    buf = (handle->pos+sizeof(int)*2);
-
-    switch(dtype)
-    {
-        case PIMS_IPC_DATA_TYPE_CHAR:
-        case PIMS_IPC_DATA_TYPE_UCHAR:
-        case PIMS_IPC_DATA_TYPE_INT:
-        case PIMS_IPC_DATA_TYPE_UINT:
-        case PIMS_IPC_DATA_TYPE_LONG:
-        case PIMS_IPC_DATA_TYPE_ULONG:
-        case PIMS_IPC_DATA_TYPE_FLOAT:
-        case PIMS_IPC_DATA_TYPE_DOUBLE:
-        case PIMS_IPC_DATA_TYPE_STRING:
-        case PIMS_IPC_DATA_TYPE_MEMORY:
-            break;
-        default:
-            ERROR("Unknown data type");
-            dsize = 0;
-            break;
-    }
-
-    if (dtype != PIMS_IPC_DATA_TYPE_STRING && dsize == 0)
-    {
-        *type = PIMS_IPC_DATA_TYPE_INVALID;
-        return NULL;
-    }
-
-    if (dsize == 0) // current position is next type field becasue data size is 0
-        buf = NULL;
-
-    used_size = _get_used_size_with_type(dsize);
-    handle->pos += used_size;
-    handle->buf_size -= used_size;
-    handle->free_size += used_size;
-
-    VERBOSE("data get type [%d] size [%u] data[%p]", dtype, dsize, buf);
-    *type = dtype;
-    *size = dsize;
-    return buf;
-}
+       ret = pims_ipc_data_put(handle, &flags, sizeof(int));
 
-API void* pims_ipc_data_get_dup_with_type(pims_ipc_data_h data, pims_ipc_data_type_e *type, unsigned int *size)
-{
-    void *buf = NULL;
+       ASSERT(ret == 0);
+       handle->flags = flags;
 
-    buf = pims_ipc_data_get_with_type(data, type, size);
-    return g_memdup(buf, *size);
+       return handle;
 }
 
-API void* pims_ipc_data_marshal(pims_ipc_data_h data, unsigned int *size)
+API void pims_ipc_data_destroy(pims_ipc_data_h data)
 {
-    pims_ipc_data_t *handle = NULL;
-    
-    if (!data || !size )
-        return NULL;
-    
-    handle = (pims_ipc_data_t *)data;
+       //      ENTER();
+       pims_ipc_data_s *handle = (pims_ipc_data_s *)data;
+       if (!handle)
+               return;
 
-    *size = handle->buf_size;
+       if (handle->buf_alloced)
+               free(handle->buf);
 
-    return handle->buf;
-}
-
-static void __pims_ipc_data_free_cb(void *data, void *hint)
-{
-    if (hint)
-        g_free(hint);
-}
-
-API int pims_ipc_data_marshal_with_zmq(pims_ipc_data_h data, zmq_msg_t *pzmsg)
-{
-    pims_ipc_data_t *handle = NULL;
-   
-    if (!data || !pzmsg )
-        return -1;
-
-    handle = (pims_ipc_data_t *)data;
-
-    if (handle->zmsg_alloced)
-    {
-        // TODO: need to prevent memory leackage when reusing data marshaled
-        WARNING("It's ever been marshaled");
-    }
-
-    zmq_msg_init_data(&handle->zmsg, handle->buf, handle->buf_size, __pims_ipc_data_free_cb, handle->buf); 
-    
-    if (zmq_msg_copy(pzmsg, &handle->zmsg) != 0)
-    {
-        zmq_msg_close(&handle->zmsg);
-        return -1;
-    }
-
-    handle->zmsg_alloced = 1;
-    handle->buf_alloced = 0;
-
-    return 0;
+       free(handle);
 }
 
-API void* pims_ipc_data_marshal_dup(pims_ipc_data_h data, unsigned int *size)
+API int pims_ipc_data_put(pims_ipc_data_h data, void *buf, unsigned int size)
 {
-    unsigned int lsize = 0;
-    gpointer buf = NULL;
-    
-    if (!data || !size )
-        return NULL;
-    
-    buf = pims_ipc_data_marshal(data, &lsize);
-    *size = lsize;
-    return g_memdup(buf, lsize);
+       //      ENTER();
+       pims_ipc_data_s *handle = NULL;
+       unsigned int dsize = size;
+       unsigned int used_size = 0;
+       handle = (pims_ipc_data_s *)data;
+
+       if (handle->created == 0) {
+               ERROR("This handle isn't create mode.");
+               return -1;
+       }
+
+       if (handle->flags & PIMS_IPC_DATA_FLAGS_WITH_TYPE) {
+               ERROR("Not without-type mode");
+               return -1;
+       }
+
+       if (dsize > 0 && buf == NULL) {
+               ERROR("Invalid argument");
+               return -1;
+       }
+
+       used_size = _get_used_size(dsize);
+       if (handle->free_size < used_size) {
+               int new_size = 0;
+               new_size = handle->alloc_size * 2;
+
+               while (new_size < handle->buf_size + used_size)
+                       new_size *= 2;
+               handle->buf = realloc(handle->buf, new_size);
+               handle->alloc_size = new_size;
+               handle->free_size = handle->alloc_size - handle->buf_size;
+               handle->pos = handle->buf;
+               handle->pos += handle->buf_size;
+               VERBOSE("free_size [%d] dsize [%d]", handle->free_size, dsize);
+       }
+
+       *(int*)(handle->pos) = dsize;
+       if (dsize > 0) {
+               memcpy((handle->pos+sizeof(int)), buf, dsize);
+               int pad_size = used_size-dsize-sizeof(int);
+               if (pad_size > 0)
+                       memset((handle->pos+sizeof(int)+dsize), 0x0, pad_size);
+       }
+
+       handle->pos += used_size;
+       handle->buf_size += used_size;
+       handle->free_size -= used_size;
+
+       VERBOSE("data put size [%u] data[%p]", dsize, buf);
+
+       return 0;
 }
 
-API pims_ipc_data_h pims_ipc_data_unmarshal(void *buf, unsigned int size)
+API void* pims_ipc_data_get(pims_ipc_data_h data, unsigned int *size)
 {
-    pims_ipc_data_t *handle = NULL;
-    zmq_msg_t zmsg; 
-
-    zmq_msg_init_data(&zmsg, buf, size, __pims_ipc_data_free_cb, NULL); 
-
-    handle = pims_ipc_data_unmarshal_with_zmq(&zmsg);
-    zmq_msg_close(&zmsg);
-
-    return handle;
+       //      ENTER();
+       pims_ipc_data_s *handle = NULL;
+       unsigned int dsize = 0;
+       unsigned int used_size = 0;
+       void *buf = NULL;
+       handle = (pims_ipc_data_s *)data;
+
+       if (handle->created == 1) {
+               ERROR("This handle is create mode.");
+               return NULL;
+       }
+       if (handle->buf_size == 0) {
+               ERROR("Remain buffer size is 0.");
+               return NULL;
+       }
+       if (handle->flags & PIMS_IPC_DATA_FLAGS_WITH_TYPE) {
+               ERROR("Not without-type mode");
+               return NULL;
+       }
+
+       dsize = *(int*)(handle->pos);
+       buf = (handle->pos+sizeof(int));
+
+       if (dsize == 0) // current position is next size field becasue data size is 0
+               buf = NULL;
+
+       used_size = _get_used_size(dsize);
+       handle->pos += used_size;
+       handle->buf_size -= used_size;
+       handle->free_size += used_size;
+
+       VERBOSE("data get size [%u] data[%p]", dsize, buf);
+       *size = dsize;
+       return buf;
 }
 
-API pims_ipc_data_h pims_ipc_data_unmarshal_with_zmq(zmq_msg_t *pzmsg)
-{
-    pims_ipc_data_t *handle = NULL;
-    unsigned int size = 0;
-    void *ptr = NULL;
-
-    handle = g_new0(pims_ipc_data_t, 1);
-    zmq_msg_init(&handle->zmsg);
-    if (zmq_msg_copy(&handle->zmsg, pzmsg) != 0)
-    {
-        g_free(handle);
-        return NULL;
-    }
-    handle->alloc_size = zmq_msg_size(&handle->zmsg);
-    handle->free_size = 0;
-    handle->buf_size = handle->alloc_size;
-    handle->buf = zmq_msg_data(&handle->zmsg);
-    handle->pos = handle->buf;
-    handle->created = 0;
-    handle->zmsg_alloced = 1;
-    
-    ptr = pims_ipc_data_get(handle, &size);
-    if (!ptr || size != sizeof(int))
-    {
-        g_free(handle);
-        return NULL;
-    }
-    handle->flags = *((int*)ptr);
-
-    VERBOSE("handle[%p] zmsg[%p] flags[%x]", handle, pzmsg, handle->flags);
-    
-    return handle;
+pims_ipc_data_h pims_ipc_data_steal_unmarshal(void *buf, unsigned int size)
+{
+       //      ENTER();
+       void *ptr = NULL;
+       pims_ipc_data_s *handle = NULL;
+
+       VERBOSE("size : %d", size);
+       handle = calloc(1, sizeof(pims_ipc_data_s));
+       handle->alloc_size = size;
+       handle->free_size = 0;
+       handle->buf_size = handle->alloc_size;
+       handle->buf = buf;
+       handle->pos = handle->buf;
+       handle->created = 0;
+       handle->buf_alloced = 1;
+
+       ptr = pims_ipc_data_get(handle, &size);
+       if (!ptr || size != sizeof(int)) {
+               ERROR("pims_ipc_data_get : error");
+               free(handle->buf);
+               free(handle);
+               return NULL;
+       }
+       handle->flags = *((int*)ptr);
+
+       VERBOSE("handle[%p] flags[%x]", handle, handle->flags);
+
+       return handle;
 }
 
-API pims_ipc_data_h pims_ipc_data_unmarshal_dup(void *buf, unsigned int size)
-{
-    pims_ipc_data_t *handle = NULL;
-    zmq_msg_t zmsg; 
-
-    zmq_msg_init_size(&zmsg, size);
-    memcpy(zmq_msg_data(&zmsg), buf, size);
-
-    handle = pims_ipc_data_unmarshal_with_zmq(&zmsg);
-    zmq_msg_close(&zmsg);
-
-    return handle;
-}
index ef48e0c..796caa4 100644 (file)
 #include <glib.h>
 #include <pthread.h>
 #include <stdint.h>
-#include <sys/types.h>
+#include <poll.h>                              // pollfds
+#include <fcntl.h>                             //fcntl
+#include <unistd.h>
+#include <systemd/sd-daemon.h>
+#include <errno.h>
+
 #include <sys/stat.h>
+#include <sys/un.h>                    // sockaddr_un
+#include <sys/ioctl.h>         // ioctl
+#include <sys/epoll.h>         // epoll
+#include <sys/eventfd.h>       // eventfd
+#include <sys/socket.h>                //socket
+#include <sys/types.h>
 
-#include <pims-internal.h>
-#include <pims-debug.h>
-#include <pims-socket.h>
-#include <pims-ipc-data.h>
-#include <pims-ipc-svc.h>
+#include "pims-internal.h"
+#include "pims-debug.h"
+#include "pims-socket.h"
+#include "pims-ipc-data.h"
+#include "pims-ipc-data-internal.h"
+#include "pims-ipc-svc.h"
 
 #define PIMS_IPC_WORKERS_DEFAULT_MAX_COUNT  2
 
-typedef struct
-{
-    char *service;
-    gid_t group;
-    mode_t mode;
-    GHashTable *cb_table;
-    GHashTable *client_table;
-    GList *workers;
-    GList *requests;
-    int workers_max_count;
-    void* context;
-    void* router;
-    void* worker;
-    void* manager;
-    void* monitor;
-} pims_ipc_svc_t;
-
-typedef struct
-{
-    char *service;
-    gid_t group;
-    mode_t mode;
-    void* context;
-    void* publisher;
-} pims_ipc_svc_for_publish_t;
-
-
-typedef struct
+typedef struct {
+       char *service;
+       gid_t group;
+       mode_t mode;
+
+       // callback functions
+       GHashTable *cb_table;                   // call_id, cb_data
+
+       // Global socket info and epoll thread
+       int sockfd;
+       bool epoll_stop_thread;
+
+       /////////////////////////////////////////////
+       // router inproc eventfd
+       int router;
+       int delay_count;  // not need mutex
+       // epoll thread add client_fd, when receive, router read requests
+       GList *request_queue;    // client_id lists to send request
+       pthread_mutex_t request_data_queue_mutex;
+       GHashTable *request_data_queue;  // key : client id, data : GList pims_ipc_raw_data_s (client_fd, seq_no, request(command), additional data...)
+       // router add client when receive connecting request, remove client when disconneting request in router thread
+       // manager remove client when terminating client without disconnect request in router thread
+       GHashTable *client_worker_map;           // key : client_id, worker_fd, not need mutex
+       GList *client_id_fd_map;                 // pims_ipc_client_map_s
+       //key :client_id(pid:seq_no), data : client_fd
+
+       /////////////////////////////////////////////
+       pthread_mutex_t task_fds_mutex;
+       // when starting worker thread, register fd
+       // when endting worker thread, deregister fd
+       GHashTable *task_fds;    // worker_fd - worker data (worker fd, client_fd, request queue(GList), stop_thread)
+       int workers_max_count;
+
+       /////////////////////////////////////////////
+       // manager inproc eventfd
+       int manager;
+       // write by new worker thread, read by manager in router thread, need mutex
+       pthread_mutex_t manager_queue_from_worker_mutex;
+       GList *manager_queue_from_worker;        // worker_fd => add to workers
+       // write in epoll thread(for dead client), read by manager in router thread, need mutex
+       pthread_mutex_t manager_queue_from_epoll_mutex;
+       GList *manager_queue_from_epoll; // cliend_fd => find worker_fd => add to idle workers
+       // managed by manager, router find idle worker when connecting new client in router thread => remove from idle workers
+       GList *workers;          // worker_fd list, not need mutex
+       /////////////////////////////////////////////
+} pims_ipc_svc_s;
+
+typedef struct {
+       char *service;
+       gid_t group;
+       mode_t mode;
+
+       int publish_sockfd;
+       bool epoll_stop_thread;
+       pthread_mutex_t subscribe_fds_mutex;
+       GList *subscribe_fds;           // cliend fd list
+} pims_ipc_svc_for_publish_s;
+
+typedef struct {
+       int fd;
+       char *id;
+}pims_ipc_client_map_s;
+
+typedef struct {
+       pims_ipc_svc_call_cb callback;
+       void * user_data;
+} pims_ipc_svc_cb_s;
+
+typedef struct {
+       pims_ipc_svc_client_disconnected_cb callback;
+       void * user_data;
+} pims_ipc_svc_client_disconnected_cb_t;
+
+typedef struct {
+       int fd;
+       int worker_id;  // pthrad_self()
+       int client_fd;
+       bool stop_thread;
+       GList *queue;           // pims_ipc_raw_data_s list
+       pthread_mutex_t queue_mutex;
+} pims_ipc_worker_data_s;
+
+typedef struct{
+       char *client_id;
+       unsigned int client_id_len;
+       unsigned int seq_no;
+       char *call_id;
+       unsigned int call_id_len;
+       unsigned int is_data;
+       unsigned int data_len;
+       char *data;
+}pims_ipc_raw_data_s;
+
+typedef struct {
+       int client_fd;
+       int request_count;
+       GList *raw_data;                // pims_ipc_raw_data_s list
+       pthread_mutex_t raw_data_mutex;
+}pims_ipc_request_s;
+
+static pims_ipc_svc_s *_g_singleton = NULL;
+static pims_ipc_svc_for_publish_s *_g_singleton_for_publish = NULL;
+
+static __thread pims_ipc_svc_client_disconnected_cb_t _client_disconnected_cb = {NULL, NULL};
+
+static void __free_raw_data(pims_ipc_raw_data_s *data)
 {
-    pims_ipc_svc_call_cb callback;
-    void * user_data;
-} pims_ipc_svc_cb_t;
+       if (!data) return;
 
-static pims_ipc_svc_t *_g_singleton = NULL;
-static pims_ipc_svc_for_publish_t *_g_singleton_for_publish = NULL;
-
-#define PIMS_IPC_STRING_WORKER_ID_SIZE  10
-static char* __get_string_worker_id(int worker_id, char *string_worker_id)
-{
-    snprintf(string_worker_id, PIMS_IPC_STRING_WORKER_ID_SIZE, "%08x00", worker_id);
-    string_worker_id[PIMS_IPC_STRING_WORKER_ID_SIZE] = 0x0;
-
-    return string_worker_id;
+       free(data->client_id);
+       free(data->call_id);
+       free(data->data);
+       free(data);
 }
 
-API int pims_ipc_svc_init(char *service, gid_t group, mode_t mode)
+static void __worker_data_free(gpointer data)
 {
-    if (_g_singleton)
-    {
-        ERROR("Already exist");
-        return -1;
-    }
-
-    _g_singleton = g_new0(pims_ipc_svc_t, 1);
-    _g_singleton->service = g_strdup(service);
-    _g_singleton->group = group;
-    _g_singleton->mode = mode;
-    _g_singleton->workers_max_count = PIMS_IPC_WORKERS_DEFAULT_MAX_COUNT;
-    _g_singleton->cb_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-    ASSERT(_g_singleton->cb_table);
-    _g_singleton->client_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
-    ASSERT(_g_singleton->client_table);
-
-    return 0;
+       pims_ipc_worker_data_s *worker_data = (pims_ipc_worker_data_s*)data;
+
+       pthread_mutex_lock(&worker_data->queue_mutex);
+       if (worker_data->queue) {
+               GList *cursor = g_list_first(worker_data->queue);
+               while(cursor) {
+                       GList *l = cursor;
+                       pims_ipc_raw_data_s *data = l->data;
+                       cursor = g_list_next(cursor);
+                       worker_data->queue = g_list_remove_link(worker_data->queue, l);
+                       g_list_free(l);
+                       __free_raw_data(data);
+               }
+       }
+       pthread_mutex_unlock(&worker_data->queue_mutex);
+       free(worker_data);
 }
 
-static void __free_zmq_msg(gpointer data)
+API int pims_ipc_svc_init(char *service, gid_t group, mode_t mode)
 {
-    zmq_msg_t *lpzmsg = data;
-
-    if (lpzmsg)
-    {
-        zmq_msg_close(lpzmsg);
-        g_free(lpzmsg);
-    }
+       if (_g_singleton) {
+               ERROR("Already exist");
+               return -1;
+       }
+
+       _g_singleton = g_new0(pims_ipc_svc_s, 1);
+       _g_singleton->service = g_strdup(service);
+       _g_singleton->group = group;
+       _g_singleton->mode = mode;
+       _g_singleton->workers_max_count = PIMS_IPC_WORKERS_DEFAULT_MAX_COUNT;
+       _g_singleton->cb_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+       ASSERT(_g_singleton->cb_table);
+
+       pthread_mutex_init(&_g_singleton->request_data_queue_mutex, 0);
+       _g_singleton->request_queue = NULL;
+       _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
+       ASSERT(_g_singleton->request_data_queue);
+       _g_singleton->client_worker_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);         // client id - worker_fd mapping
+       ASSERT(_g_singleton->client_worker_map);
+       _g_singleton->delay_count = 0;
+
+       pthread_mutex_init(&_g_singleton->task_fds_mutex, 0);
+       _g_singleton->task_fds = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, __worker_data_free);                // pims_ipc_worker_data_s
+       ASSERT(_g_singleton->task_fds);
+
+       pthread_mutex_init(&_g_singleton->manager_queue_from_epoll_mutex, 0);
+       _g_singleton->manager_queue_from_epoll = NULL;
+
+       pthread_mutex_init(&_g_singleton->manager_queue_from_worker_mutex, 0);
+       _g_singleton->manager_queue_from_worker = NULL;
+       _g_singleton->workers = NULL;
+
+       _g_singleton->epoll_stop_thread = false;
+
+       return 0;
 }
 
 API int pims_ipc_svc_deinit(void)
 {
-    if (!_g_singleton)
-        return -1;
-
-    g_free(_g_singleton->service);
-    g_hash_table_destroy(_g_singleton->cb_table);
-    g_hash_table_destroy(_g_singleton->client_table);
-    g_list_free(_g_singleton->workers);
-    g_list_free_full(_g_singleton->requests, __free_zmq_msg);
-    g_free(_g_singleton);
-    _g_singleton = NULL;
-
-    return 0;
+       if (!_g_singleton)
+               return -1;
+
+       g_free(_g_singleton->service);
+       g_hash_table_destroy(_g_singleton->cb_table);
+
+       pthread_mutex_destroy(&_g_singleton->request_data_queue_mutex);
+       g_hash_table_destroy(_g_singleton->client_worker_map);
+       g_hash_table_destroy(_g_singleton->request_data_queue);
+       g_list_free_full(_g_singleton->request_queue, g_free);
+
+       pthread_mutex_destroy(&_g_singleton->task_fds_mutex);
+       g_hash_table_destroy(_g_singleton->task_fds);
+
+       pthread_mutex_destroy(&_g_singleton->manager_queue_from_epoll_mutex);
+       g_list_free_full(_g_singleton->manager_queue_from_epoll, g_free);
+       pthread_mutex_destroy(&_g_singleton->manager_queue_from_worker_mutex);
+       g_list_free(_g_singleton->manager_queue_from_worker);
+
+       GList *cursor = g_list_first(_g_singleton->client_id_fd_map);
+       while(cursor) {
+               pims_ipc_client_map_s *client = cursor->data;
+               _g_singleton->client_id_fd_map = g_list_remove_link(_g_singleton->client_id_fd_map, cursor);                    //free(client_id);
+               free(client->id);
+               free(client);
+               g_list_free(cursor);
+               cursor = g_list_first(_g_singleton->client_id_fd_map);
+       }
+       g_list_free(_g_singleton->client_id_fd_map);
+
+       g_list_free(_g_singleton->workers);
+       g_free(_g_singleton);
+       _g_singleton = NULL;
+
+       return 0;
 }
 
 API int pims_ipc_svc_register(char *module, char *function, pims_ipc_svc_call_cb callback, void *userdata)
 {
-    pims_ipc_svc_cb_t *cb_data = NULL;
-    gchar *call_id = NULL;
-
-    if (!module || !function || !callback)
-    {
-        ERROR("Invalid argument");
-        return -1;
-    }
-    cb_data = g_new0(pims_ipc_svc_cb_t, 1);
-    call_id = PIMS_IPC_MAKE_CALL_ID(module, function);
-
-    VERBOSE("register cb id[%s]", call_id);
-    cb_data->callback = callback;
-    cb_data->user_data = userdata;
-    g_hash_table_insert(_g_singleton->cb_table, call_id, cb_data);
-
-    return 0;
+       pims_ipc_svc_cb_s *cb_data = NULL;
+       gchar *call_id = NULL;
+
+       if (!module || !function || !callback) {
+               ERROR("Invalid argument");
+               return -1;
+       }
+       cb_data = g_new0(pims_ipc_svc_cb_s, 1);
+       call_id = PIMS_IPC_MAKE_CALL_ID(module, function);
+
+       VERBOSE("register cb id[%s]", call_id);
+       cb_data->callback = callback;
+       cb_data->user_data = userdata;
+       g_hash_table_insert(_g_singleton->cb_table, call_id, cb_data);
+
+       return 0;
 }
 
 API int pims_ipc_svc_init_for_publish(char *service, gid_t group, mode_t mode)
 {
-    if (_g_singleton_for_publish)
-    {
-        ERROR("Already exist");
-        return -1;
-    }
-
-    _g_singleton_for_publish = g_new0(pims_ipc_svc_for_publish_t, 1);
-    _g_singleton_for_publish->service = g_strdup(service);
-    _g_singleton_for_publish->group = group;
-    _g_singleton_for_publish->mode = mode;
-
-    return 0;
+       if (_g_singleton_for_publish) {
+               ERROR("Already exist");
+               return -1;
+       }
+
+       _g_singleton_for_publish = g_new0(pims_ipc_svc_for_publish_s, 1);
+       _g_singleton_for_publish->service = g_strdup(service);
+       _g_singleton_for_publish->group = group;
+       _g_singleton_for_publish->mode = mode;
+       _g_singleton_for_publish->subscribe_fds = NULL;
+
+       pthread_mutex_init(&_g_singleton_for_publish->subscribe_fds_mutex, 0);
+
+       return 0;
 }
 
 API int pims_ipc_svc_deinit_for_publish(void)
 {
-    if (!_g_singleton_for_publish)
-        return -1;
+       if (!_g_singleton_for_publish)
+               return -1;
 
-    g_free(_g_singleton_for_publish->service);
-    g_free(_g_singleton_for_publish);
-    _g_singleton_for_publish = NULL;
+       pthread_mutex_destroy(&_g_singleton_for_publish->subscribe_fds_mutex);
+       g_list_free(_g_singleton_for_publish->subscribe_fds);
 
-    return 0;
-}
+       g_free(_g_singleton_for_publish->service);
+       g_free(_g_singleton_for_publish);
+       _g_singleton_for_publish = NULL;
 
-static void __pims_ipc_svc_data_free_cb(void *data, void *hint)
-{
-    if (hint)
-        g_free(hint);
+       return 0;
 }
 
 API int pims_ipc_svc_publish(char *module, char *event, pims_ipc_data_h data)
 {
-    pims_ipc_svc_for_publish_t *ipc_svc = _g_singleton_for_publish;
-    gboolean is_valid = FALSE;
-    gchar *call_id = PIMS_IPC_MAKE_CALL_ID(module, event);
-
-    // init messages
-    zmq_msg_t call_id_msg;
-    zmq_msg_t data_msg;
-
-    zmq_msg_init_data(&call_id_msg, call_id, strlen(call_id) + 1, __pims_ipc_svc_data_free_cb, call_id);
-    VERBOSE("call id = %s", (char*)zmq_msg_data(&call_id_msg));
-
-    zmq_msg_init(&data_msg);
-
-    do {
-        if (data == NULL)
-        {
-            // send call id
-            if (_pims_zmq_msg_send(&call_id_msg, ipc_svc->publisher, 0) == -1)
-            {
-                ERROR("send error : %s", zmq_strerror(errno));
-                break;
-            }
-        }
-        else
-        {
-            // send call id
-            if (_pims_zmq_msg_send(&call_id_msg, ipc_svc->publisher, ZMQ_SNDMORE) == -1)
-            {
-                ERROR("send error : %s", zmq_strerror(errno));
-                break;
-            }
-
-            // marshal data
-            if (pims_ipc_data_marshal_with_zmq(data, &data_msg) != 0)
-            {
-                ERROR("marshal error");
-                break;
-            }
-
-            VERBOSE("the size of sending data = %d", zmq_msg_size(&data_msg));
-
-            // send data
-            if (_pims_zmq_msg_send(&data_msg, ipc_svc->publisher, 0) == -1)
-            {
-                ERROR("send error : %s", zmq_strerror(errno));
-                break;
-            }
-        }
-
-        is_valid = TRUE;
-    } while (0);
-
-    zmq_msg_close(&call_id_msg);
-    zmq_msg_close(&data_msg);
-
-    if (is_valid == FALSE)
-        return -1;
-    return 0;
+       pims_ipc_svc_for_publish_s *ipc_svc = _g_singleton_for_publish;
+       gboolean is_valid = FALSE;
+       gchar *call_id = PIMS_IPC_MAKE_CALL_ID(module, event);
+       pims_ipc_data_s *data_in = (pims_ipc_data_s*)data;
+       unsigned int call_id_len = strlen(call_id);
+       unsigned int is_data = FALSE;
+
+       do {
+               // make publish data
+               unsigned int len = sizeof(unsigned int)                                         // total size
+                       + call_id_len + sizeof(unsigned int)                    // call_id
+                       + sizeof(unsigned int);                                                 // is data
+               unsigned int total_len = len;
+
+               if (data_in) {
+                       is_data = TRUE;
+                       len += sizeof(unsigned int);
+                       total_len = len + data_in->buf_size;                    // data
+               }
+
+               char buf[len+1];
+               int length = 0;
+               memset(buf, 0x0, len+1);
+
+               // total_size
+               memcpy(buf, (void*)&total_len, sizeof(unsigned int));
+               length += sizeof(unsigned int);
+
+               // call_id
+               memcpy(buf+length, (void*)&(call_id_len), sizeof(unsigned int));
+               length += sizeof(unsigned int);
+               memcpy(buf+length, (void*)(call_id), call_id_len);
+               length += call_id_len;
+               g_free(call_id);
+
+               // is_data
+               memcpy(buf+length, (void*)&(is_data), sizeof(unsigned int));
+               length += sizeof(unsigned int);
+
+               // data
+               if (is_data) {
+                       memcpy(buf+length, (void*)&(data_in->buf_size), sizeof(unsigned int));
+                       length += sizeof(unsigned int);
+               }
+
+               // Publish to clients
+               pthread_mutex_lock(&ipc_svc->subscribe_fds_mutex);
+               GList *cursor = g_list_first(ipc_svc->subscribe_fds);
+               int ret = 0;
+               while(cursor) {
+                       int fd = (int)cursor->data;
+                       ret = socket_send(fd, buf, length);
+                       if (ret < 0) {
+                               ERROR("socket_send publish error : %d", ret);
+                       }
+
+                       if (is_data) {
+                               ret = socket_send_data(fd, data_in->buf, data_in->buf_size);
+                               if (ret < 0) {
+                                       ERROR("socket_send_data publish error : %d", ret);
+                               }
+                       }
+                       cursor = g_list_next(cursor);
+               }
+               pthread_mutex_unlock(&ipc_svc->subscribe_fds_mutex);
+
+               is_valid = TRUE;
+       } while (0);
+
+       if (is_valid == FALSE)
+               return -1;
+       return 0;
 }
 
 static void __run_callback(int worker_id, char *call_id, pims_ipc_data_h dhandle_in, pims_ipc_data_h *dhandle_out)
 {
-    pims_ipc_svc_cb_t *cb_data = NULL;
-
-    VERBOSE("Call id [%s]", call_id);
-
-    cb_data = (pims_ipc_svc_cb_t*)g_hash_table_lookup(_g_singleton->cb_table, call_id);
-    if (cb_data == NULL)
-    {
-        VERBOSE("unable to find %s", call_id);
-        return;
-    }
-    
-    cb_data->callback((pims_ipc_h)worker_id, dhandle_in, dhandle_out, cb_data->user_data);
+       pims_ipc_svc_cb_s *cb_data = NULL;
+
+       VERBOSE("Call id [%s]", call_id);
+
+       cb_data = (pims_ipc_svc_cb_s*)g_hash_table_lookup(_g_singleton->cb_table, call_id);
+       if (cb_data == NULL) {
+               VERBOSE("unable to find %s", call_id);
+               return;
+       }
+
+       cb_data->callback((pims_ipc_h)worker_id, dhandle_in, dhandle_out, cb_data->user_data);
+}
+
+static void __make_raw_data(const char *call_id, int seq_no, pims_ipc_data_h data, pims_ipc_raw_data_s**out)
+{
+       pims_ipc_raw_data_s *raw_data = NULL;
+       raw_data = (pims_ipc_raw_data_s*)calloc(1, sizeof(pims_ipc_raw_data_s));
+       pims_ipc_data_s *data_in = (pims_ipc_data_s*)data;
+
+       raw_data->call_id = strdup(call_id);
+       raw_data->call_id_len = strlen(raw_data->call_id);
+       raw_data->seq_no = seq_no;
+
+       if (data_in && data_in->buf_size > 0) {
+               raw_data->is_data = TRUE;
+               raw_data->data = calloc(1, data_in->buf_size+1);
+               memcpy(raw_data->data, data_in->buf, data_in->buf_size);
+               raw_data->data_len = data_in->buf_size;
+       }
+       else {
+               raw_data->is_data = FALSE;
+               raw_data->data_len = 0;
+               raw_data->data = NULL;
+       }
+       *out = raw_data;
+       return;
 }
 
-static int __process_worker_task(int worker_id, void *context, void *worker)
+static int __send_raw_data(int fd, const char *client_id, pims_ipc_raw_data_s *data)
 {
-    gboolean is_create = FALSE;
-    gboolean is_destroy = FALSE;
-    char *pid = NULL;
-    char *call_id = NULL;
-    int64_t more = 0;
-    size_t more_size = sizeof(more);
-    pims_ipc_data_h dhandle_in = NULL;
-    pims_ipc_data_h dhandle_out = NULL;
-
-    VERBOSE("");
-
-#ifdef _TEST
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    printf("worker time[%lu:%lu]\n", tv.tv_sec, tv.tv_usec);
-#endif
-
-    zmq_msg_t pid_msg;
-    zmq_msg_t sequence_no_msg;
-    zmq_msg_t call_id_msg;
-    zmq_msg_t data_msg;
-    
-    zmq_msg_init(&pid_msg);
-    zmq_msg_init(&sequence_no_msg);
-    zmq_msg_init(&call_id_msg);
-    zmq_msg_init(&data_msg);
-
-    do {
-        // read pid
-        if (_pims_zmq_msg_recv(&pid_msg, worker, 0) == -1)
-        {
-            ERROR("recv error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        // read sequence no
-        if (_pims_zmq_msg_recv(&sequence_no_msg, worker, 0) == -1)
-        {
-            ERROR("recv error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        // read call id
-        if (_pims_zmq_msg_recv(&call_id_msg, worker, 0) == -1)
-        {
-            ERROR("recv error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        more = 0;
-        zmq_getsockopt(worker, ZMQ_RCVMORE, &more, &more_size);
-        if (more)
-        {
-            // read data
-            if (_pims_zmq_msg_recv(&data_msg, worker, 0) == -1)
-            {
-                ERROR("recv error : %s", zmq_strerror(errno));
-                break;
-            }
-
-            dhandle_in = pims_ipc_data_unmarshal_with_zmq(&data_msg);
-            if (dhandle_in == NULL)
-            {
-                ERROR("unmarshal error");
-                break;
-            }
-        }
-
-        pid = (char*)zmq_msg_data(&pid_msg);
-        ASSERT(pid);
-        VERBOSE("client pid = %s", pid);
-
-        call_id = (char*)zmq_msg_data(&call_id_msg);
-        ASSERT(call_id);
-        VERBOSE("call_id = [%s]", call_id);
-
-        // call a callback function with call id and data
-        if (strcmp(PIMS_IPC_CALL_ID_CREATE, call_id) == 0)
-        {
-            is_create = TRUE;
-        }
-        else if (strcmp(PIMS_IPC_CALL_ID_DESTROY, call_id) == 0)
-        {
-            is_destroy = TRUE;
-        }
-        else
-        {
-            __run_callback(worker_id, call_id, dhandle_in, &dhandle_out);
-        }
-
-        // send pid
-        if (_pims_zmq_msg_send(&pid_msg, worker, ZMQ_SNDMORE) == -1)
-        {
-            ERROR("send error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        // send empty 
-        zmq_msg_t empty_msg;
-        zmq_msg_init_size(&empty_msg, 0);
-        if (_pims_zmq_msg_send(&empty_msg, worker, ZMQ_SNDMORE) == -1)
-        {
-            ERROR("send error : %s", zmq_strerror(errno));
-            zmq_msg_close(&empty_msg);
-            break;
-        }
-        zmq_msg_close(&empty_msg);
-
-        // send sequence no
-        if (_pims_zmq_msg_send(&sequence_no_msg, worker, ZMQ_SNDMORE) == -1)
-        {
-            ERROR("send error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        if (dhandle_out)
-        {
-            // send call id
-            if (_pims_zmq_msg_send(&call_id_msg, worker, ZMQ_SNDMORE) == -1)
-            {
-                ERROR("send error : %s", zmq_strerror(errno));
-                break;
-            }
-
-            // marshal data
-            zmq_msg_close(&data_msg);
-            zmq_msg_init(&data_msg);
-            if (pims_ipc_data_marshal_with_zmq(dhandle_out, &data_msg) != 0)
-            {
-                ERROR("marshal error");
-                break;
-            }
-
-            // send data
-            VERBOSE("the size of sending data = %d", zmq_msg_size(&data_msg));
-            if (_pims_zmq_msg_send(&data_msg, worker, 0) == -1)
-            {
-                ERROR("send error : %s", zmq_strerror(errno));
-                break;
-            }
-        }
-        else
-        {
-            // send call id
-            if (_pims_zmq_msg_send(&call_id_msg, worker, 0) == -1)
-            {
-                ERROR("send error : %s", zmq_strerror(errno));
-                break;
-            }
-        }
-    } while (0);
-
-    zmq_msg_close(&pid_msg);
-    zmq_msg_close(&sequence_no_msg);
-    zmq_msg_close(&call_id_msg);
-    zmq_msg_close(&data_msg);
-
-    if (dhandle_in)
-        pims_ipc_data_destroy(dhandle_in);
-    if (dhandle_out)
-        pims_ipc_data_destroy(dhandle_out);
-
-    VERBOSE("responsed");
-
-#ifdef _TEST
-    gettimeofday(&tv, NULL);
-    printf("worker time[%lu:%lu]\n", tv.tv_sec, tv.tv_usec);
-#endif
-
-    if (is_destroy)
-        return -1;
-    return 0;
+       int ret = 0;
+       unsigned int client_id_len = strlen(client_id);
+
+       if (!data) {
+               INFO("No data to send NULL\n");
+               return -1;
+       }
+
+       unsigned int len = sizeof(unsigned int)                 // total size
+               + client_id_len + sizeof(unsigned int)          // client_id
+               + sizeof(unsigned int)                                                  // seq_no
+               + data->call_id_len + sizeof(unsigned int)      // call_id
+               + sizeof(unsigned int);                                                 // is data
+       unsigned int total_len = len;
+
+       if (data->is_data) {
+               len += sizeof(unsigned int); // data
+               total_len = len + data->data_len;               // data
+       }
+
+       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);
+
+       char buf[len+1];
+
+       int length = 0;
+       memset(buf, 0x0, len+1);
+
+       // total_len
+       memcpy(buf, (void*)&total_len, sizeof(unsigned int));
+       length += sizeof(unsigned int);
+
+       // client_id
+       memcpy(buf+length, (void*)&(client_id_len), sizeof(unsigned int));
+       length += sizeof(unsigned int);
+       memcpy(buf+length, (void*)(client_id), client_id_len);
+       length += client_id_len;
+
+       // seq_no
+       memcpy(buf+length, (void*)&(data->seq_no), sizeof(unsigned int));
+       length += sizeof(unsigned int);
+
+       // call id
+       memcpy(buf+length, (void*)&(data->call_id_len), sizeof(unsigned int));
+       length += sizeof(unsigned int);
+       memcpy(buf+length, (void*)(data->call_id), data->call_id_len);
+       length += data->call_id_len;
+
+       // is_data
+       memcpy(buf+length, (void*)&(data->is_data), sizeof(unsigned int));
+       length += sizeof(unsigned int);
+
+       if (data->is_data) {
+               memcpy(buf+length, (void*)&(data->data_len), sizeof(unsigned int));
+               length += sizeof(unsigned int);
+               ret = socket_send(fd, buf, length);
+
+               // send data
+               if (ret > 0)
+                       ret += socket_send_data(fd, data->data, data->data_len);
+       }
+       else
+               ret = socket_send(fd, buf, length);
+
+       return ret;
 }
 
-static int __process_manager_task(int worker_id, void *context, void *manager)
+static gboolean __worker_raw_data_pop(pims_ipc_worker_data_s *worker, pims_ipc_raw_data_s **data)
 {
-    VERBOSE("");
-
-    // read pid
-    zmq_msg_t pid_msg;
-    zmq_msg_init(&pid_msg);
-    if (_pims_zmq_msg_recv(&pid_msg, manager, 0) == -1)
-    {
-        ERROR("recv error : %s", zmq_strerror(errno));
-        zmq_msg_close(&pid_msg);
-        return -1;
-    }
-    zmq_msg_close(&pid_msg);
-
-    return -1;
+       if (!worker)
+               return FALSE;
+
+       pthread_mutex_lock(&worker->queue_mutex);
+       if (!worker->queue) {
+               pthread_mutex_unlock(&worker->queue_mutex);
+               *data = NULL;
+               return FALSE;
+       }
+
+       *data = g_list_first(worker->queue)->data;
+       worker->queue = g_list_delete_link(worker->queue, g_list_first(worker->queue));
+       pthread_mutex_unlock(&worker->queue_mutex);
+
+       return TRUE;
 }
 
-static void* __worker_loop(void *args)
+static void* __worker_loop(void *data)
 {
-    void *context = args;
-    int worker_id = (int)pthread_self();
-    char *path = NULL;
-
-    void *worker = zmq_socket(context, ZMQ_DEALER);
-    if (!worker)
-    {
-        ERROR("socket error : %s", zmq_strerror(errno));
-        return NULL;
-    }
-    char string_worker_id[PIMS_IPC_STRING_WORKER_ID_SIZE + 1] = "";
-    if (zmq_setsockopt(worker, ZMQ_IDENTITY, __get_string_worker_id(worker_id, string_worker_id),
-                PIMS_IPC_STRING_WORKER_ID_SIZE) != 0)
-    {
-        ERROR("setsockopt error : %s", zmq_strerror(errno));
-        zmq_close(worker);
-        return NULL;
-    }
-    path = g_strdup_printf("inproc://%s-%s", _g_singleton->service, PIMS_IPC_DEALER_PATH);
-    if (zmq_connect(worker, path) != 0)
-    {
-        ERROR("connect error : %s", zmq_strerror(errno));
-        g_free(path);
-        zmq_close(worker);
-        return NULL;
-    }
-    g_free(path);
-
-    // send the ID of a worker to the manager
-    void *manager = zmq_socket(context, ZMQ_DEALER);
-    if (!manager)
-    {
-        ERROR("socket error : %s", zmq_strerror(errno));
-        zmq_close(worker);
-        return NULL;
-    }
-    if (zmq_setsockopt(manager, ZMQ_IDENTITY, __get_string_worker_id(worker_id, string_worker_id),
-                PIMS_IPC_STRING_WORKER_ID_SIZE) != 0)
-    {
-        ERROR("setsockopt error : %s", zmq_strerror(errno));
-        zmq_close(manager);
-        zmq_close(worker);
-        return NULL;
-    }
-    path = g_strdup_printf("inproc://%s-%s", _g_singleton->service, PIMS_IPC_MANAGER_PATH);
-    if (zmq_connect(manager, path) != 0)
-    {
-        ERROR("connect error : %s", zmq_strerror(errno));
-        g_free(path);
-        zmq_close(manager);
-        zmq_close(worker);
-        return NULL;
-    }
-    g_free(path);
-
-    VERBOSE("starting worker id: %x", worker_id);
-    zmq_msg_t message;
-    zmq_msg_init_size(&message, sizeof(int));
-    memcpy(zmq_msg_data(&message), &worker_id, sizeof(int));
-    if (_pims_zmq_msg_send(&message, manager, 0) == -1)
-    {
-        ERROR("send error : %s", zmq_strerror(errno));
-        zmq_msg_close(&message);
-        zmq_close(manager);
-        zmq_close(worker);
-        return NULL;
-    }
-    zmq_msg_close(&message);
-
-    // poll all sockets
-    while (1)
-    {
-        zmq_pollitem_t items[] = {
-            {worker, 0, ZMQ_POLLIN, 0},
-            {manager, 0, ZMQ_POLLIN, 0}
-        };
-
-        if (zmq_poll(items, 2, -1) == -1)
-        {
-            if (errno == EINTR)
-                continue;
-
-            ERROR("poll error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        if (items[0].revents & ZMQ_POLLIN)
-        {
-            if (__process_worker_task(worker_id, context, worker) != 0)
-                break;
-        }
-
-        if (items[1].revents & ZMQ_POLLIN)
-        {
-            if (__process_manager_task(worker_id, context, manager) != 0)
-                break;
-        }
-    }
-
-    VERBOSE("terminating worker id: %x", worker_id);
-
-    zmq_close(manager);
-    zmq_close(worker);
-    return NULL;
+       int ret;
+       int worker_id;
+       int worker_fd;
+       pims_ipc_svc_s *ipc_svc = (pims_ipc_svc_s*)data;
+       pims_ipc_worker_data_s *worker_data;
+       bool disconnected = false;
+
+       worker_fd = eventfd(0, 0);
+       if (worker_fd == -1)
+               return NULL;
+       worker_id = (int)pthread_self();
+
+       worker_data = calloc(1, sizeof(pims_ipc_worker_data_s));
+       worker_data->fd = worker_fd;
+       worker_data->worker_id = worker_id;
+       worker_data->client_fd = -1;
+       worker_data->stop_thread = false;
+       pthread_mutex_init(&worker_data->queue_mutex, 0);
+
+       pthread_mutex_lock(&ipc_svc->task_fds_mutex);
+       g_hash_table_insert(ipc_svc->task_fds, GINT_TO_POINTER(worker_fd), worker_data);
+       pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
+
+       pthread_mutex_lock(&ipc_svc->manager_queue_from_worker_mutex);
+       ipc_svc->manager_queue_from_worker = g_list_append(ipc_svc->manager_queue_from_worker, (void*)worker_fd);
+       pthread_mutex_unlock(&ipc_svc->manager_queue_from_worker_mutex);
+
+       write_command(ipc_svc->manager, 1);
+       DEBUG("worker register to manager : worker_id(%08x00), worker_fd(%d)\n", worker_id, worker_fd);
+
+       struct pollfd *pollfds = (struct pollfd*) malloc (1 * sizeof (struct pollfd));
+       pollfds[0].fd = worker_fd;
+       pollfds[0].events = POLLIN;
+
+       while (!worker_data->stop_thread) {
+               while(1) {
+                       if (worker_data->stop_thread)
+                               break;
+                       ret = poll(pollfds, 1, 3000);   // waiting command from router
+                       if (ret == -1 && errno == EINTR) {
+                               continue;
+                       }
+                       break;
+               }
+
+               if (worker_data->stop_thread)
+                       break;
+
+               if (ret > 0) {
+                       pims_ipc_raw_data_s *raw_data = NULL;
+                       pims_ipc_raw_data_s *result = NULL;
+
+                       if (pollfds[0].revents & POLLIN) {
+                               uint64_t dummy;
+                               read_command(pollfds[0].fd, &dummy);
+                               if (__worker_raw_data_pop(worker_data, &raw_data)) {
+                                       pims_ipc_data_h data_in = NULL;
+                                       pims_ipc_data_h data_out = NULL;
+
+                                       if (strcmp(PIMS_IPC_CALL_ID_CREATE, raw_data->call_id) == 0) {
+
+                                       }
+                                       else if (strcmp(PIMS_IPC_CALL_ID_DESTROY, raw_data->call_id) == 0) {
+                                               disconnected = true;
+                                       }
+                                       else {
+                                               data_in = pims_ipc_data_steal_unmarshal(raw_data->data, raw_data->data_len);
+                                               raw_data->data = NULL;
+                                               raw_data->data_len = 0;
+                                               raw_data->is_data = false;
+                                               __run_callback(worker_id, raw_data->call_id, data_in, &data_out);
+                                               pims_ipc_data_destroy(data_in);
+                                       }
+
+                                       if (data_out) {
+                                               __make_raw_data(raw_data->call_id, raw_data->seq_no, data_out, &result);
+                                               pims_ipc_data_destroy(data_out);
+                                       }
+                                       else
+                                               __make_raw_data(raw_data->call_id, raw_data->seq_no, NULL, &result);
+
+                                       if (worker_data->client_fd != -1)
+                                               __send_raw_data(worker_data->client_fd, raw_data->client_id, result);
+                                       __free_raw_data(raw_data);
+                                       __free_raw_data(result);
+                               }
+                       }
+               }
+       }
+
+       if (!disconnected)
+               ERROR("client fd closed, worker_fd : %d", worker_fd);
+       INFO("task thread terminated --------------------------- (worker_fd : %d)", worker_fd);
+
+       pthread_mutex_lock(&ipc_svc->task_fds_mutex);
+       g_hash_table_remove(ipc_svc->task_fds, GINT_TO_POINTER(worker_fd));             // __worker_data_free will be called
+       pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
+
+       close(worker_fd);
+       free ((void*)pollfds);
+
+       if (_client_disconnected_cb.callback)
+               _client_disconnected_cb.callback((pims_ipc_h)worker_id, _client_disconnected_cb.user_data);
+
+       return NULL;
 }
 
-static void __launch_worker(void *(*start_routine) (void *), void *context)
+static void __launch_thread(void *(*start_routine) (void *), void *data)
 {
-    pthread_t worker;
-    pthread_attr_t attr;
+       pthread_t worker;
+       pthread_attr_t attr;
 
-    // set kernel thread
-    pthread_attr_init(&attr);
-    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+       // set kernel thread
+       pthread_attr_init(&attr);
+       pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
 
-    pthread_create(&worker, &attr, start_routine, context);
-    // detach this thread
-    pthread_detach(worker);
+       pthread_create(&worker, &attr, start_routine, data);
+       // detach this thread
+       pthread_detach(worker);
 }
 
 static gboolean __is_worker_available()
 {
-    if (_g_singleton->workers)
-        return TRUE;
-    else
-        return FALSE;
+       if (_g_singleton->workers)
+               return TRUE;
+       else
+               return FALSE;
 }
 
-static int __get_worker(const char *pid, int *worker_id)
+static int __get_worker(const char *client_id, int *worker_id)
 {
-    ASSERT(pid);
-    ASSERT(worker_id);
+       ASSERT(client_id);
+       ASSERT(worker_id);
 
-    if (!__is_worker_available())
-    {
-        ERROR("There is no idle worker");
-        return -1;
-    }
-    *worker_id = (int)(g_list_first(_g_singleton->workers)->data);
-    _g_singleton->workers = g_list_delete_link(_g_singleton->workers,
-            g_list_first(_g_singleton->workers));
+       if (!__is_worker_available()) {
+               ERROR("There is no idle worker");
+               return -1;
+       }
+       *worker_id = (int)(g_list_first(_g_singleton->workers)->data);
+       _g_singleton->workers = g_list_delete_link(_g_singleton->workers,
+                       g_list_first(_g_singleton->workers));
 
-    g_hash_table_insert(_g_singleton->client_table, g_strdup(pid), GINT_TO_POINTER(*worker_id));
+       g_hash_table_insert(_g_singleton->client_worker_map, g_strdup(client_id), GINT_TO_POINTER(*worker_id));
 
-    return 0;
+       return 0;
 }
 
-static int __find_worker(const char *pid, int *worker_id)
+static int __find_worker(const char *client_id, int *worker_fd)
 {
-    char *orig_pid = NULL;
-
-    ASSERT(pid);
-    ASSERT(worker_id);
-    
-    if (g_hash_table_lookup_extended(_g_singleton->client_table, pid,
-                (gpointer*)&orig_pid, (gpointer*)worker_id) == TRUE)
-    {
-        VERBOSE("found worker id for %s = %x", pid, *worker_id);
-        return 0;
-    }
-    else
-    {
-        VERBOSE("unable to find worker id for %s", pid);
-        return -1;
-    }
+       char *orig_pid = NULL;
+       int fd;
+
+       ASSERT(client_id);
+       ASSERT(worker_fd);
+
+       if (FALSE == g_hash_table_lookup_extended(_g_singleton->client_worker_map, client_id,
+                               (gpointer*)&orig_pid, (gpointer*)&fd)) {
+               VERBOSE("unable to find worker id for %s", client_id);
+               return -1;
+       }
+
+       *worker_fd = GPOINTER_TO_INT(fd);
+       return 0;
 }
 
-static void __remove_worker(const char *pid)
+static bool __request_pop(pims_ipc_request_s *data_queue, pims_ipc_raw_data_s **data)
 {
-    g_hash_table_remove(_g_singleton->client_table, pid);
+       bool ret = false;
+       GList *cursor;
+
+       pthread_mutex_lock(&data_queue->raw_data_mutex);
+       cursor = g_list_first(data_queue->raw_data);
+       if (cursor) {
+               *data = cursor->data;
+               data_queue->raw_data = g_list_delete_link(data_queue->raw_data, cursor);
+               (data_queue->request_count)--;
+
+               ret = true;
+       }
+       else
+               *data = NULL;
+
+       pthread_mutex_unlock(&data_queue->raw_data_mutex);
+       return ret;
 }
 
-static void __terminate_worker(void *manager, int worker_id, const char *pid)
+static bool __worker_raw_data_push(pims_ipc_worker_data_s *worker_data, int client_fd, pims_ipc_raw_data_s *data)
 {
-    // send worker id
-    zmq_msg_t worker_id_msg;
-    zmq_msg_init_size(&worker_id_msg, PIMS_IPC_STRING_WORKER_ID_SIZE);
-    char string_worker_id[PIMS_IPC_STRING_WORKER_ID_SIZE + 1] = "";
-    memcpy(zmq_msg_data(&worker_id_msg), __get_string_worker_id(worker_id, string_worker_id),
-            PIMS_IPC_STRING_WORKER_ID_SIZE);
-    if (_pims_zmq_msg_send(&worker_id_msg, manager, ZMQ_SNDMORE) == -1)
-    {
-        ERROR("send error : %s", zmq_strerror(errno));
-        zmq_msg_close(&worker_id_msg);
-        return;
-    }
-    zmq_msg_close(&worker_id_msg);
-
-    // send pid
-    zmq_msg_t pid_msg;
-    zmq_msg_init_data(&pid_msg, (char*)pid, strlen(pid) + 1, NULL, NULL);
-    if (_pims_zmq_msg_send(&pid_msg, manager, 0) == -1)
-    {
-        ERROR("send error : %s", zmq_strerror(errno));
-        zmq_msg_close(&pid_msg);
-        return;
-    }
-    zmq_msg_close(&pid_msg);
+       pthread_mutex_lock(&worker_data->queue_mutex);
+       worker_data->queue = g_list_append(worker_data->queue, data);
+       worker_data->client_fd = client_fd;
+       pthread_mutex_unlock(&worker_data->queue_mutex);
+
+       return true;
 }
 
-static gboolean __enqueue_zmq_msg(zmq_msg_t *zmsg)
+static int __process_router_event(pims_ipc_svc_s *ipc_svc, gboolean for_queue)
 {
-    zmq_msg_t *lpzmsg = NULL;
-    
-    if (zmsg)
-    {
-        lpzmsg = g_new0(zmq_msg_t, 1);
-        zmq_msg_init(lpzmsg);
-        zmq_msg_copy(lpzmsg, zmsg);
-    }
-    _g_singleton->requests = g_list_append(_g_singleton->requests, lpzmsg);
-
-    return TRUE;
+       gboolean is_valid = FALSE;
+       pims_ipc_request_s *data_queue = NULL;
+       GList *queue_cursor = NULL;
+       int worker_fd = 0;
+       char *client_id = NULL;
+       int *org_fd;
+       int ret;
+
+       do {
+               pthread_mutex_lock(&ipc_svc->request_data_queue_mutex);
+               queue_cursor = g_list_first(ipc_svc->request_queue);
+               if (NULL == queue_cursor) {
+                       pthread_mutex_unlock(&ipc_svc->request_data_queue_mutex);
+                       return 0;
+               }
+               client_id = (char *)(queue_cursor->data);
+               ASSERT(client_id != NULL);
+               pthread_mutex_unlock(&ipc_svc->request_data_queue_mutex);
+
+               ret = g_hash_table_lookup_extended(ipc_svc->request_data_queue, (void*)client_id, (gpointer*)&org_fd, (gpointer*)&data_queue);
+
+               if (for_queue)
+                       ipc_svc->delay_count--;
+
+               if (ret == TRUE && data_queue) {
+                       int *org_fd;
+                       pims_ipc_worker_data_s *worker_data = NULL;
+
+                       pthread_mutex_lock(&data_queue->raw_data_mutex);
+                       GList *cursor = g_list_first(data_queue->raw_data);
+                       if (!cursor) {
+                               pthread_mutex_unlock(&data_queue->raw_data_mutex);
+                               break;
+                       }
+
+                       pims_ipc_raw_data_s *data = (pims_ipc_raw_data_s*)(cursor->data);
+                       char *call_id = data->call_id;
+                       int client_fd = data_queue->client_fd;
+
+                       ASSERT(call_id != NULL);
+
+                       VERBOSE("call_id = [%s]", call_id);
+                       if (strcmp(PIMS_IPC_CALL_ID_CREATE, call_id) == 0) {
+                               // Get a worker. If cannot get a worker, create a worker and enqueue a current request
+                               __launch_thread(__worker_loop, ipc_svc);
+                               if (__get_worker((const char*)client_id, &worker_fd) != 0) {
+                                       ipc_svc->delay_count++;
+                                       pthread_mutex_unlock(&data_queue->raw_data_mutex);
+                                       is_valid = TRUE;
+                                       break;
+                               }
+                       }
+                       else {
+                               // Find a worker
+                               if (__find_worker((const char*)client_id, &worker_fd) != 0) {
+                                       ERROR("unable to find a worker");
+                                       pthread_mutex_unlock(&data_queue->raw_data_mutex);
+                                       break;
+                               }
+                       }
+                       pthread_mutex_unlock(&data_queue->raw_data_mutex);
+
+                       VERBOSE("routing client_id : %s, seq_no: %d, client_fd = %d, worker fd = %d", client_id, data->seq_no, client_fd, worker_fd);
+
+                       if (worker_fd <= 0)
+                               break;
+
+                       pthread_mutex_lock(&ipc_svc->task_fds_mutex);
+                       if (FALSE == g_hash_table_lookup_extended(ipc_svc->task_fds,
+                                               GINT_TO_POINTER(worker_fd), (gpointer*)&org_fd, (gpointer*)&worker_data)) {
+                               ERROR("hash lookup fail : worker_fd (%d)", worker_fd);
+                               pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
+                               break;
+                       }
+
+                       if (__request_pop(data_queue, &data)) {
+                               __worker_raw_data_push(worker_data, client_fd, data);
+                               write_command(worker_fd, 1);
+                       }
+
+                       pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
+               }
+
+               pthread_mutex_lock(&ipc_svc->request_data_queue_mutex);
+               free(client_id);
+               ipc_svc->request_queue = g_list_delete_link(ipc_svc->request_queue, queue_cursor);
+               pthread_mutex_unlock(&ipc_svc->request_data_queue_mutex);
+
+               is_valid = TRUE;
+       } while (0);
+
+       if (is_valid == FALSE)
+               return -1;
+
+       return 1;
 }
 
-static gboolean __dequeue_zmq_msg(zmq_msg_t *zmsg)
+static int __process_manager_event(pims_ipc_svc_s *ipc_svc)
 {
-    zmq_msg_t *lpzmsg = NULL;
-
-    ASSERT(_g_singleton->requests);
-    lpzmsg = (zmq_msg_t*)(g_list_first(_g_singleton->requests)->data);
-    _g_singleton->requests = g_list_delete_link(_g_singleton->requests,
-            g_list_first(_g_singleton->requests));
+       GList *cursor = NULL;
+       int worker_fd;
+
+       // client socket terminated without disconnect request
+       pthread_mutex_lock(&ipc_svc->manager_queue_from_epoll_mutex);
+       if (ipc_svc->manager_queue_from_epoll) {
+               cursor = g_list_first(ipc_svc->manager_queue_from_epoll);
+               char *client_id = (char*)cursor->data;
+               __find_worker(client_id, &worker_fd);
+
+               ipc_svc->manager_queue_from_epoll = g_list_delete_link(ipc_svc->manager_queue_from_epoll, cursor);
+               pthread_mutex_unlock(&ipc_svc->manager_queue_from_epoll_mutex);
+
+               // remove client_fd
+               g_hash_table_remove(ipc_svc->client_worker_map, client_id);
+               free(client_id);
+
+               // stop worker thread
+               if (worker_fd) {
+                       int *org_fd;
+                       pims_ipc_worker_data_s *worker_data;
+
+                       pthread_mutex_lock(&ipc_svc->task_fds_mutex);
+                       if (FALSE == g_hash_table_lookup_extended(ipc_svc->task_fds,
+                                               GINT_TO_POINTER(worker_fd), (gpointer*)&org_fd, (gpointer*)&worker_data)) {
+                               ERROR("g_hash_table_lookup_extended fail : worker_fd (%d)", worker_fd);
+                               pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
+                               return -1;
+                       }
+                       worker_data->stop_thread = true;
+                       worker_data->client_fd = -1;
+                       pthread_mutex_unlock(&ipc_svc->task_fds_mutex);
+
+                       write_command(worker_fd, 1);
+                       VERBOSE("write command to worker terminate (worker_fd : %d)", worker_fd);
+               }
+               return 0;
+       }
+       pthread_mutex_unlock(&ipc_svc->manager_queue_from_epoll_mutex);
+
+       // create new worker
+       pthread_mutex_lock(&ipc_svc->manager_queue_from_worker_mutex);
+       if (ipc_svc->manager_queue_from_worker) {
+
+               cursor = g_list_first(ipc_svc->manager_queue_from_worker);
+               while (cursor) {
+                       worker_fd = (int)cursor->data;
+                       ipc_svc->manager_queue_from_worker = g_list_delete_link(ipc_svc->manager_queue_from_worker, cursor);
+
+                       if (worker_fd) {
+                               DEBUG("add idle worker_fd : %d", worker_fd);
+                               ipc_svc->workers = g_list_append(ipc_svc->workers, (void*)worker_fd);
+                       }
+                       cursor = g_list_first(ipc_svc->manager_queue_from_worker);
+               }
+               pthread_mutex_unlock(&ipc_svc->manager_queue_from_worker_mutex);
+               return 0;
+       }
+       pthread_mutex_unlock(&ipc_svc->manager_queue_from_worker_mutex);
+
+       return 0;
+}
 
-    if (lpzmsg == NULL)
-        return FALSE;
+// if delete = true, steal client_id, then free(client_id)
+// if delete = false, return client_id pointer, then do no call free(client_id
+static int __find_client_id(pims_ipc_svc_s *ipc_svc, int client_fd, bool delete, char **client_id)
+{
+       pims_ipc_client_map_s *client;
+       GList *cursor = NULL;
+       cursor = g_list_first(ipc_svc->client_id_fd_map);
+       while(cursor) {
+               client = cursor->data;
+               if (client->fd == client_fd) {
+                       *client_id = client->id;
+                       if (delete) {
+                               client->id = NULL;
+                               ipc_svc->client_id_fd_map = g_list_delete_link(ipc_svc->client_id_fd_map, cursor);                      //free(client);
+                               free(client);
+                       }
+                       return 0;
+               }
+               cursor = g_list_next(cursor);
+       }
+       return -1;
+}
 
-    zmq_msg_copy(zmsg, lpzmsg);
-    zmq_msg_close(lpzmsg);
-    g_free(lpzmsg);
+static void __request_push(pims_ipc_svc_s *ipc_svc, char *client_id, int client_fd, pims_ipc_raw_data_s *data)
+{
+       int ret;
+       int *org_fd;
+       pims_ipc_request_s *data_queue = NULL;
+
+       pthread_mutex_lock(&ipc_svc->request_data_queue_mutex);
+       ret = g_hash_table_lookup_extended(ipc_svc->request_data_queue, (void*)client_id, (gpointer*)&org_fd,(gpointer*)&data_queue);
+       if (ret == TRUE && data_queue) {
+       }
+       else {
+               data_queue = calloc(1, sizeof(pims_ipc_request_s));
+               data_queue->request_count = 0;
+               pthread_mutex_init(&data_queue->raw_data_mutex, 0);
+
+               g_hash_table_insert(ipc_svc->request_data_queue, g_strdup(client_id), data_queue);
+       }
+       ipc_svc->request_queue = g_list_append(ipc_svc->request_queue, g_strdup(client_id));
+       pthread_mutex_unlock(&ipc_svc->request_data_queue_mutex);
+
+       pthread_mutex_lock(&data_queue->raw_data_mutex);
+       data_queue->raw_data = g_list_append(data_queue->raw_data, data);
+       data_queue->client_fd = client_fd;
+       data_queue->request_count++;
+       pthread_mutex_unlock(&data_queue->raw_data_mutex);
+}
 
-    return TRUE;
+static void __delete_request_queue(pims_ipc_svc_s *ipc_svc, char *client_id)
+{
+       pims_ipc_request_s *data_queue = NULL;
+       int ret;
+       int *org_fd;
+       GList *l;
+       GList *cursor;
+
+       pthread_mutex_lock(&ipc_svc->request_data_queue_mutex);
+       ret = g_hash_table_lookup_extended(ipc_svc->request_data_queue, (void*)client_id, (gpointer*)&org_fd,(gpointer*)&data_queue);
+       if (ret == TRUE)
+               g_hash_table_remove(ipc_svc->request_data_queue, (void*)client_id);
+
+       cursor = g_list_first(ipc_svc->request_queue);
+       while (cursor) {
+               l = cursor;
+               char *id = l->data;
+               cursor = g_list_next(cursor);
+               if (id && strcmp(id, client_id) == 0) {
+                       free(id);
+                       ipc_svc->request_queue = g_list_delete_link(ipc_svc->request_queue, l);
+               }
+       }
+       pthread_mutex_unlock(&ipc_svc->request_data_queue_mutex);
+
+       if (data_queue) {
+               pthread_mutex_lock(&data_queue->raw_data_mutex);
+               cursor = g_list_first(data_queue->raw_data);
+               pims_ipc_raw_data_s *data;
+               while(cursor) {
+                       l = cursor;
+                       data = (pims_ipc_raw_data_s *)cursor->data;
+                       cursor = g_list_next(cursor);
+                       data_queue->raw_data = g_list_delete_link(data_queue->raw_data, l);
+                       __free_raw_data(data);
+               }
+               g_list_free(data_queue->raw_data);
+               pthread_mutex_unlock(&data_queue->raw_data_mutex);
+               pthread_mutex_destroy(&data_queue->raw_data_mutex);
+               free(data_queue);
+       }
 }
 
-static int __process_router_event(void *context, void *router, void *worker, gboolean for_queue)
+static int __send_identify(int fd, unsigned int seq_no, char *id, int id_len)
 {
-    char *pid = NULL;
-    char *call_id = NULL;
-    int64_t more = 0;
-    size_t more_size = sizeof(more);
-    int worker_id = -1;
-    gboolean is_with_data = FALSE;
-    gboolean is_valid = FALSE;
-
-#ifdef _TEST
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    printf("router time[%lu:%lu]\n", tv.tv_sec, tv.tv_usec);
-#endif
-
-    // init messages for receiving
-    zmq_msg_t pid_msg;
-    zmq_msg_t sequence_no_msg;
-    zmq_msg_t call_id_msg;
-    zmq_msg_t data_msg;
-    
-    zmq_msg_init(&pid_msg);
-    zmq_msg_init(&sequence_no_msg);
-    zmq_msg_init(&call_id_msg);
-    zmq_msg_init(&data_msg);
-
-    // relay a request from a client to a worker
-    do {
-        if (for_queue)
-        {
-            // dequeue a request
-            __dequeue_zmq_msg(&pid_msg);
-            __dequeue_zmq_msg(&sequence_no_msg);
-            __dequeue_zmq_msg(&call_id_msg);
-            is_with_data = __dequeue_zmq_msg(&data_msg);
-
-            if (is_with_data)
-                __dequeue_zmq_msg(NULL);
-        }
-        else
-        {
-            // read pid
-            if (_pims_zmq_msg_recv(&pid_msg, router, 0) == -1)
-            {
-                ERROR("recv error : %s", zmq_strerror(errno));
-                break;
-            }
-
-            // read empty and kill
-            zmq_msg_t empty_msg;
-            zmq_msg_init(&empty_msg);
-            if (_pims_zmq_msg_recv(&empty_msg, router, 0) == -1)
-            {
-                ERROR("recv error : %s", zmq_strerror(errno));
-                zmq_msg_close(&empty_msg);
-                break;
-            }
-            zmq_msg_close(&empty_msg);
-
-            // read sequence no
-            more = 0;
-            zmq_getsockopt(router, ZMQ_RCVMORE, &more, &more_size);
-            if (!more)
-            {
-                ERROR("recv error : corrupted message");
-                break;
-            }
-            if (_pims_zmq_msg_recv(&sequence_no_msg, router, 0) == -1)
-            {
-                ERROR("recv error : %s", zmq_strerror(errno));
-                break;
-            }
-
-            // read call id
-            more = 0;
-            zmq_getsockopt(router, ZMQ_RCVMORE, &more, &more_size);
-            if (!more)
-            {
-                ERROR("recv error : corrupted message");
-                break;
-            }
-            if (_pims_zmq_msg_recv(&call_id_msg, router, 0) == -1)
-            {
-                ERROR("recv error : %s", zmq_strerror(errno));
-                break;
-            }
-
-            // read data
-            more = 0;
-            zmq_getsockopt(router, ZMQ_RCVMORE, &more, &more_size);
-            if (more)
-            {
-                is_with_data = TRUE;
-                if (_pims_zmq_msg_recv(&data_msg, router, 0) == -1)
-                {
-                    ERROR("recv error : %s", zmq_strerror(errno));
-                    break;
-                }
-            }
-        }
-
-        pid = zmq_msg_data(&pid_msg);
-        ASSERT(pid != NULL);
-        VERBOSE("client pid = %s", pid);
-
-        call_id = (char*)zmq_msg_data(&call_id_msg);
-        ASSERT(call_id != NULL);
-        VERBOSE("call_id = [%s], create_call_id = [%s]", PIMS_IPC_CALL_ID_CREATE, call_id);
-        if (strcmp(PIMS_IPC_CALL_ID_CREATE, call_id) == 0)
-        {
-            // Get a worker. If cannot get a worker, create a worker and enqueue a current request 
-            __launch_worker(__worker_loop, context);
-            if (__get_worker((const char*)pid, &worker_id) != 0)
-            {
-                // enqueue a request until a new worker will be registered
-                __enqueue_zmq_msg(&pid_msg);
-                __enqueue_zmq_msg(&sequence_no_msg);
-                __enqueue_zmq_msg(&call_id_msg);
-                if (is_with_data)
-                    __enqueue_zmq_msg(&data_msg);
-                __enqueue_zmq_msg(NULL);
-
-                is_valid = TRUE;
-                break;
-            }
-        }
-        else
-        {
-            // Find a worker
-            if (__find_worker((const char*)pid, &worker_id) != 0)
-            {
-                ERROR("unable to find a worker");
-                break;
-            }
-
-            if (strcmp(PIMS_IPC_CALL_ID_DESTROY, call_id) == 0)
-            {
-                __remove_worker((const char*)pid);
-            }
-        }
-
-        VERBOSE("routing worker id = %x", worker_id);
-        // send worker id
-        zmq_msg_t worker_id_msg;
-        zmq_msg_init_size(&worker_id_msg, PIMS_IPC_STRING_WORKER_ID_SIZE);
-        char string_worker_id[PIMS_IPC_STRING_WORKER_ID_SIZE + 1] = "";
-        memcpy(zmq_msg_data(&worker_id_msg), __get_string_worker_id(worker_id, string_worker_id),
-                PIMS_IPC_STRING_WORKER_ID_SIZE);
-        if (_pims_zmq_msg_send(&worker_id_msg, worker, ZMQ_SNDMORE) == -1)
-        {
-            ERROR("send error : %s", zmq_strerror(errno));
-            zmq_msg_close(&worker_id_msg);
-            break;
-        }
-        zmq_msg_close(&worker_id_msg);
-
-        // send pid
-        if (_pims_zmq_msg_send(&pid_msg, worker, ZMQ_SNDMORE) == -1)
-        {
-            ERROR("send error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        // send sequence no
-        if (_pims_zmq_msg_send(&sequence_no_msg, worker, ZMQ_SNDMORE) == -1)
-        {
-            ERROR("send error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        // send call id
-        if (_pims_zmq_msg_send(&call_id_msg, worker, is_with_data?ZMQ_SNDMORE:0) == -1)
-        {
-            ERROR("send error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        // send data
-        if (is_with_data)
-        {
-            if (_pims_zmq_msg_send(&data_msg, worker, 0) == -1)
-            {
-                ERROR("send error : %s", zmq_strerror(errno));
-                break;
-            }
-        }
-
-        is_valid = TRUE;
-    } while (0);
-
-    zmq_msg_close(&pid_msg);
-    zmq_msg_close(&sequence_no_msg);
-    zmq_msg_close(&call_id_msg);
-    zmq_msg_close(&data_msg);
-
-#ifdef _TEST
-    gettimeofday(&tv, NULL);
-    printf("router time[%lu:%lu]\n", tv.tv_sec, tv.tv_usec);
-#endif
-
-    if (is_valid == FALSE)
-        return -1;
-    
-    return 0;
+       int len = sizeof(unsigned int)                                  // total size
+               + id_len + sizeof(unsigned int)         // id
+               + sizeof(unsigned int);                         // seq_no
+
+       char buf[len+1];
+
+       int length = 0;
+       memset(buf, 0x0, len+1);
+
+       // total len
+       memcpy(buf, (void*)&len, sizeof(unsigned int));
+       length += sizeof(unsigned int);
+
+       // id
+       memcpy(buf+length, (void*)&(id_len), sizeof(unsigned int));
+       length += sizeof(unsigned int);
+       memcpy(buf+length, (void*)(id), id_len);
+       length += id_len;
+
+       // seq_no
+       memcpy(buf+length, (void*)&(seq_no), sizeof(unsigned int));
+       length += sizeof(unsigned int);
+
+       return socket_send(fd, buf, length);
 }
 
-static int __process_worker_event(void *context, void *worker, void *router)
+static int __recv_raw_data(int fd, pims_ipc_raw_data_s **data, bool *identity)
 {
-    zmq_msg_t message;
-    int64_t more = 0;
-    size_t more_size = sizeof(more);
-
-    // Remove worker_id
-    zmq_msg_init(&message);
-    if (_pims_zmq_msg_recv(&message, worker, 0) == -1)
-    {
-        ERROR("recv error : %s", zmq_strerror(errno));
-    }
-    zmq_msg_close(&message);
-
-    while (1)
-    {
-        //  Process all parts of the message
-        zmq_msg_init(&message);
-        if (_pims_zmq_msg_recv(&message, worker, 0) == -1)
-        {
-            ERROR("recv error : %s", zmq_strerror(errno));
-        }
-        more = 0;
-        zmq_getsockopt(worker, ZMQ_RCVMORE, &more, &more_size);
-        VERBOSE("router received a message : more[%u]", (unsigned int)more);
-        if (_pims_zmq_msg_send(&message, router, more?ZMQ_SNDMORE:0) == -1)
-        {
-            ERROR("send error : %s", zmq_strerror(errno));
-        }
-        zmq_msg_close(&message);
-        if (!more)
-            break;      //  Last message part
-    }
-
-    return 0;
+       int len = 0;
+       pims_ipc_raw_data_s *temp;
+
+       /* read the size of message. note that ioctl is non-blocking */
+       if (ioctl(fd, FIONREAD, &len)) {
+               ERROR("ioctl failed: %d", errno);
+               return -1;
+       }
+
+       /* when server or client closed socket */
+       if (len == 0) {
+               INFO("[IPC Socket] connection is closed");
+               return 0;
+       }
+
+       temp = (pims_ipc_raw_data_s*)calloc(1, sizeof(pims_ipc_raw_data_s));
+       temp->client_id = NULL;
+       temp->client_id_len = 0;
+       temp->call_id = NULL;
+       temp->call_id_len = 0;
+       temp->seq_no = 0;
+       temp->is_data = FALSE;
+       temp->data = NULL;
+       temp->data_len = 0;
+
+       int ret = 0;
+       unsigned int read_len = 0;
+       unsigned int total_len = 0;
+       unsigned int is_data = FALSE;
+
+       do {
+               // total length
+               ret = read(fd, (void *)&total_len, sizeof(unsigned int));
+               if (ret < 0) {   ERROR("read error"); break;            }
+               read_len += ret;
+
+               // client_id
+               ret  = read(fd, (void *)&(temp->client_id_len), sizeof(unsigned int));
+               if (ret < 0) {   ERROR("read error"); break;            }
+               read_len += ret;
+
+               temp->client_id = calloc(1, temp->client_id_len+1);
+               ret = socket_recv(fd, (void *)&(temp->client_id), temp->client_id_len);
+               if (ret < 0) {   ERROR("socket_recv error"); break;             }
+               read_len += ret;
+
+               // sequnce no
+               ret = read(fd, (void *)&(temp->seq_no), sizeof(unsigned int));
+               if (ret < 0) {   ERROR("read error"); break;            }
+               read_len += ret;
+
+               if (total_len == read_len) {
+                       *data = temp;
+                       *identity = true;
+                       return read_len;
+               }
+
+               // call_id
+               ret  = read(fd, (void *)&(temp->call_id_len), sizeof(unsigned int));
+               if (ret < 0)    { ERROR("read error"); break;           }
+               read_len += ret;
+
+               temp->call_id = calloc(1, temp->call_id_len+1);
+               ret = socket_recv(fd, (void *)&(temp->call_id), temp->call_id_len);
+               if (ret < 0) {   ERROR("socket_recv error"); break;             }
+               read_len += ret;
+
+               // is_data
+               ret = read(fd, (void *)&(is_data), sizeof(unsigned int));
+               if (ret < 0) {   ERROR("read error"); break;            }
+               read_len += ret;
+
+               // data
+               if (is_data) {
+                       temp->is_data = TRUE;
+                       ret = read(fd, (void *)&(temp->data_len), sizeof(unsigned int));
+                       if (ret < 0) {  ERROR("read error"); break;             }
+                       read_len += ret;
+
+                       temp->data = calloc(1, temp->data_len+1);
+                       ret = socket_recv(fd, (void *)&(temp->data), temp->data_len);
+                       if (ret < 0) {  ERROR("socket_recv error"); break;              }
+                       read_len += ret;
+               }
+
+               INFO("client_id : %s, call_id : %s, seq_no : %d", temp->client_id, temp->call_id, temp->seq_no);
+
+               *data = temp;
+               *identity = false;
+       }while(0);
+
+       if (ret < 0) {
+               __free_raw_data(temp);
+               *data = NULL;
+               *identity = false;
+       }
+
+       return read_len;
 }
 
-static int __process_manager_event(void *context, void *manager)
+static gboolean __request_handler(GIOChannel *src, GIOCondition condition, gpointer data)
 {
-    zmq_msg_t worker_id_msg;
-    int worker_id = -1;
-    
-    zmq_msg_init(&worker_id_msg);
-    if (_pims_zmq_msg_recv(&worker_id_msg, manager, 0) == -1)
-    {
-        ERROR("recv error : %s", zmq_strerror(errno));
-        zmq_msg_close(&worker_id_msg);
-        return -1;
-    }
-    zmq_msg_close(&worker_id_msg);
-
-    zmq_msg_init(&worker_id_msg);
-    if (_pims_zmq_msg_recv(&worker_id_msg, manager, 0) == -1)
-    {
-        ERROR("recv error : %s", zmq_strerror(errno));
-        zmq_msg_close(&worker_id_msg);
-        return -1;
-    }
-    memcpy(&worker_id, zmq_msg_data(&worker_id_msg), sizeof(int));
-    zmq_msg_close(&worker_id_msg);
-
-    VERBOSE("registered worker id = %x", worker_id);
-    _g_singleton->workers = g_list_append(_g_singleton->workers, GINT_TO_POINTER(worker_id));
-
-    return 0;
+       int ret;
+       int event_fd = g_io_channel_unix_get_fd(src);
+       char *client_id = NULL;
+       pims_ipc_svc_s *ipc_svc = (pims_ipc_svc_s*)data;
+
+       if (G_IO_HUP & condition) {
+               INFO("client closed ------------------------client_fd : %d", event_fd);
+
+               close(event_fd);
+
+               // Find client_id
+               __find_client_id(ipc_svc, event_fd, true, &client_id);
+
+               // Send client_id to manager to terminate worker thread
+               if (client_id) {
+                       pthread_mutex_lock(&ipc_svc->manager_queue_from_epoll_mutex);
+                       ipc_svc->manager_queue_from_epoll = g_list_append(ipc_svc->manager_queue_from_epoll, (void*)g_strdup(client_id));
+                       pthread_mutex_unlock(&ipc_svc->manager_queue_from_epoll_mutex);
+                       write_command(ipc_svc->manager, 1);
+
+                       __delete_request_queue(ipc_svc, client_id);
+                       free(client_id);
+               }
+
+               return FALSE;
+       }
+
+       // receive data from client
+       int recv_len;
+       bool identity = false;
+       pims_ipc_raw_data_s *req = NULL;
+
+       recv_len = __recv_raw_data(event_fd, &req, &identity);
+       if (recv_len > 0) {
+               // send command to router
+               if (identity) {
+                       pims_ipc_client_map_s *client = (pims_ipc_client_map_s*)calloc(1, sizeof(pims_ipc_client_map_s));
+                       client->fd = event_fd;
+                       client->id = req->client_id;
+                       req->client_id = NULL;
+                       ipc_svc->client_id_fd_map = g_list_append(ipc_svc->client_id_fd_map, client);
+
+                       // send server pid to client
+                       char temp[100];
+                       snprintf(temp, sizeof(temp), "%x", getpid());
+                       ret = __send_identify(event_fd, req->seq_no, temp, strlen(temp));
+
+                       __free_raw_data(req);
+                       if (ret < 0)
+                               return FALSE;
+                       return TRUE;
+               }
+
+               __find_client_id(ipc_svc, event_fd, false, &client_id);
+
+               if (client_id) {
+                       __request_push(ipc_svc, client_id, event_fd, req);
+                       write_command(ipc_svc->router, 1);
+               }
+               else
+                       ERROR("__find_client_id fail : event_fd (%d)", event_fd);
+       }
+       else {
+               ERROR("receive invalid : %d", event_fd);
+               close(event_fd);
+               return FALSE;
+       }
+
+       return TRUE;
 }
 
-static int __process_monitor_event(void *context, void *monitor, void *manager)
+static gboolean __socket_handler(GIOChannel *src, GIOCondition condition, gpointer data)
 {
-    int worker_id = -1;
-    char *pid = NULL;
-    zmq_msg_t pid_msg;
-
-    VERBOSE("");
-    
-    // read pid
-    zmq_msg_init(&pid_msg);
-    if (_pims_zmq_msg_recv(&pid_msg, monitor, 0) == -1)
-    {
-        ERROR("recv error : %s", zmq_strerror(errno));
-        zmq_msg_close(&pid_msg);
-        return -1;
-    }
-
-    pid = (char*)zmq_msg_data(&pid_msg);
-    ASSERT(pid);
-    VERBOSE("client pid = %s", pid);
-
-    if (__find_worker(pid, &worker_id) != 0)
-        return 0;
-
-    VERBOSE("found worker id for %s = %x", pid, worker_id);
-    
-    __terminate_worker(manager, worker_id, pid);
-    __remove_worker(pid);
-
-    zmq_msg_close(&pid_msg);
-
-    return 0;
+       GIOChannel *channel;
+       pims_ipc_svc_s *ipc_svc = (pims_ipc_svc_s*)data;
+       int client_sockfd = -1;
+       int sockfd = ipc_svc->sockfd;
+       struct sockaddr_un clientaddr;
+       socklen_t client_len = sizeof(clientaddr);
+
+       client_sockfd = accept(sockfd, (struct sockaddr *)&clientaddr, &client_len);
+       if (-1 == client_sockfd) {
+               ERROR("accept error : %s", strerror(errno));
+               return TRUE;
+       }
+
+       channel = g_io_channel_unix_new(client_sockfd);
+       g_io_add_watch(channel, G_IO_IN|G_IO_HUP, __request_handler, data);
+       g_io_channel_unref(channel);
+
+       return TRUE;
 }
 
-static void __client_closed_cb(const char *pid, void *data)
+static void* __main_loop(void *user_data)
 {
-       pims_ipc_svc_t *ipc_svc = (pims_ipc_svc_t*)data;
-    
-    VERBOSE("client pid = %s", pid);
-
-    zmq_msg_t pid_msg;
-    zmq_msg_init_size(&pid_msg, strlen(pid) + 1);
-    memcpy(zmq_msg_data(&pid_msg), pid, strlen(pid) + 1);
-    if (_pims_zmq_msg_send(&pid_msg, ipc_svc->monitor, 0) == -1)
-        ERROR("send error : %s", zmq_strerror(errno));
-    zmq_msg_close(&pid_msg);
+       int ret;
+       struct sockaddr_un addr;
+       GIOChannel *gio = NULL;
+       pims_ipc_svc_s *ipc_svc = (pims_ipc_svc_s*)user_data;
+
+       if (sd_listen_fds(1) == 1 && sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_STREAM, -1, ipc_svc->service, 0) > 0) {
+                ipc_svc->sockfd = SD_LISTEN_FDS_START;
+       }
+       else {
+               unlink(ipc_svc->service);
+               ipc_svc->sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
+
+               bzero(&addr, sizeof(addr));
+               addr.sun_family = AF_UNIX;
+               snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", ipc_svc->service);
+
+               ret = bind(ipc_svc->sockfd, (struct sockaddr *)&addr, sizeof(addr));
+               if (ret != 0)
+                       ERROR("bind error :%d", ret);
+               ret = listen(ipc_svc->sockfd, 30);
+
+               ret = chown(ipc_svc->service, getuid(), ipc_svc->group);
+               ret = chmod(ipc_svc->service, ipc_svc->mode);
+       }
+
+       gio = g_io_channel_unix_new(ipc_svc->sockfd);
+
+       g_io_add_watch(gio, G_IO_IN, __socket_handler, (gpointer)ipc_svc);
+
+       return NULL;
 }
 
-static int __open_zmq_socket(void *context, pims_ipc_svc_t *ipc_svc)
+static int __open_router_fd(pims_ipc_svc_s *ipc_svc)
 {
-    char *path = NULL;
-    int ret = -1;
-    int i = 0;
-
-    void *router = zmq_socket(context, ZMQ_ROUTER);
-    if (!router)
-    {
-        ERROR("socket error : %s", zmq_strerror(errno));
-        return -1;
-    }
-    path = g_strdup_printf("ipc://%s", ipc_svc->service);
-    if (zmq_bind(router, path) != 0)
-    {
-        ERROR("bind error : %s", zmq_strerror(errno));
-        zmq_close(router);
-        return -1;
-    }
-    g_free(path);
-
-    ret = chown(ipc_svc->service, getuid(), ipc_svc->group);
-    ret = chmod(ipc_svc->service, ipc_svc->mode);
-
-    void *worker = zmq_socket(context, ZMQ_ROUTER);
-    if (!worker)
-    {
-        ERROR("socket error : %s", zmq_strerror(errno));
-        zmq_close(router);
-        return -1;
-    }
-    path = g_strdup_printf("inproc://%s-%s", ipc_svc->service, PIMS_IPC_DEALER_PATH);
-    if (zmq_bind(worker, path) != 0)
-    {
-        ERROR("bind error : %s", zmq_strerror(errno));
-        zmq_close(router);
-        zmq_close(worker);
-        return -1;
-    }
-    g_free(path);
-
-    void *manager = zmq_socket(context, ZMQ_ROUTER);
-    if (!manager)
-    {
-        ERROR("socket error : %s", zmq_strerror(errno));
-        zmq_close(router);
-        zmq_close(worker);
-        return -1;
-    }
-    path = g_strdup_printf("inproc://%s-%s", ipc_svc->service, PIMS_IPC_MANAGER_PATH);
-    if (zmq_bind(manager, path) != 0)
-    {
-        ERROR("bind error : %s", zmq_strerror(errno));
-        zmq_close(router);
-        zmq_close(worker);
-        zmq_close(manager);
-        return -1;
-    }
-    g_free(path);
-    
-    void *monitor = zmq_socket(context, ZMQ_PAIR);
-    if (!monitor)
-    {
-        ERROR("socket error : %s", zmq_strerror(errno));
-        zmq_close(router);
-        zmq_close(worker);
-        zmq_close(manager);
-        return -1;
-    }
-    path = g_strdup_printf("inproc://%s-%s", ipc_svc->service, PIMS_IPC_MONITOR2_PATH);
-    if (zmq_bind(monitor, path) != 0)
-    {
-        ERROR("bind error : %s", zmq_strerror(errno));
-        zmq_close(router);
-        zmq_close(worker);
-        zmq_close(manager);
-        zmq_close(monitor);
-        return -1;
-    }
-    g_free(path);
-
-    ipc_svc->context = context;
-    ipc_svc->router = router;
-    ipc_svc->worker = worker;
-    ipc_svc->manager = manager;
-    ipc_svc->monitor = monitor;
-
-    path = g_strdup_printf("%s-%s", ipc_svc->service, PIMS_IPC_MONITOR_PATH);
-    ret = _server_socket_init(path, ipc_svc->group, ipc_svc->mode, __client_closed_cb, ipc_svc);
-    ASSERT(ret != -1);
-    g_free(path);
-
-    // launch worker threads in advance
-    for (i = 0; i < ipc_svc->workers_max_count; i++)
-        __launch_worker(__worker_loop, context);
-
-    return 0;
+       int ret = -1;
+       int flags;
+       int router;
+       int manager;
+
+       // router inproc eventfd
+       router = eventfd(0,0);
+       if (-1 == router) {
+               ERROR("eventfd error : %d", errno);
+               return -1;
+       }
+       VERBOSE("router :%d\n", router);
+
+       flags = fcntl(router, F_GETFL, 0);
+       if (flags == -1)
+               flags = 0;
+       ret = fcntl (router, F_SETFL, flags | O_NONBLOCK);
+       VERBOSE("rounter fcntl : %d\n", ret);
+
+       // manager inproc eventfd
+       manager = eventfd(0,0);
+       if (-1 == manager) {
+               ERROR("eventfd error : %d", errno);
+               close(router);
+               return -1;
+       }
+       VERBOSE("manager :%d\n", manager);
+
+       flags = fcntl(manager, F_GETFL, 0);
+       if (flags == -1)
+               flags = 0;
+       ret = fcntl (manager, F_SETFL, flags | O_NONBLOCK);
+       VERBOSE("manager fcntl : %d\n", ret);
+
+       ipc_svc->router = router;
+       ipc_svc->manager = manager;
+
+       return 0;
 }
 
-static void __close_zmq_socket(pims_ipc_svc_t *ipc_svc)
+static void __close_router_fd(pims_ipc_svc_s *ipc_svc)
 {
-    zmq_close(ipc_svc->router);
-    zmq_close(ipc_svc->worker);
-    zmq_close(ipc_svc->manager);
-    zmq_close(ipc_svc->monitor);
+       close(ipc_svc->router);
+       close(ipc_svc->manager);
 }
 
-static int __open_zmq_socket_for_publish(void *context, pims_ipc_svc_for_publish_t *ipc_svc)
+static void* __publish_loop(void *user_data)
 {
-    char *path = NULL;
-    int ret = -1;
-
-    ipc_svc->context = context;
-    void *publisher = NULL;
-    publisher = zmq_socket(context, ZMQ_PUB);
-    if (!publisher)
-    {
-        ERROR("socket error : %s", zmq_strerror(errno));
-        return -1;
-    }
-
-    path = g_strdup_printf("ipc://%s", ipc_svc->service);
-    if (zmq_bind(publisher, path) != 0)
-    {
-        ERROR("bind error : %s", zmq_strerror(errno));
-        zmq_close(publisher);
-        return -1;
-    }
-    g_free(path);
-
-    ret = chown(ipc_svc->service, getuid(), ipc_svc->group);
-    ret = chmod(ipc_svc->service, ipc_svc->mode);
-
-    ipc_svc->context = context;
-    ipc_svc->publisher = publisher;
-
-    return 0;
+       int ret;
+       int epfd;
+
+       struct sockaddr_un addr;
+       struct epoll_event ev = {0};
+       pims_ipc_svc_for_publish_s *ipc_svc = (pims_ipc_svc_for_publish_s*)user_data;
+
+       unlink(ipc_svc->service);
+       ipc_svc->publish_sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
+
+       bzero(&addr, sizeof(struct sockaddr_un));
+       addr.sun_family = AF_UNIX;
+       snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", ipc_svc->service);
+
+       int flags = fcntl (ipc_svc->publish_sockfd, F_GETFL, 0);
+       if (flags == -1)
+               flags = 0;
+       ret = fcntl (ipc_svc->publish_sockfd, F_SETFL, flags | O_NONBLOCK);
+       VERBOSE("publish socketfd fcntl : %d\n", ret);
+
+       ret = bind(ipc_svc->publish_sockfd, (struct sockaddr *)&(addr), sizeof(struct sockaddr_un));
+       if (ret != 0)
+               ERROR("bind error :%d", ret);
+       ret = listen(ipc_svc->publish_sockfd, 30);
+       WARN_IF(ret != 0, "listen error :%d", ret);
+
+       ret = chown(ipc_svc->service, getuid(), ipc_svc->group);
+       WARN_IF(ret != 0, "listen error :%d", ret);
+       ret = chmod(ipc_svc->service, ipc_svc->mode);
+       WARN_IF(ret != 0, "listen error :%d", ret);
+
+       epfd = epoll_create(MAX_EPOLL_EVENT);
+
+       ev.events = EPOLLIN | EPOLLHUP;
+       ev.data.fd = ipc_svc->publish_sockfd;
+
+       ret = epoll_ctl(epfd, EPOLL_CTL_ADD, ipc_svc->publish_sockfd, &ev);
+       WARN_IF(ret != 0, "listen error :%d", ret);
+
+       while (!ipc_svc->epoll_stop_thread) {
+               int i = 0;
+               struct epoll_event events[MAX_EPOLL_EVENT] = {{0}, };
+               int event_num = epoll_wait(epfd, events, MAX_EPOLL_EVENT, -1);
+
+               if (ipc_svc->epoll_stop_thread)
+                       break;
+
+               if (event_num == -1) {
+                       if (errno != EINTR) {
+                               ERROR("errno:%d\n", errno);
+                               break;
+                       }
+               }
+
+               for (i = 0; i < event_num; i++) {
+                       int event_fd = events[i].data.fd;
+
+                       if (events[i].events & EPOLLHUP) {
+                               VERBOSE("client closed -----------------------------------------:%d", event_fd);
+                               if (epoll_ctl(epfd, EPOLL_CTL_DEL, event_fd, events) == -1) {
+                                       ERROR("epoll_ctl (EPOLL_CTL_DEL) fail : errno(%d)", errno);
+                               }
+                               close(event_fd);
+
+                               // Find client_id and delete
+                               GList *cursor = NULL;
+
+                               pthread_mutex_lock(&ipc_svc->subscribe_fds_mutex);
+                               cursor = g_list_first(ipc_svc->subscribe_fds);
+                               while (cursor) {
+                                       if (event_fd == (int)cursor->data) {
+                                               ipc_svc->subscribe_fds = g_list_delete_link(ipc_svc->subscribe_fds, cursor);
+                                               break;
+                                       }
+                                       cursor = g_list_next(cursor);
+                               }
+                               pthread_mutex_unlock(&ipc_svc->subscribe_fds_mutex);
+                               continue;
+                       }
+                       else if (event_fd == ipc_svc->publish_sockfd) {         // connect client
+                               struct sockaddr_un remote;
+                               int remote_len = sizeof(remote);
+                               int client_fd = accept(ipc_svc->publish_sockfd, (struct sockaddr *)&remote, (socklen_t*) &remote_len);
+                               if (client_fd == -1) {
+                                       ERROR("accept fail : errno : %d", errno);
+                                       continue;
+                               }
+                               VERBOSE("client subscriber connect: %d", client_fd);
+
+                               pthread_mutex_lock(&ipc_svc->subscribe_fds_mutex);
+                               ipc_svc->subscribe_fds = g_list_append(ipc_svc->subscribe_fds, (void*)client_fd);
+                               pthread_mutex_unlock(&ipc_svc->subscribe_fds_mutex);
+
+                               ev.events = EPOLLIN;
+                               ev.data.fd = client_fd;
+                               if (epoll_ctl(epfd, EPOLL_CTL_ADD, client_fd, &ev) == -1) {
+                                       ERROR("epoll_ctl (EPOLL_CTL_ADD) fail : error(%d)\n", errno);
+                                       continue;
+                               }
+                       }
+               }
+       }
+
+       close(ipc_svc->publish_sockfd);
+       close(epfd);
+
+       return NULL;
 }
 
-static void __close_zmq_socket_for_publish(pims_ipc_svc_for_publish_t *ipc_svc)
+static void __stop_for_publish(pims_ipc_svc_for_publish_s *ipc_svc)
 {
-    zmq_close(ipc_svc->publisher);
+       ipc_svc->epoll_stop_thread = true;
 }
 
-static void* __main_loop(void *args)
+static void* __router_loop(void *data)
 {
-    char *path = NULL;
-    int ret = -1;
-       pims_ipc_svc_t *ipc_svc = (pims_ipc_svc_t*)args;
-
-    void *monitor_peer = zmq_socket(ipc_svc->context, ZMQ_PAIR);
-    ASSERT(monitor_peer);
-    
-    path = g_strdup_printf("inproc://%s-%s", ipc_svc->service, PIMS_IPC_MONITOR2_PATH);
-    ret = zmq_connect(monitor_peer, path);
-    ASSERT(ret == 0);
-    g_free(path);
-
-    // poll all sockets
-    while (1)
-    {
-        zmq_pollitem_t items[] = {
-            {ipc_svc->router, 0, ZMQ_POLLIN, 0},
-            {ipc_svc->worker, 0, ZMQ_POLLIN, 0},
-            {ipc_svc->manager, 0, ZMQ_POLLIN, 0},
-            {monitor_peer, 0, ZMQ_POLLIN, 0}
-        };
-
-        if (zmq_poll(items, 4, -1) == -1)
-        {
-            if (errno == EINTR)
-                continue;
-
-            ERROR("poll error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        if (items[0].revents & ZMQ_POLLIN)
-        {
-            __process_router_event(ipc_svc->context, ipc_svc->router, ipc_svc->worker, FALSE);
-        }
-
-        if (items[1].revents & ZMQ_POLLIN)
-        {
-            __process_worker_event(ipc_svc->context, ipc_svc->worker, ipc_svc->router);
-        }
-
-        if (items[2].revents & ZMQ_POLLIN)
-        {
-            __process_manager_event(ipc_svc->context, ipc_svc->manager);
-            if (ipc_svc->requests)
-                __process_router_event(ipc_svc->context, ipc_svc->router, ipc_svc->worker, TRUE);
-        }
-
-        if (items[3].revents & ZMQ_POLLIN)
-        {
-            __process_monitor_event(ipc_svc->context, monitor_peer, ipc_svc->manager);
-        }
-    }
-    
-    zmq_close(monitor_peer);
-
-    return NULL;
+       pims_ipc_svc_s *ipc_svc = (pims_ipc_svc_s*)data;
+       int fd_count = 2;
+       struct pollfd *pollfds;
+
+       pollfds = (struct pollfd*) malloc (fd_count * sizeof (struct pollfd));
+
+       pollfds[0].fd = ipc_svc->router;
+       pollfds[0].events = POLLIN;
+       pollfds[1].fd = ipc_svc->manager;
+       pollfds[1].events = POLLIN;
+
+       while (1) {
+               int ret = -1;
+               uint64_t dummy;
+               int check_router_queue = -1;
+               int check_manager_queue = -1;
+
+               while (1) {
+                       ret = poll(pollfds, fd_count, 1000);
+                       if (ret == -1 && errno == EINTR) {
+                               //free (pollfds);
+                               continue;               //return NULL;
+                       }
+                       break;
+               }
+
+               if (ret > 0) {
+                       if (pollfds[0].revents & POLLIN) {
+                               // request router: send request to worker
+                               if (sizeof (dummy) == read_command(pollfds[0].fd, &dummy)) {
+                                       check_router_queue = __process_router_event(ipc_svc, false);
+                               }
+                       }
+
+                       if (pollfds[1].revents & POLLIN) {
+                               // worker manager
+                               if (sizeof (dummy) == read_command(pollfds[1].fd, &dummy)) {
+                                       check_manager_queue = __process_manager_event(ipc_svc);
+                                       if (ipc_svc->delay_count > 0)
+                                               check_router_queue = __process_router_event(ipc_svc, true);
+                               }
+                       }
+               }
+
+               // check queue
+               while(check_router_queue > 0 || check_manager_queue > 0) {
+                       read_command(pollfds[0].fd, &dummy);
+                       check_router_queue = __process_router_event(ipc_svc, false);
+
+                       read_command(pollfds[1].fd, &dummy);
+                       check_manager_queue = __process_manager_event(ipc_svc);
+                       if (ipc_svc->delay_count > 0)
+                               check_router_queue = __process_router_event(ipc_svc, true);
+               }
+       }
+
+       free(pollfds);
+
+       return NULL;
 }
 
 API void pims_ipc_svc_run_main_loop(GMainLoop* loop)
 {
-    int retval = -1;
-    GMainLoop* main_loop = loop;
+       int ret = -1;
+       GMainLoop* main_loop = loop;
 
-    if(main_loop == NULL) {
-        main_loop = g_main_loop_new(NULL, FALSE);
-    }
+       if (main_loop == NULL) {
+               main_loop = g_main_loop_new(NULL, FALSE);
+       }
 
-    void *context = zmq_init(1);
-    ASSERT (context != NULL);
+       if (_g_singleton_for_publish)
+               __launch_thread(__publish_loop, _g_singleton_for_publish);
 
-    if (_g_singleton_for_publish)
-    {
-        retval = __open_zmq_socket_for_publish(context, _g_singleton_for_publish);
-        ASSERT(retval == 0);
-    }
+       if (_g_singleton) {
+               ret = __open_router_fd(_g_singleton);
+               ASSERT(ret == 0);
 
-    if (_g_singleton)
-    {
-        retval = __open_zmq_socket(context, _g_singleton);
-        ASSERT(retval == 0);
-    }
+               int i;
+               // launch worker threads in advance
+               for (i = 0; i < _g_singleton->workers_max_count; i++)
+                       __launch_thread(__worker_loop, _g_singleton);
 
-    __launch_worker(__main_loop, _g_singleton);
+               __launch_thread(__router_loop, _g_singleton);
+               __main_loop(_g_singleton);
+       }
 
-    g_main_loop_run(main_loop);
+       g_main_loop_run(main_loop);
 
-    if (_g_singleton)
-    {
-        __close_zmq_socket(_g_singleton);
-    }
+       if (_g_singleton)
+               __close_router_fd(_g_singleton);
 
-    if (_g_singleton_for_publish)
-    {
-        __close_zmq_socket_for_publish(_g_singleton_for_publish);
-    }
+       if (_g_singleton_for_publish)
+               __stop_for_publish(_g_singleton_for_publish);
 
-    if (zmq_term(context) == -1)
-        WARNING("term error : %s", zmq_strerror(errno));
 }
+
+API void pims_ipc_svc_set_client_disconnected_cb(pims_ipc_svc_client_disconnected_cb callback, void *user_data)
+{
+       if (_client_disconnected_cb.callback) {
+               ERROR("already registered");
+               return;
+       }
+       _client_disconnected_cb.callback = callback;
+       _client_disconnected_cb.user_data = user_data;
+}
+
+
index 301a52f..3529476 100644 (file)
 #include <time.h>
 #include <glib.h>
 #include <stdint.h>
-#include <sys/types.h>
 #include <pthread.h>
-
-#include <pims-internal.h>
-#include <pims-socket.h>
-#include <pims-debug.h>
-#include <pims-ipc-data.h>
-#include <pims-ipc.h>
+#include <poll.h>                      // pollfds
+#include <sys/un.h>            // sockaddr_un
+#include <sys/ioctl.h>         // ioctl
+#include <sys/socket.h>                //socket
+#include <sys/types.h>
+#include <sys/epoll.h>         // epoll
+#include <sys/eventfd.h>       // eventfd
+#include <fcntl.h>
+#include <errno.h>
+
+#include "pims-internal.h"
+#include "pims-socket.h"
+#include "pims-debug.h"
+#include "pims-ipc-data.h"
+#include "pims-ipc-data-internal.h"
+#include "pims-ipc.h"
 
 #define GET_CALL_SEQUNECE_NO(handle, sequence_no) do {\
-    sequence_no = ++((handle)->call_sequence_no);\
+       sequence_no = ++((handle)->call_sequence_no);\
 } while (0)
 
 static pthread_mutex_t __gmutex = PTHREAD_MUTEX_INITIALIZER;
 
 typedef enum
 {
-    PIMS_IPC_CALL_STATUS_READY = 0,
-    PIMS_IPC_CALL_STATUS_IN_PROGRESS
+       PIMS_IPC_CALL_STATUS_READY = 0,
+       PIMS_IPC_CALL_STATUS_IN_PROGRESS
 } pims_ipc_call_status_e;
 
 typedef enum
 {
-    PIMS_IPC_MODE_REQ = 0,
-    PIMS_IPC_MODE_SUB
+       PIMS_IPC_MODE_REQ = 0,
+       PIMS_IPC_MODE_SUB
 } pims_ipc_mode_e;
 
 typedef struct
 {
-    pid_t pid;
-    void *context;
-    unsigned int ref_cnt;
-    unsigned int id_sequence_no;
-    GList *subscribe_handles;
-} pims_ipc_context_t;
-
-static pims_ipc_context_t *_g_singleton = NULL;
+       pims_ipc_subscribe_cb callback;
+       void * user_data;
+} pims_ipc_cb_s;
 
 typedef struct
 {
-    pims_ipc_subscribe_cb callback;
-    void * user_data;
-} pims_ipc_cb_t;
+       char *call_id;
+       pims_ipc_data_h *handle;
+}pims_ipc_subscribe_data_s;
 
 typedef struct
 {
-    int fd;
-    void *requester;
-    char *service;
-    char *id;
-    GIOChannel *async_channel;
-    guint async_source_id;
-    pims_ipc_call_status_e call_status;
-    unsigned int call_sequence_no;
-    pims_ipc_call_async_cb call_async_callback;
-    void *call_async_userdata;
-    GHashTable *subscribe_cb_table;
-} pims_ipc_t;
-
-#define PIMS_IPC_SOCKET_BUFFER_SIZE     256
-static inline int __pims_zmq_msg_recv_by_handle(zmq_msg_t *msg, pims_ipc_t *handle, int flags)
+       int fd;
+       char *service;
+       char *id;
+       GIOChannel *async_channel;
+       guint async_source_id;
+       pthread_mutex_t call_status_mutex;
+       pims_ipc_call_status_e call_status;
+       unsigned int call_sequence_no;
+       pims_ipc_call_async_cb call_async_callback;
+       void *call_async_userdata;
+       pims_ipc_data_h dhandle_for_async_idler;
+
+       int subscribe_fd;
+       int epoll_stop_thread;
+       pthread_t io_thread;
+       GHashTable *subscribe_cb_table;
+
+       pthread_mutex_t data_queue_mutex;
+       GList *data_queue;
+} pims_ipc_s;
+
+static unsigned int ref_cnt;
+static GList *subscribe_handles;
+
+static void __sub_data_free(gpointer user_data)
 {
-    int ret = -1;
-
-    while (1)
-    {
-        zmq_pollitem_t items[] = {
-            {handle->requester, 0, ZMQ_POLLIN, 0},
-            {NULL, handle->fd, ZMQ_POLLIN, 0}
-        };
-
-        if (zmq_poll(items, 2, -1) == -1)
-        {
-            if (errno == EINTR)
-                continue;
-            
-            ERROR("poll error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        if (items[0].revents & ZMQ_POLLIN)
-        {
-            ret = zmq_msg_recv(msg, handle->requester, flags);
-            if (ret == -1 && errno == EINTR)
-                continue;
-            break;
-        }
-
-        if (items[1].revents & ZMQ_POLLIN)
-        {
-            char buffer[PIMS_IPC_SOCKET_BUFFER_SIZE] = "";
-           
-            memset(buffer, 0x00, PIMS_IPC_SOCKET_BUFFER_SIZE);
-            ret = read(handle->fd, (char *)buffer, PIMS_IPC_SOCKET_BUFFER_SIZE-1);
-            ASSERT(ret <= 0);
-            
-            close(handle->fd);
-            handle->fd = -1;
-
-            if (handle->requester)
-                zmq_close(handle->requester);
-            handle->requester = NULL;
-
-            errno = ETERM;
-            ret = -1;
-            break;
-        }
-    }
-
-    return ret;
+       pims_ipc_subscribe_data_s *data = (pims_ipc_subscribe_data_s*)user_data;
+       pims_ipc_data_destroy(data->handle);
+       free(data->call_id);
+       free(data);
 }
 
-static void __pims_ipc_free_handle(pims_ipc_t *handle)
+static void __pims_ipc_free_handle(pims_ipc_s *handle)
 {
-    pthread_mutex_lock(&__gmutex);
-
-    g_free(handle->id);
-    g_free(handle->service);
-
-    if (handle->requester)
-        zmq_close(handle->requester);
-
-    if (handle->fd != -1)
-        close(handle->fd);
-    
-    if (handle->async_channel)
-    {
-        // remove a subscriber handle from the golbal list
-        if (_g_singleton)
-        {
-            _g_singleton->subscribe_handles = g_list_remove(_g_singleton->subscribe_handles, handle);
-            VERBOSE("the count of subscribe handles = %d", g_list_length(_g_singleton->subscribe_handles));
-        }
-
-        g_source_remove(handle->async_source_id);
-        g_io_channel_unref(handle->async_channel);
-    }
-
-    if (handle->subscribe_cb_table)
-        g_hash_table_destroy(handle->subscribe_cb_table);
-
-    g_free(handle);
-
-    if (_g_singleton && --_g_singleton->ref_cnt <= 0)
-    {
-        if (zmq_term(_g_singleton->context) == -1)
-        {
-            WARNING("term error : %s", zmq_strerror(errno));
-        }
-        g_free(_g_singleton);
-        _g_singleton = NULL;
-    }
-    
-    pthread_mutex_unlock(&__gmutex);
+       pthread_mutex_lock(&__gmutex);
+
+       handle->epoll_stop_thread = true;
+
+       if (handle->fd != -1)
+               close(handle->fd);
+
+       if (handle->io_thread)
+               pthread_join(handle->io_thread, NULL);
+
+       g_free(handle->id);
+       g_free(handle->service);
+
+       if (handle->async_channel) {
+               // remove a subscriber handle from the golbal list
+               subscribe_handles = g_list_remove(subscribe_handles, handle);
+               VERBOSE("the count of subscribe handles = %d", g_list_length(subscribe_handles));
+
+               g_source_remove(handle->async_source_id);
+               g_io_channel_unref(handle->async_channel);
+       }
+
+       if (handle->subscribe_cb_table)
+               g_hash_table_destroy(handle->subscribe_cb_table);
+
+       pthread_mutex_lock(&handle->data_queue_mutex);
+       if (handle->data_queue) {
+               g_list_free_full(handle->data_queue, __sub_data_free);
+       }
+       pthread_mutex_unlock(&handle->data_queue_mutex);
+       pthread_mutex_destroy(&handle->data_queue_mutex);
+
+       if (handle->subscribe_fd != -1)
+               close(handle->subscribe_fd);
+
+       pthread_mutex_destroy(&handle->call_status_mutex);
+
+       g_free(handle);
+
+       if (--ref_cnt <= 0) {
+               if (subscribe_handles)
+                       g_list_free(subscribe_handles);
+               subscribe_handles = NULL;
+       }
+
+       pthread_mutex_unlock(&__gmutex);
 }
 
-static int __pims_ipc_receive_for_subscribe(pims_ipc_t *handle)
+static int __pims_ipc_receive_for_subscribe(pims_ipc_s *handle)
 {
-    gboolean is_valid = FALSE;
-    int64_t more = 0;
-    pims_ipc_data_h dhandle = NULL;
-    pims_ipc_cb_t *cb_data = NULL;
-   
-    zmq_msg_t call_id_msg;
-    zmq_msg_t data_msg;
-
-    zmq_msg_init(&call_id_msg);
-    zmq_msg_init(&data_msg);
-
-    do {
-        // recv call id 
-        if (__pims_zmq_msg_recv_by_handle(&call_id_msg, handle, 0) == -1)
-        {
-            ERROR("recv error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        // find a callback by a call id
-        cb_data = (pims_ipc_cb_t*)g_hash_table_lookup(handle->subscribe_cb_table, zmq_msg_data(&call_id_msg));
-
-        size_t more_size = sizeof(more);
-        zmq_getsockopt(handle->requester, ZMQ_RCVMORE, &more, &more_size);
-        if (more)
-        {
-            if (__pims_zmq_msg_recv_by_handle(&data_msg, handle, 0) == -1)
-            {
-                ERROR("recv error : %s", zmq_strerror(errno));
-                break;
-            } 
-            
-            if (cb_data == NULL)
-            {
-                VERBOSE("unable to find %s", (char*)zmq_msg_data(&call_id_msg));
-                is_valid = TRUE;
-                break;
-            }
-
-            dhandle = pims_ipc_data_unmarshal_with_zmq(&data_msg);
-            if (dhandle == NULL)
-            {
-                ERROR("unmarshal error");
-                break;
-            }
-
-            cb_data->callback((pims_ipc_h)handle, dhandle, cb_data->user_data);
-        }
-
-        is_valid = TRUE;
-    } while (0);
-
-    zmq_msg_close(&call_id_msg);
-    zmq_msg_close(&data_msg);
-    if (dhandle)
-        pims_ipc_data_destroy(dhandle);
-
-    if (is_valid == FALSE)
-        return -1;
-    return 0;
+       pims_ipc_cb_s *cb_data = NULL;
+       uint64_t dummy;
+
+       do {
+               read_command(handle->subscribe_fd, &dummy);
+
+               pthread_mutex_lock(&handle->data_queue_mutex);
+               if (!handle->data_queue) {
+                       pthread_mutex_unlock(&handle->data_queue_mutex);
+                       break;
+               }
+
+               GList *cursor = g_list_first(handle->data_queue);
+               pims_ipc_subscribe_data_s *data = (pims_ipc_subscribe_data_s *)cursor->data;
+               if (data == NULL) {
+                       pthread_mutex_unlock(&handle->data_queue_mutex);
+                       break;
+               }
+
+               cb_data = (pims_ipc_cb_s*)g_hash_table_lookup(handle->subscribe_cb_table, data->call_id);
+               if (cb_data == NULL) {
+                       VERBOSE("unable to find %s", call_id);
+               }
+               else
+                       cb_data->callback((pims_ipc_h)handle, data->handle, cb_data->user_data);
+
+               handle->data_queue = g_list_delete_link(handle->data_queue, cursor);
+               __sub_data_free(data);
+               pthread_mutex_unlock(&handle->data_queue_mutex);
+       } while(1);
+
+       return 0;
 }
 
 static gboolean __pims_ipc_subscribe_handler(GIOChannel *src, GIOCondition condition, gpointer data)
 {
-    pims_ipc_t *handle = (pims_ipc_t *)data;
-    uint32_t zmq_events = 0;
-    size_t opt_len = 0;
-    int rc = 0;
-
-    VERBOSE("");
-
-    pthread_mutex_lock(&__gmutex);
-
-    // check if a subscriber handle is exists
-    if (_g_singleton == NULL || g_list_find(_g_singleton->subscribe_handles, handle) == NULL)
-    {
-        DEBUG("No such handle that ID is %p", handle);
-        pthread_mutex_unlock(&__gmutex);
-        return FALSE;
-    }
-    
-    opt_len = sizeof(uint32_t);
-    while (1)
-    {
-        rc = zmq_getsockopt(handle->requester, ZMQ_EVENTS, &zmq_events, &opt_len);
-        ASSERT(rc == 0);
-        if (ZMQ_POLLIN & zmq_events) {
-            __pims_ipc_receive_for_subscribe(handle);
-        }
-        else
-        {
-            break;
-        }
-    }
-
-    pthread_mutex_unlock(&__gmutex);
-
-    return TRUE;
+       pims_ipc_s *handle = (pims_ipc_s *)data;
+
+       VERBOSE("");
+
+       if (condition & G_IO_HUP)
+               return FALSE;
+
+       pthread_mutex_lock(&__gmutex);
+
+       // check if a subscriber handle is exists
+       if (g_list_find(subscribe_handles, handle) == NULL) {
+               ERROR("No such handle that ID is %p", handle);
+               pthread_mutex_unlock(&__gmutex);
+               return FALSE;
+       }
+
+       __pims_ipc_receive_for_subscribe(handle);
+
+       pthread_mutex_unlock(&__gmutex);
+
+       return TRUE;
+}
+
+static unsigned int __get_global_sequence_no()
+{
+       static unsigned int __gsequence_no = 0xffffffff;
+
+       if (__gsequence_no == 0xffffffff)
+               __gsequence_no = (unsigned int)time(NULL);
+       else
+               __gsequence_no++;
+       return __gsequence_no;
+}
+
+static int __pims_ipc_send_identify(pims_ipc_s *handle)
+{
+       unsigned int sequence_no;
+       unsigned int client_id_len = strlen(handle->id);
+       unsigned int len = sizeof(unsigned int)         // total size
+               + client_id_len + sizeof(unsigned int)          // client_id
+               + sizeof(unsigned int)  ;       // seq_no
+
+       char buf[len+1];
+       int length = 0;
+       memset(buf, 0x0, len+1);
+
+       // total len
+       memcpy(buf, (void*)&len, sizeof(unsigned int));
+       length += sizeof(unsigned int);
+
+       // client_id
+       memcpy(buf+length, (void*)&(client_id_len), sizeof(unsigned int));
+       length += sizeof(unsigned int);
+       memcpy(buf+length, (void*)(handle->id), client_id_len);
+       length += client_id_len;
+
+       // seq_no
+       GET_CALL_SEQUNECE_NO(handle, sequence_no);
+       memcpy(buf+length, (void*)&(sequence_no), sizeof(unsigned int));
+       length += sizeof(unsigned int);
+
+       return socket_send(handle->fd, buf, length);
+}
+
+static int __pims_ipc_read_data(pims_ipc_s *handle, pims_ipc_data_h *data_out)
+{
+       int ret;
+       gboolean is_ok = FALSE;
+       int len = 0;
+       pims_ipc_data_h data = NULL;
+       unsigned int sequence_no = 0;
+       char *client_id = NULL;
+       char *call_id = NULL;
+       char *buf = NULL;
+
+       /* read the size of message. note that ioctl is non-blocking */
+       if (ioctl(handle->fd, FIONREAD, &len)) {
+               ERROR("ioctl failed: %d", errno);
+               return -1;
+       }
+
+       /* when server or client closed socket */
+       if (len == 0) {
+               ERROR("[IPC Socket] connection is closed");
+               return -1;
+       }
+
+       do {
+               unsigned int read_len = 0;
+               unsigned int total_len = 0;
+               unsigned int client_id_len = 0;
+               unsigned int call_id_len = 0;
+               unsigned int is_data = FALSE;
+
+               // get total_len
+               read_len = read(handle->fd, (void *)&total_len, sizeof(unsigned int));
+
+               // client_id
+               read_len += read(handle->fd, (void *)&(client_id_len), sizeof(unsigned int));
+               if (client_id_len > 0 && client_id_len < UINT_MAX-1) {
+                       client_id = calloc(1, client_id_len+1);
+                       if (client_id == NULL) {
+                               ERROR("calloc fail");
+                               break;
+                       }
+               }
+               else
+                       break;
+               ret = socket_recv(handle->fd, (void *)&(client_id), client_id_len);
+               if (ret < 0) {  ERROR("socket_recv error"); break;      }
+               read_len += ret;
+
+               // sequence no
+               read_len += read(handle->fd, (void *)&(sequence_no), sizeof(unsigned int));
+               if (total_len == read_len) {
+                       // send identity
+                       data = pims_ipc_data_create(0);
+                       ret = pims_ipc_data_put(data, client_id, client_id_len);
+                       if (ret != 0)
+                               WARNING("pims_ipc_data_put fail(%d)", ret);
+                       break;
+               }
+
+               read_len += read(handle->fd, (void *)&(call_id_len), sizeof(unsigned int));
+               if (call_id_len > 0 && call_id_len < UINT_MAX-1) {
+                       call_id = calloc(1, call_id_len+1);
+                       if (call_id == NULL) {
+                               ERROR("calloc fail");
+                               break;
+                       }
+               }
+               else
+                       break;
+
+               ret = socket_recv(handle->fd, (void *)&(call_id), call_id_len);
+               if (ret < 0) {  ERROR("socket_recv error"); break;      }
+               read_len += ret;
+
+               read_len += read(handle->fd, (void *)&(is_data), sizeof(unsigned int));
+               if (is_data) {
+                       unsigned int data_len;
+                       read_len += read(handle->fd, (void *)&(data_len), sizeof(unsigned int));
+                       if (data_len > 0 && data_len < UINT_MAX-1) {
+                               buf = calloc(1, data_len+1);
+                               if (buf == NULL) {
+                                       ERROR("calloc fail");
+                                       break;
+                               }
+                       }
+                       else
+                               break;
+                       ret = socket_recv(handle->fd, (void *)&(buf), data_len);
+                       if (ret < 0) {  ERROR("socket_recv error"); break;      }
+                       read_len += ret;
+
+                       data = pims_ipc_data_steal_unmarshal(buf, data_len);
+                       buf = NULL;
+               }
+
+               INFO("client_id :%s, call_id : %s, seq_no : %d", client_id, call_id, sequence_no);
+       } while(0);
+       free(client_id);
+       free(call_id);
+       free(buf);
+
+       if (sequence_no == handle->call_sequence_no) {
+               if (data_out != NULL) {
+                       *data_out = data;
+               }
+               else if (data)
+                       pims_ipc_data_destroy(data);
+               is_ok = TRUE;
+       }
+       else {
+               if (data)
+                       pims_ipc_data_destroy(data);
+               VERBOSE("received an mismatched response (%x:%x)", handle->call_sequence_no, sequence_no);
+       }
+
+       if (is_ok)
+               return 0;
+
+       return -1;
+}
+
+static int __pims_ipc_receive(pims_ipc_s *handle, pims_ipc_data_h *data_out)
+{
+       int ret = -1;
+       struct pollfd *pollfds = (struct pollfd*) malloc (1 * sizeof (struct pollfd));
+
+       pollfds[0].fd = handle->fd;
+       pollfds[0].events = POLLIN | POLLERR | POLLHUP;
+
+       while(1) {
+               while(1) {
+                       ret = poll(pollfds, 1, 1000);
+                       if (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
+                               continue;
+                       }
+                       break;
+               }
+
+               if (ret > 0) {
+                       if (pollfds[0].revents & (POLLERR|POLLHUP)) {
+                               ERROR("Server disconnected");
+                               ret = -1;
+                               break;
+                       }
+                       if (pollfds[0].revents & POLLIN) {
+                               ret = __pims_ipc_read_data(handle, data_out);
+                               break;
+                       }
+               }
+       }
+       free (pollfds);
+       return ret;
+}
+
+static int __open_subscribe_fd(pims_ipc_s *handle)
+{
+       // router inproc eventfd
+       int subscribe_fd = eventfd(0,0);
+       int flags;
+       int ret;
+
+       if (-1 == subscribe_fd) {
+               ERROR("eventfd error : %d", errno);
+               return -1;
+       }
+       VERBOSE("subscribe :%d\n", subscribe_fd);
+
+       flags = fcntl (subscribe_fd, F_GETFL, 0);
+       if (flags == -1)
+               flags = 0;
+       ret = fcntl (subscribe_fd, F_SETFL, flags | O_NONBLOCK);
+       VERBOSE("subscribe fcntl : %d\n", ret);
+
+       handle->subscribe_fd = subscribe_fd;
+       return 0;
+}
+
+static int __subscribe_data(pims_ipc_s * handle)
+{
+       int len;
+       int ret = -1;
+       char *call_id = NULL;
+       char *buf = NULL;
+       pims_ipc_data_h dhandle = NULL;
+
+       do {
+               /* read the size of message. note that ioctl is non-blocking */
+               if (ioctl(handle->fd, FIONREAD, &len)) {
+                       ERROR("ioctl failed: %d", errno);
+                       break;
+               }
+
+               /* when server or client closed socket */
+               if (len == 0) {
+                       INFO("[IPC Socket] connection is closed");
+                       break;
+               }
+
+               unsigned int read_len = 0;
+               unsigned int total_len = 0;
+               unsigned int call_id_len = 0;
+               unsigned int is_data = FALSE;
+
+               // get total_len
+               read_len = read(handle->fd, (void *)&total_len, sizeof(unsigned int));
+
+               // call_id
+               read_len += read(handle->fd, (void *)&(call_id_len), sizeof(unsigned int));
+               if (call_id_len > 0 && call_id_len < UINT_MAX-1) {
+                       call_id = calloc(1, call_id_len+1);
+                       if (call_id == NULL) {
+                               ERROR("calloc fail");
+                               break;
+                       }
+               }
+               else
+                       break;
+
+               ret = socket_recv(handle->fd, (void *)&(call_id), call_id_len);
+               if (ret < 0) {  ERROR("socket_recv error"); break; }
+               read_len += ret;
+
+               // is_data
+               read_len += read(handle->fd, (void *)&(is_data), sizeof(unsigned int));
+
+               if (is_data) {
+                       unsigned int data_len;
+                       read_len += read(handle->fd, (void *)&(data_len), sizeof(unsigned int));
+                       if (data_len > 0 && data_len < UINT_MAX-1) {
+                               buf = calloc(1, data_len+1);
+                               if (buf == NULL) {
+                                       ERROR("calloc fail");
+                                       break;
+                               }
+                       }
+                       else
+                               break;
+                       ret = socket_recv(handle->fd, (void *)&(buf), data_len);
+                       if (ret < 0) {  ERROR("socket_recv error"); break; }
+                       read_len += ret;
+
+                       dhandle = pims_ipc_data_steal_unmarshal(buf, data_len);
+                       buf = NULL;
+
+                       pims_ipc_subscribe_data_s *sub_data = (pims_ipc_subscribe_data_s *)calloc(1, sizeof(pims_ipc_subscribe_data_s));
+                       sub_data->handle = dhandle;
+                       sub_data->call_id = call_id;
+                       call_id = NULL;
+
+                       pthread_mutex_lock(&handle->data_queue_mutex);
+                       handle->data_queue = g_list_append(handle->data_queue, sub_data);
+                       pthread_mutex_unlock(&handle->data_queue_mutex);
+                       write_command(handle->subscribe_fd, 1);
+               }
+               ret = 0;
+       }while(0);
+
+       free(call_id);
+       free(buf);
+       return ret;
+}
+
+static void* __io_thread(void *data)
+{
+       pims_ipc_s *handle = data;
+       struct epoll_event ev = {0};
+       int ret;
+       int epfd;
+
+       epfd = epoll_create(MAX_EPOLL_EVENT);
+
+       ev.events = EPOLLIN | EPOLLHUP;
+       ev.data.fd = handle->fd;
+
+       ret = epoll_ctl(epfd, EPOLL_CTL_ADD, handle->fd, &ev);
+       WARN_IF(ret != 0, "listen error :%d", ret);
+
+       while (!handle->epoll_stop_thread) {
+               int i = 0;
+               struct epoll_event events[MAX_EPOLL_EVENT] = {{0}, };
+               int event_num = epoll_wait(epfd, events, MAX_EPOLL_EVENT, 50);
+
+               if (handle->epoll_stop_thread)
+                       break;
+
+               if (event_num == -1) {
+                       if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
+                               ERROR("errno:%d\n", errno);
+                               break;
+                       }
+               }
+
+               for (i = 0; i < event_num; i++) {
+                       if (events[i].events & EPOLLHUP) {
+                               ERROR("server fd closed");
+                               handle->epoll_stop_thread = true;
+                               break;
+                       }
+
+                       if (events[i].events & EPOLLIN) {
+                               if(__subscribe_data(handle) < 0)
+                                       break;
+                       }
+               }
+       }
+
+       close(epfd);
+
+       pthread_exit(NULL);
 }
 
 static pims_ipc_h __pims_ipc_create(char *service, pims_ipc_mode_e mode)
 {
-    pims_ipc_context_t *ghandle = NULL;
-    pims_ipc_t *handle = NULL;
-    pid_t pid = 0;
-    void *context = NULL;
-    void *requester = NULL;
-    char *path = NULL;
-    gboolean is_ok = FALSE;
-        
-    pthread_mutex_lock(&__gmutex);
-
-    do {
-        if (_g_singleton == NULL)
-        {
-            ghandle = g_new0(pims_ipc_context_t, 1);
-            if (ghandle == NULL)
-            {
-                ERROR("Failed to allocation");
-                break;
-            }
-            
-            pid = getpid();
-            ghandle->pid = pid;
-            VERBOSE("The PID of the current process is %d.", pid);
-
-            context = zmq_init(1);
-            if (!context)
-            {
-                ERROR("init error : %s", zmq_strerror(errno));
-                break;
-            }
-            ghandle->context = context;
-            ghandle->id_sequence_no = (unsigned int)time(NULL);
-            ghandle->ref_cnt = 1;
-            _g_singleton = ghandle;
-        }
-        else
-        {
-            ghandle = _g_singleton;
-            ghandle->ref_cnt++;
-            pid = ghandle->pid;
-            context = ghandle->context;
-        }
-
-        VERBOSE("Create %d th..", ghandle->ref_cnt);
-
-        handle = g_new0(pims_ipc_t, 1);
-        if (handle == NULL)
-        {
-            ERROR("Failed to allocation");
-            break;
-        }
-        handle->fd = -1;
-
-        handle->service = g_strdup(service);
-        handle->id = g_strdup_printf("%x:%x", pid, ghandle->id_sequence_no++);
-        
-        if (mode == PIMS_IPC_MODE_REQ)
-        {
-            path = g_strdup_printf("%s-%s", handle->service, PIMS_IPC_MONITOR_PATH);
-            handle->fd = _client_socket_init(path, handle->id);
-            if (handle->fd == -1)
-            {
-                g_free(path);
-                break;
-            }
-            g_free(path);
-
-            requester = zmq_socket(context, ZMQ_REQ);
-            if (!requester)
-            {
-                ERROR("socket error : %s", zmq_strerror(errno));
-                break;
-            }
-            if (zmq_setsockopt(requester, ZMQ_IDENTITY, handle->id, strlen(handle->id) + 1) != 0)
-            {
-                ERROR("setsockopt error : %s", zmq_strerror(errno));
-                break;
-            }
-            handle->requester = requester;
-
-            path = g_strdup_printf("ipc://%s", handle->service);
-            if (zmq_connect(requester, path) != 0)
-            {
-                ERROR("connect error : %s", zmq_strerror(errno));
-                g_free(path);
-                break;
-            }
-            g_free(path);
-
-            handle->call_sequence_no = (unsigned int)time(NULL);
-            if (pims_ipc_call(handle, PIMS_IPC_MODULE_INTERNAL, PIMS_IPC_FUNCTION_CREATE, NULL, NULL) != 0)
-            {
-                WARNING("pims_ipc_call(PIMS_IPC_FUNCTION_CREATE) failed");
-            }
-        }
-        else
-        {
-            requester = zmq_socket(context, ZMQ_SUB);
-            if (!requester)
-            {
-                ERROR("socket error : %s", zmq_strerror(errno));
-                break;
-            }
-            if (zmq_setsockopt(requester, ZMQ_SUBSCRIBE, "", 0) != 0)
-            {
-                ERROR("setsockopt error : %s", zmq_strerror(errno));
-                break;
-            }
-            handle->requester = requester;
-
-            path = g_strdup_printf("ipc://%s", handle->service);
-            if (zmq_connect(requester, path) != 0)
-            {
-                ERROR("connect error : %s", zmq_strerror(errno));
-                g_free(path);
-                break;
-            }
-            g_free(path);
-
-            int fd = -1;
-            size_t opt_len = sizeof(int);
-            int rc = zmq_getsockopt(handle->requester, ZMQ_FD, &fd, &opt_len);
-            ASSERT(rc == 0);
-
-            handle->async_channel = g_io_channel_unix_new(fd);
-            if (!handle->async_channel)
-            {
-                ERROR("g_io_channel_unix_new error");
-                break;
-            }
-
-            guint source_id = 0;
-            source_id = g_io_add_watch(handle->async_channel, G_IO_IN, __pims_ipc_subscribe_handler, handle);
-            handle->async_source_id = source_id;
-            handle->subscribe_cb_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-            ASSERT(handle->subscribe_cb_table);
-
-            // add a subscriber handle to the global list
-            ghandle->subscribe_handles = g_list_append(ghandle->subscribe_handles, handle);
-            VERBOSE("the count of subscribe handles = %d", g_list_length(ghandle->subscribe_handles));
-        }
-
-        is_ok = TRUE;
-        VERBOSE("A new handle is created : %s, %s", handle->service, handle->id);
-    } while(0);
-
-    pthread_mutex_unlock(&__gmutex);
-
-    if (FALSE == is_ok)
-    {
-        if (handle)
-        {
-            __pims_ipc_free_handle(handle);
-            handle = NULL;
-        }
-    }
-
-    return handle;
+       pims_ipc_s *handle = NULL;
+       gboolean is_ok = FALSE;
+
+       pthread_mutex_lock(&__gmutex);
+
+       do {
+               struct sockaddr_un server_addr;
+               int ret;
+
+               ref_cnt++;
+               VERBOSE("Create %d th..", ref_cnt);
+
+               handle = g_new0(pims_ipc_s, 1);
+               if (handle == NULL) {
+                       ERROR("Failed to allocation");
+                       break;
+               }
+
+               handle->subscribe_fd = -1;
+               handle->io_thread = 0;
+               handle->service = g_strdup(service);
+               handle->id = g_strdup_printf("%x:%x", getpid(), __get_global_sequence_no());
+               handle->fd = socket(PF_UNIX, SOCK_STREAM, 0);
+               if (handle->fd < 0) {
+                       ERROR("socket error : %d, errno: %d", handle->fd, errno);
+                       break;
+               }
+               int flags = fcntl (handle->fd, F_GETFL, 0);
+               if (flags == -1)
+                       flags = 0;
+               ret = fcntl (handle->fd, F_SETFL, flags | O_NONBLOCK);
+               VERBOSE("socket fcntl : %d\n", ret);
+
+               pthread_mutex_init(&handle->call_status_mutex, 0);
+
+               pthread_mutex_lock(&handle->call_status_mutex);
+               handle->call_status = PIMS_IPC_CALL_STATUS_READY;
+               pthread_mutex_unlock(&handle->call_status_mutex);
+
+               bzero(&server_addr, sizeof(server_addr));
+               server_addr.sun_family = AF_UNIX;
+               snprintf(server_addr.sun_path, sizeof(server_addr.sun_path), "%s", handle->service);
+
+               ret = connect(handle->fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
+               if (ret != 0) {
+                       ERROR("connect error : %d, errno: %d", ret, errno);
+                       break;
+               }
+               VERBOSE("connect to server : socket:%s, client_sock:%d, %d\n", handle->service, handle->fd, ret);
+
+               if (mode == PIMS_IPC_MODE_REQ) {
+                       handle->call_sequence_no = (unsigned int)time(NULL);
+                       ret = __pims_ipc_send_identify(handle);
+                       if (ret < 0) {
+                               ERROR("__pims_ipc_send_identify error");
+                               break;
+                       }
+                       __pims_ipc_receive(handle, NULL);
+
+                       if (pims_ipc_call(handle, PIMS_IPC_MODULE_INTERNAL, PIMS_IPC_FUNCTION_CREATE, NULL, NULL) != 0) {
+                               WARNING("pims_ipc_call(PIMS_IPC_FUNCTION_CREATE) failed");
+                       }
+               }
+               else {
+                       handle->epoll_stop_thread = false;
+                       pthread_mutex_init(&handle->data_queue_mutex, 0);
+
+                       pthread_mutex_lock(&handle->data_queue_mutex);
+                       handle->data_queue = NULL;
+                       pthread_mutex_unlock(&handle->data_queue_mutex);
+
+                       ret = __open_subscribe_fd(handle);
+                       if (ret < 0)
+                               break;
+
+                       pthread_t worker;
+                       ret = pthread_create(&worker, NULL, __io_thread, handle);
+                       if (ret != 0)
+                               break;
+                       handle->io_thread  = worker;
+
+                       GIOChannel *async_channel = g_io_channel_unix_new(handle->subscribe_fd);
+                       if (!async_channel) {
+                               ERROR("g_io_channel_unix_new error");
+                               break;
+                       }
+                       handle->async_channel = async_channel;
+                       handle->async_source_id = g_io_add_watch(handle->async_channel, G_IO_IN|G_IO_HUP, __pims_ipc_subscribe_handler, handle);
+                       handle->subscribe_cb_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+                       ASSERT(handle->subscribe_cb_table);
+
+                       // add a subscriber handle to the global list
+                       subscribe_handles = g_list_append(subscribe_handles, handle);
+                       VERBOSE("the count of subscribe handles = %d", g_list_length(subscribe_handles));
+               }
+
+               is_ok = TRUE;
+               VERBOSE("A new handle is created : %s, %s", handle->service, handle->id);
+       } while(0);
+
+       pthread_mutex_unlock(&__gmutex);
+
+       if (FALSE == is_ok) {
+               if (handle) {
+                       __pims_ipc_free_handle(handle);
+                       handle = NULL;
+               }
+       }
+
+       return handle;
 }
 
 API pims_ipc_h pims_ipc_create(char *service)
 {
-    return __pims_ipc_create(service, PIMS_IPC_MODE_REQ);
+       return __pims_ipc_create(service, PIMS_IPC_MODE_REQ);
 }
 
 API pims_ipc_h pims_ipc_create_for_subscribe(char *service)
 {
-    return __pims_ipc_create(service, PIMS_IPC_MODE_SUB);
+       return __pims_ipc_create(service, PIMS_IPC_MODE_SUB);
 }
 
 static void __pims_ipc_destroy(pims_ipc_h ipc, pims_ipc_mode_e mode)
 {
-    pims_ipc_t *handle = (pims_ipc_t *)ipc;
+       pims_ipc_s *handle = (pims_ipc_s *)ipc;
 
-    if (mode == PIMS_IPC_MODE_REQ)
-    {
-        if (pims_ipc_call(handle, PIMS_IPC_MODULE_INTERNAL, PIMS_IPC_FUNCTION_DESTROY, NULL, NULL) != 0)
-        {
-            WARNING("pims_ipc_call(PIMS_IPC_FUNCTION_DESTROY) failed");
-        }
-    }
+       if (mode == PIMS_IPC_MODE_REQ) {
+               if (pims_ipc_call(handle, PIMS_IPC_MODULE_INTERNAL, PIMS_IPC_FUNCTION_DESTROY, NULL, NULL) != 0) {
+                       WARNING("pims_ipc_call(PIMS_IPC_FUNCTION_DESTROY) failed");
+               }
+       }
 
-    __pims_ipc_free_handle(handle);
+       if (handle)
+               __pims_ipc_free_handle(handle);
 }
 
 API void pims_ipc_destroy(pims_ipc_h ipc)
 {
-    __pims_ipc_destroy(ipc, PIMS_IPC_MODE_REQ);
+       __pims_ipc_destroy(ipc, PIMS_IPC_MODE_REQ);
 }
 
 API void pims_ipc_destroy_for_subscribe(pims_ipc_h ipc)
 {
-    __pims_ipc_destroy(ipc, PIMS_IPC_MODE_SUB);
+       __pims_ipc_destroy(ipc, PIMS_IPC_MODE_SUB);
 }
 
-static void __pims_ipc_data_free_cb(void *data, void *hint)
+static int __pims_ipc_send(pims_ipc_s *handle, char *module, char *function, pims_ipc_data_h data_in)
 {
-    if (hint)
-        g_free(hint);
+       int ret = -1;
+       unsigned int sequence_no = 0;
+       gchar *call_id = PIMS_IPC_MAKE_CALL_ID(module, function);
+       unsigned int call_id_len = strlen(call_id);
+       pims_ipc_data_s *data = NULL;
+       unsigned int is_data = FALSE;
+       unsigned int client_id_len = strlen(handle->id);
+       int length = 0;
+
+       GET_CALL_SEQUNECE_NO(handle, sequence_no);
+
+       int len = sizeof(unsigned int)                                          // total size
+               + client_id_len + sizeof(unsigned int)  // client_id
+               + sizeof(unsigned int)                                          // seq_no
+               + call_id_len + sizeof(unsigned int)    // call_id
+               + sizeof(unsigned int);                                         // is data
+
+       int total_len = len;
+
+       if (data_in) {
+               is_data = TRUE;
+               data = (pims_ipc_data_s*)data_in;
+               len += sizeof(unsigned int);
+               total_len = len + data->buf_size;
+       }
+
+       INFO("len : %d, client_id : %s, call_id : %s, seq_no :%d", len, handle->id, call_id, sequence_no);
+
+       char buf[len+1];
+
+       memset(buf, 0x0, len+1);
+
+       memcpy(buf, (void*)&total_len, sizeof(unsigned int));
+       length += sizeof(unsigned int);
+
+       // client_id
+       client_id_len = strlen(handle->id);
+       memcpy(buf+length, (void*)&(client_id_len), sizeof(unsigned int));
+       length += sizeof(unsigned int);
+       memcpy(buf+length, (void*)(handle->id), client_id_len);
+       length += client_id_len;
+
+       // seq_no
+       memcpy(buf+length, (void*)&(sequence_no), sizeof(unsigned int));
+       length += sizeof(unsigned int);
+
+       // call id
+       memcpy(buf+length, (void*)&(call_id_len), sizeof(unsigned int));
+       length += sizeof(unsigned int);
+       memcpy(buf+length, (void*)(call_id), call_id_len);
+       length += call_id_len;
+       g_free(call_id);
+
+       // is_data
+       memcpy(buf+length, (void*)&(is_data), sizeof(unsigned int));
+       length += sizeof(unsigned int);
+
+       if (is_data) {
+               memcpy(buf+length, (void*)&(data->buf_size), sizeof(unsigned int));
+               length += sizeof(unsigned int);
+
+               ret = socket_send(handle->fd, buf, length);
+               if (ret > 0)
+                       ret = socket_send_data(handle->fd, data->buf, data->buf_size);
+       }
+       else {
+               ret = socket_send(handle->fd, buf, length);
+       }
+
+       if (ret < 0)
+               return -1;
+
+       return 0;
 }
 
-static int __pims_ipc_send(pims_ipc_t *handle, char *module, char *function, pims_ipc_h data_in)
+API int pims_ipc_call(pims_ipc_h ipc, char *module, char *function, pims_ipc_data_h data_in,
+               pims_ipc_data_h *data_out)
 {
-    gboolean is_valid = FALSE;
-    unsigned int sequence_no = 0;
-    gchar *call_id = PIMS_IPC_MAKE_CALL_ID(module, function);
-
-    // init messages
-    zmq_msg_t sequence_no_msg;
-    zmq_msg_t call_id_msg;
-    zmq_msg_t data_in_msg;
-
-    zmq_msg_init_size(&sequence_no_msg, sizeof(unsigned int));
-    GET_CALL_SEQUNECE_NO(handle, sequence_no);
-    memcpy(zmq_msg_data(&sequence_no_msg), &(sequence_no), sizeof(unsigned int));
-
-    zmq_msg_init_data(&call_id_msg, call_id, strlen(call_id) + 1, __pims_ipc_data_free_cb, call_id);
-    VERBOSE("call id = %s", (char*)zmq_msg_data(&call_id_msg));
-
-    zmq_msg_init(&data_in_msg);
-
-    do {
-        // send sequence no
-        if (_pims_zmq_msg_send(&sequence_no_msg, handle->requester, ZMQ_SNDMORE) == -1)
-        {
-            ERROR("send error : %s", zmq_strerror(errno));
-            break;
-        }
-
-        if (data_in == NULL)
-        {
-            // send call id
-            if (_pims_zmq_msg_send(&call_id_msg, handle->requester, 0) == -1)
-            {
-                ERROR("send error : %s", zmq_strerror(errno));
-                break;
-            }
-        }
-        else
-        {
-            // send call id
-            if (_pims_zmq_msg_send(&call_id_msg, handle->requester, ZMQ_SNDMORE) == -1)
-            {
-                ERROR("send error : %s", zmq_strerror(errno));
-                break;
-            }
-
-            // marshal data
-            if (pims_ipc_data_marshal_with_zmq(data_in, &data_in_msg) != 0)
-            {
-                ERROR("marshal error");
-                break;
-            }
-
-            VERBOSE("the size of sending data = %d", zmq_msg_size(&data_in_msg));
-            
-            // send data
-            if (_pims_zmq_msg_send(&data_in_msg, handle->requester, 0) == -1)
-            {
-                ERROR("send error : %s", zmq_strerror(errno));
-                break;
-            }
-        }
-
-        is_valid = TRUE;
-    } while (0);
-
-    zmq_msg_close(&sequence_no_msg);
-    zmq_msg_close(&call_id_msg);
-    zmq_msg_close(&data_in_msg);
-
-    if (is_valid == FALSE)
-        return -1;
-    return 0;
-}
+       pims_ipc_s *handle = (pims_ipc_s *)ipc;
 
-static int __pims_ipc_receive(pims_ipc_t *handle, pims_ipc_data_h *data_out)
-{
-    gboolean is_ok = FALSE;
-    gboolean is_valid = FALSE;
-    int64_t more = 0;
-    pims_ipc_data_h dhandle = NULL;
-    unsigned int sequence_no = 0;
-   
-    zmq_msg_t sequence_no_msg;
-    zmq_msg_t call_id_msg;
-    zmq_msg_t data_out_msg;
-
-    while (1)
-    {
-        is_valid = FALSE;
-        more = 0;
-
-        zmq_msg_init(&sequence_no_msg);
-        zmq_msg_init(&call_id_msg);
-        zmq_msg_init(&data_out_msg);
-
-        do {
-            // recv sequence no
-            if (__pims_zmq_msg_recv_by_handle(&sequence_no_msg, handle, 0) == -1)
-            {
-                ERROR("recv error : %s", zmq_strerror(errno));
-                break;
-            }
-            memcpy(&sequence_no, zmq_msg_data(&sequence_no_msg), sizeof(unsigned int));
-
-            // recv call id 
-            if (__pims_zmq_msg_recv_by_handle(&call_id_msg, handle, 0) == -1)
-            {
-                ERROR("recv error : %s", zmq_strerror(errno));
-                break;
-            }
-
-            size_t more_size = sizeof(more);
-            zmq_getsockopt(handle->requester, ZMQ_RCVMORE, &more, &more_size);
-            if (more)
-            {
-                if (__pims_zmq_msg_recv_by_handle(&data_out_msg, handle, 0) == -1)
-                {
-                    ERROR("recv error : %s", zmq_strerror(errno));
-                    break;
-                }
-                dhandle = pims_ipc_data_unmarshal_with_zmq(&data_out_msg);
-                if (dhandle == NULL)
-                {
-                    ERROR("unmarshal error");
-                    break;
-                }
-
-                if (sequence_no == handle->call_sequence_no)
-                {
-                    if (data_out != NULL)
-                        *data_out = dhandle;
-                    is_ok = TRUE;
-                }
-                else
-                {
-                    pims_ipc_data_destroy(dhandle);
-                    DEBUG("received an mismatched response (%x:%x)", handle->call_sequence_no, sequence_no);
-                }
-            }
-            else
-            {
-                if (sequence_no == handle->call_sequence_no)
-                    is_ok = TRUE;
-            }
-
-            is_valid = TRUE;
-        } while (0);
-
-        zmq_msg_close(&sequence_no_msg);
-        zmq_msg_close(&call_id_msg);
-        zmq_msg_close(&data_out_msg);
-
-        if (is_ok)
-            return 0;
-
-        if (is_valid == FALSE)
-            return -1;
-    }
-
-    return -1;
+
+       if (ipc == NULL) {
+               ERROR("invalid handle : %p", ipc);
+               return -1;
+       }
+
+       if (!module || !function) {
+               ERROR("invalid argument");
+               return -1;
+       }
+
+       pthread_mutex_lock(&handle->call_status_mutex);
+       if (handle->call_status != PIMS_IPC_CALL_STATUS_READY) {
+               pthread_mutex_unlock(&handle->call_status_mutex);
+               ERROR("the previous call is in progress : %p", ipc);
+               return -1;
+       }
+       pthread_mutex_unlock(&handle->call_status_mutex);
+
+
+       if (__pims_ipc_send(handle, module, function, data_in) != 0) {
+               return -1;
+       }
+
+       if (__pims_ipc_receive(handle, data_out) != 0) {
+               return -1;
+       }
+
+       return 0;
 }
 
-API int pims_ipc_call(pims_ipc_h ipc, char *module, char *function, pims_ipc_data_h data_in,
-                      pims_ipc_data_h *data_out)
+static gboolean __call_async_idler_cb(gpointer data)
 {
-    pims_ipc_t *handle = (pims_ipc_t *)ipc;
-
-
-    if (ipc == NULL)
-    {
-        ERROR("invalid handle : %p", ipc);
-        return -1;
-    }
-
-    if (!module || !function)
-    {
-        ERROR("invalid argument");
-        return -1;
-    }
-
-    if (handle->call_status != PIMS_IPC_CALL_STATUS_READY)
-    {
-        ERROR("the previous call is in progress : %p", ipc);
-        return -1;
-    }
-
-    if (__pims_ipc_send(handle, module, function, data_in) != 0)
-    {
-        return -1;
-    }
-
-    if (__pims_ipc_receive(handle, data_out) != 0)
-    {
-        return -1;
-    }
-    
-    return 0;
+       VERBOSE("");
+
+       pims_ipc_s *handle = (pims_ipc_s *)data;
+       ASSERT(handle);
+       ASSERT(handle->dhandle_for_async_idler);
+       pims_ipc_data_h dhandle = handle->dhandle_for_async_idler;
+       handle->dhandle_for_async_idler = NULL;
+
+       pthread_mutex_lock(&handle->call_status_mutex);
+       handle->call_status = PIMS_IPC_CALL_STATUS_READY;
+       pthread_mutex_unlock(&handle->call_status_mutex);
+
+       handle->call_async_callback((pims_ipc_h)handle, dhandle, handle->call_async_userdata);
+       pims_ipc_data_destroy(dhandle);
+
+       return FALSE;
 }
 
 static gboolean __pims_ipc_call_async_handler(GIOChannel *src, GIOCondition condition, gpointer data)
 {
-    pims_ipc_t *handle = (pims_ipc_t *)data;
-    uint32_t zmq_events = 0;
-    size_t opt_len = 0;
-    int rc = 0;
-
-    VERBOSE("");
-
-    opt_len = sizeof(uint32_t);
-    while (1)
-    {
-        rc = zmq_getsockopt(handle->requester, ZMQ_EVENTS, &zmq_events, &opt_len);
-        ASSERT(rc == 0);
-        if (ZMQ_POLLIN & zmq_events) {
-            pims_ipc_data_h dhandle = NULL;
-            if (__pims_ipc_receive(handle, &dhandle) == 0)
-            {
-                VERBOSE("call status = %d", handle->call_status);
-                if (handle->call_status != PIMS_IPC_CALL_STATUS_IN_PROGRESS)
-                {
-                    pims_ipc_data_destroy(dhandle);
-                }
-                else
-                {
-                    handle->call_status = PIMS_IPC_CALL_STATUS_READY;
-                    handle->call_async_callback((pims_ipc_h)handle, dhandle, handle->call_async_userdata);
-                    pims_ipc_data_destroy(dhandle);
-                }
-            }
-        }
-        else
-        {
-            break;
-        }
-    }
-
-    return FALSE;
+       pims_ipc_s *handle = (pims_ipc_s *)data;
+       pims_ipc_data_h dhandle = NULL;
+
+       if (__pims_ipc_receive(handle, &dhandle) == 0) {
+               VERBOSE("call status = %d", handle->call_status);
+
+               pthread_mutex_lock(&handle->call_status_mutex);
+               if (handle->call_status != PIMS_IPC_CALL_STATUS_IN_PROGRESS) {
+                       pthread_mutex_unlock(&handle->call_status_mutex);
+                       pims_ipc_data_destroy(dhandle);
+               }
+               else {
+                       pthread_mutex_unlock(&handle->call_status_mutex);
+                       if (src == NULL) {    // A response is arrived too quickly
+                               handle->dhandle_for_async_idler = dhandle;
+                               g_idle_add(__call_async_idler_cb, handle);
+                       }
+                       else {
+                               pthread_mutex_lock(&handle->call_status_mutex);
+                               handle->call_status = PIMS_IPC_CALL_STATUS_READY;
+                               pthread_mutex_unlock(&handle->call_status_mutex);
+
+                               handle->call_async_callback((pims_ipc_h)handle, dhandle, handle->call_async_userdata);
+                               pims_ipc_data_destroy(dhandle);
+                       }
+               }
+       }
+       return FALSE;
 }
 
 API int pims_ipc_call_async(pims_ipc_h ipc, char *module, char *function, pims_ipc_data_h data_in,
-                            pims_ipc_call_async_cb callback, void *userdata)
+               pims_ipc_call_async_cb callback, void *userdata)
 {
-    pims_ipc_t *handle = (pims_ipc_t *)ipc;
-    guint source_id = 0;
-
-    if (ipc == NULL)
-    {
-        ERROR("invalid handle : %p", ipc);
-        return -1;
-    }
-
-    if (!module || !function || !callback)
-    {
-        ERROR("invalid argument");
-        return -1;
-    }
-
-    if (handle->call_status != PIMS_IPC_CALL_STATUS_READY)
-    {
-        ERROR("the previous call is in progress : %p", ipc);
-        return -1;
-    }
-
-    handle->call_status = PIMS_IPC_CALL_STATUS_IN_PROGRESS;
-    handle->call_async_callback = callback;
-    handle->call_async_userdata = userdata;
-
-    // add a callback for GIOChannel
-    if (!handle->async_channel)
-    {
-        int fd = -1;
-        size_t opt_len = sizeof(int);
-        int rc = zmq_getsockopt(handle->requester, ZMQ_FD, &fd, &opt_len);
-        ASSERT(rc == 0);
-
-        handle->async_channel = g_io_channel_unix_new(fd);
-        if (!handle->async_channel)
-        {
-            ERROR("g_io_channel_unix_new error");
-            return -1;
-        }
-    }
-    
-    source_id = g_io_add_watch(handle->async_channel, G_IO_IN, __pims_ipc_call_async_handler, handle);
-    handle->async_source_id = source_id;
-
-    if (__pims_ipc_send(handle, module, function, data_in) != 0)
-    {
-        g_source_remove(source_id);
-        return -1;
-    }
-    
-    uint32_t zmq_events = 0;
-    size_t opt_len = sizeof(uint32_t);
-    int rc = 0;
-    rc = zmq_getsockopt(handle->requester, ZMQ_EVENTS, &zmq_events, &opt_len);
-    ASSERT(rc == 0);
-
-    return 0;
+       pims_ipc_s *handle = (pims_ipc_s *)ipc;
+       guint source_id = 0;
+
+       if (ipc == NULL) {
+               ERROR("invalid handle : %p", ipc);
+               return -1;
+       }
+
+       if (!module || !function || !callback) {
+               ERROR("invalid argument");
+               return -1;
+       }
+
+       pthread_mutex_lock(&handle->call_status_mutex);
+       if (handle->call_status != PIMS_IPC_CALL_STATUS_READY) {
+               pthread_mutex_unlock(&handle->call_status_mutex);
+               ERROR("the previous call is in progress : %p", ipc);
+               return -1;
+       }
+       pthread_mutex_unlock(&handle->call_status_mutex);
+
+       pthread_mutex_lock(&handle->call_status_mutex);
+       handle->call_status = PIMS_IPC_CALL_STATUS_IN_PROGRESS;
+       pthread_mutex_unlock(&handle->call_status_mutex);
+
+       handle->call_async_callback = callback;
+       handle->call_async_userdata = userdata;
+
+       // add a callback for GIOChannel
+       if (!handle->async_channel) {
+               handle->async_channel = g_io_channel_unix_new(handle->fd);
+               if (!handle->async_channel) {
+                       ERROR("g_io_channel_unix_new error");
+                       return -1;
+               }
+       }
+
+       source_id = g_io_add_watch(handle->async_channel, G_IO_IN, __pims_ipc_call_async_handler, handle);
+       handle->async_source_id = source_id;
+
+       if (__pims_ipc_send(handle, module, function, data_in) != 0) {
+               g_source_remove(source_id);
+               return -1;
+       }
+
+       __pims_ipc_call_async_handler(NULL, G_IO_NVAL, handle);
+
+       return 0;
 }
 
 API bool pims_ipc_is_call_in_progress(pims_ipc_h ipc)
 {
-    pims_ipc_t *handle = (pims_ipc_t *)ipc;
-
-    if (ipc == NULL)
-    {
-        ERROR("invalid handle : %p", ipc);
-        return false;
-    }
-
-    if (handle->call_status == PIMS_IPC_CALL_STATUS_IN_PROGRESS)
-        return true;
-    else
-        return false;
+       int ret;
+       pims_ipc_s *handle = (pims_ipc_s *)ipc;
+
+       if (ipc == NULL) {
+               ERROR("invalid handle : %p", ipc);
+               return false;
+       }
+
+       pthread_mutex_lock(&handle->call_status_mutex);
+       if (handle->call_status == PIMS_IPC_CALL_STATUS_IN_PROGRESS)
+               ret = true;
+       else
+               ret = false;
+       pthread_mutex_unlock(&handle->call_status_mutex);
+       return ret;
 }
 
 API int pims_ipc_subscribe(pims_ipc_h ipc, char *module, char *event, pims_ipc_subscribe_cb callback, void *userdata)
 {
-    gchar *call_id = NULL;
-    pims_ipc_cb_t *cb_data = NULL;
-    pims_ipc_t *handle = (pims_ipc_t *)ipc;
-
-    if (ipc == NULL || handle->subscribe_cb_table == NULL)
-    {
-        ERROR("invalid handle : %p", ipc);
-        return -1;
-    }
-
-    if (!module || !event || !callback)
-    {
-        ERROR("invalid argument");
-        return -1;
-    }
-
-    cb_data = g_new0(pims_ipc_cb_t, 1);
-    call_id = PIMS_IPC_MAKE_CALL_ID(module, event);
-
-    VERBOSE("subscribe cb id[%s]", call_id);
-    cb_data->callback = callback;
-    cb_data->user_data = userdata;
-    g_hash_table_insert(handle->subscribe_cb_table, call_id, cb_data);
-
-    return 0;
+       gchar *call_id = NULL;
+       pims_ipc_cb_s *cb_data = NULL;
+       pims_ipc_s *handle = (pims_ipc_s *)ipc;
+
+       if (ipc == NULL || handle->subscribe_cb_table == NULL) {
+               ERROR("invalid handle : %p", ipc);
+               return -1;
+       }
+
+       if (!module || !event || !callback) {
+               ERROR("invalid argument");
+               return -1;
+       }
+
+       cb_data = g_new0(pims_ipc_cb_s, 1);
+       call_id = PIMS_IPC_MAKE_CALL_ID(module, event);
+
+       VERBOSE("subscribe cb id[%s]", call_id);
+       cb_data->callback = callback;
+       cb_data->user_data = userdata;
+       g_hash_table_insert(handle->subscribe_cb_table, call_id, cb_data);
+
+       return 0;
 }
 
 API int pims_ipc_unsubscribe(pims_ipc_h ipc, char *module, char *event)
 {
-    gchar *call_id = NULL;
-    pims_ipc_t *handle = (pims_ipc_t *)ipc;
-
-    if (ipc == NULL || handle->subscribe_cb_table == NULL)
-    {
-        ERROR("invalid handle : %p", ipc);
-        return -1;
-    }
-
-    if (!module || !event)
-    {
-        ERROR("invalid argument");
-        return -1;
-    }
-
-    call_id = PIMS_IPC_MAKE_CALL_ID(module, event);
-
-    VERBOSE("unsubscribe cb id[%s]", call_id);
-
-    if (g_hash_table_remove(handle->subscribe_cb_table, call_id) != TRUE)
-    {
-        ERROR("g_hash_table_remove error");
-        g_free(call_id);
-        return -1;
-    }
-
-    g_free(call_id);
-    return 0;
+       gchar *call_id = NULL;
+       pims_ipc_s *handle = (pims_ipc_s *)ipc;
+
+       if (ipc == NULL || handle->subscribe_cb_table == NULL) {
+               ERROR("invalid handle : %p", ipc);
+               return -1;
+       }
+
+       if (!module || !event) {
+               ERROR("invalid argument");
+               return -1;
+       }
+
+       call_id = PIMS_IPC_MAKE_CALL_ID(module, event);
+
+       VERBOSE("unsubscribe cb id[%s]", call_id);
+
+       if (g_hash_table_remove(handle->subscribe_cb_table, call_id) != TRUE) {
+               ERROR("g_hash_table_remove error");
+               g_free(call_id);
+               return -1;
+       }
+
+       g_free(call_id);
+       return 0;
 }
+
index bf02682..eff803d 100644 (file)
@@ -16,8 +16,6 @@
  * limitations under the License.
  */
 
-
-#ifndef _NON_SLP
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <systemd/sd-daemon.h>
 
-#include <pims-internal.h>
-#include <pims-debug.h>
-#include <pims-socket.h>
+#include "pims-internal.h"
+#include "pims-debug.h"
+#include "pims-socket.h"
 
-typedef struct
-{
-    int sockfd;
-    server_socket_client_closed_cb callback;
-    void *user_data;
-    GHashTable *client_table;
-} server_socket_context_t;
+#define MAX_ARRAY_LEN  65535
 
-static int __socket_writen(int fd, char *buf, int buf_size)
+int socket_send(int fd, char *buf, int len)
 {
-    int ret, writed = 0;
-    while (buf_size)
-    {
-        ret = write(fd, buf+writed, buf_size);
-        if (-1 == ret)
-        {
-            if (EINTR == errno)
-                continue;
-            else
-                return ret;
-        }
-        writed += ret;
-        buf_size -= ret;
-    }
-    return writed;
+       if (!buf || len <= 0) {
+               INFO("No data to send %p, %d", buf, len);
+               return -1;
+       }
+
+       int length = len;
+       int passed_len = 0;
+       int write_len = 0;
+
+       while (length > 0) {
+               passed_len = send(fd, (const void *)buf, length, MSG_NOSIGNAL);
+               if (passed_len == -1) {
+                       if (errno == EINTR)
+                               continue;
+                       else if (errno == EAGAIN)
+                               continue;
+                       else if (errno == EWOULDBLOCK)
+                               continue;
+                       ERROR("send error [%d]", errno);
+                       break;
+               } else if (passed_len == 0)
+                       break;
+               length -= passed_len;
+               buf += passed_len;
+       }
+       write_len = len - length;
+
+       if (write_len != len) {
+               WARNING("WARNING: buf_size [%d] != write_len[%d]", len, write_len);
+               return -1;
+       }
+       VERBOSE("write_len [%d]", write_len);
+
+       return write_len;
 }
 
-static int __socket_readn(int fd, char *buf, int buf_size)
+int socket_recv(int fd, void **buf, unsigned int len)
 {
-    int ret, read_size = 0;
-
-    while (buf_size)
-    {
-        ret = read(fd, buf+read_size, buf_size);
-        if (-1 == ret)
-        {
-            if (EINTR == errno)
-                continue;
-            else
-                return ret;
-        }
-        read_size += ret;
-        buf_size -= ret;
-    }
-    return read_size;
+       if (!buf) {
+               INFO("Buffer must not null");
+               return -1;
+       }
+
+       unsigned int length = len;
+       int read_len = 0;
+       int final_len = 0;
+       char *temp = *buf;
+
+       while (length > 0) {
+               read_len = read(fd, (void *)temp, length);
+               if (read_len < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       else if (errno == EAGAIN)
+                               continue;
+                       else if (errno == EWOULDBLOCK)
+                               continue;
+                       else if (errno == EPIPE) {
+                               ERROR("connection closed : read err %d", errno, read_len, length);
+                               free(*buf);
+                               *buf = NULL;
+                               return 0; /* connection closed */
+                       }
+                       ERROR("read err %d, read_len :%d, length : %d", errno, read_len, length);
+                       final_len = read_len;
+                       break;
+               } else if (read_len == 0)
+                       break;
+
+               length -= read_len;
+               temp += read_len;
+       }
+
+       if (final_len == 0)
+               final_len = (len-length);
+
+       if (len != final_len) {
+               WARNING("WARNING: buf_size [%d] != read_len[%d]\n", read_len, final_len);
+               return -1;
+       }
+
+       ((char*)*buf)[len]= '\0';
+
+       return final_len;
 }
 
-#define PIMS_IPC_PID_BUFFER_SIZE    20
-static gboolean __request_handler(GIOChannel *src, GIOCondition condition, gpointer data)
+int socket_send_data(int fd, char *buf, unsigned int len)
 {
-    server_socket_context_t *context = (server_socket_context_t*)data;
-    int ret = -1;
-    int fd = -1;
-    int orig_fd = -1;
-    char *pid = NULL;
-    char buffer[PIMS_IPC_PID_BUFFER_SIZE] = "";
-
-    fd = g_io_channel_unix_get_fd(src);
-
-    if (G_IO_HUP & condition)
-    {
-        close(fd);
-
-        if (g_hash_table_lookup_extended(context->client_table, GINT_TO_POINTER(fd),
-                    (gpointer*)&orig_fd, (gpointer*)&pid) == TRUE)
-        {
-            VERBOSE("found pid for %u = %s", fd, pid);
-            context->callback((const char*)pid, context->user_data);
-            g_hash_table_remove(context->client_table, (gconstpointer)fd);
-        }
-        else
-        {
-            VERBOSE("unable to find pid for %u", fd);
-        }
-
-        return FALSE;
-    }
-
-    memset(buffer, 0x00, PIMS_IPC_PID_BUFFER_SIZE);
-    ret = read(fd, (char *)buffer, PIMS_IPC_PID_BUFFER_SIZE-1);
-    if (ret <= 0)
-    {
-        ERROR("read error : %s", strerror(errno));
-        close(fd);
-
-        return FALSE;
-    }
-
-    VERBOSE("client fd = %u, pid = %s", fd, buffer);
-    g_hash_table_insert(context->client_table, GINT_TO_POINTER(fd), g_strdup(buffer));
-
-    pid_t mypid = getpid();
-    ret = __socket_writen(fd, (char*)&mypid, sizeof(pid_t));
-    if (ret != sizeof(pid_t))
-    {
-        ERROR("write error : %s", strerror(errno));
-        close(fd);
-        g_hash_table_remove(context->client_table, (gconstpointer)fd);
-
-        return FALSE;
-    }
-
-   return TRUE;
-}
-
-static gboolean __socket_handler(GIOChannel *src, GIOCondition condition, gpointer data)
-{
-    GIOChannel *channel;
-    server_socket_context_t *context = (server_socket_context_t*)data;
-    int client_sockfd = -1;
-    int sockfd = context->sockfd;
-    struct sockaddr_un clientaddr;
-    socklen_t client_len = sizeof(clientaddr);
-
-    client_sockfd = accept(sockfd, (struct sockaddr *)&clientaddr, &client_len);
-    if (-1 == client_sockfd)
-    {
-        ERROR("accept error : %s", strerror(errno));
-        return TRUE;
-    }
-
-    channel = g_io_channel_unix_new(client_sockfd);
-    g_io_add_watch(channel, G_IO_IN|G_IO_HUP, __request_handler, data);
-    g_io_channel_unref(channel);
-
-    return TRUE;
+       int ret = 0;
+       int send_len = 0;
+       int remain_len = len;
+
+       if (len > MAX_ARRAY_LEN)
+               INFO("send long data : length(%d) ++++++++++++++++++++++++", len);
+
+       while (len > send_len) {
+               if (remain_len > MAX_ARRAY_LEN)
+                       ret = socket_send(fd, (buf+send_len), MAX_ARRAY_LEN);
+               else
+                       ret = socket_send(fd, (buf+send_len), remain_len);
+
+               if (ret < 0) {
+                       ERROR("socket_send error");
+                       break;
+               }
+               send_len += ret;
+               remain_len -= ret;
+       }
+
+       if (ret < 0) {
+               ERROR("socket_send error");
+               return -1;
+       }
+
+       return send_len;
 }
 
-int _server_socket_init(const char *path, gid_t group, mode_t mode,
-        server_socket_client_closed_cb callback, void *user_data)
+int write_command(int fd, const uint64_t cmd)
 {
-    int sockfd = -1;
-    GIOChannel *gio = NULL;
-
-    if (sd_listen_fds(1) == 1 && sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_STREAM, -1, path, 0) > 0)
-    {
-        DEBUG("using system daemon");
-
-        sockfd = SD_LISTEN_FDS_START;
-    }
-    else
-    {
-        struct sockaddr_un addr;
-        int ret = -1;
-        
-        DEBUG("using local socket");
+       // poll : Level Trigger
+       uint64_t clear_cmd = 0;
+       int ret = write(fd, &clear_cmd, sizeof(clear_cmd));
+       if (ret < 0)
+               ERROR("write fail (%d)", ret);
 
-        unlink(path);
-
-        bzero(&addr, sizeof(addr));
-        addr.sun_family = AF_UNIX;
-        snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
-
-        sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
-        if (-1 == sockfd)
-        {
-            ERROR("socket error : %s", strerror(errno));
-            return -1;
-        }
-
-        ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
-        if (-1 == ret)
-        {
-            ERROR("bind error : %s", strerror(errno));
-            close(sockfd);
-            return -1;
-        }
-
-        ret = chown(path, getuid(), group);
-        ret = chmod(path, mode);
-
-        ret = listen(sockfd, 30);
-        if (-1 == ret)
-        {
-            ERROR("listen error : %s", strerror(errno));
-            close(sockfd);
-            return -1;
-        }
-    }
-
-    gio = g_io_channel_unix_new(sockfd);
-
-    server_socket_context_t *context = g_new0(server_socket_context_t, 1);
-    context->sockfd = sockfd;
-    context->callback = callback;
-    context->user_data = user_data;
-    context->client_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
-    ASSERT(context->client_table);
-
-    g_io_add_watch(gio, G_IO_IN, __socket_handler, (gpointer)context);
-
-    return sockfd;
-}
-
-int _client_socket_init(const char *path, const char *pid)
-{
-    int sockfd = -1;
-    int ret = -1;
-    struct sockaddr_un caddr = {0};
-    pid_t server_pid = 0;
-
-    ASSERT(path != NULL);
-    ASSERT(pid != NULL);
-    bzero(&caddr, sizeof(caddr));
-    caddr.sun_family = AF_UNIX;
-    snprintf(caddr.sun_path, sizeof(caddr.sun_path), "%s", path);
-
-    sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
-    if (-1 == sockfd)
-    {
-        ERROR("socket error : %s", strerror(errno));
-        return -1;
-    }
-
-    ret = connect(sockfd, (struct sockaddr *)&caddr, sizeof(caddr));
-    if (-1 == ret) {
-        ERROR("connect error : %s", strerror(errno));
-        close(sockfd);
-        return -1;
-    }
-    ret = __socket_writen(sockfd, (char*)pid, strlen(pid) + 1);
-    if (ret <= 0)
-    {
-        ERROR("write error : %s", strerror(errno));
-        close(sockfd);
-        return -1;
-    }
-    ret = __socket_readn(sockfd, (char*)&server_pid, sizeof(pid_t));
-    if (ret != sizeof(pid_t))
-    {
-        ERROR("read error : %s", strerror(errno));
-        close(sockfd);
-        return -1;
-    }
-
-    return sockfd;
-}
-
-#else
-#include <pims-socket.h>
-
-int _server_socket_init(const char *path, gid_t group, mode_t mode,
-        server_socket_client_closed_cb callback, void *user_data)
-{
-    return 0;
+       return write(fd, &cmd, sizeof(cmd));
 }
 
-int _client_socket_init(const char *path, const char *pid)
+int read_command(int fd, uint64_t *cmd)
 {
-    return 0;
+       uint64_t dummy;
+       int len = read(fd, &dummy, sizeof(dummy));
+       if (len == sizeof(dummy)) {
+               *cmd = dummy;
+       }
+       return len;
 }
 
-#endif
index 790e3d0..e3bdb16 100644 (file)
 #define __PIMS_SOCKET_H__
 
 #include <unistd.h>
+#include <stdint.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#ifdef _cplusplus
+#ifdef __cplusplus
 extern "C"
 {
 #endif
 
-typedef void (*server_socket_client_closed_cb)(const char *pid, void *user_data);
-int _server_socket_init(const char *path, gid_t group, mode_t mode,
-        server_socket_client_closed_cb callback, void *user_data);
-int _client_socket_init(const char *path, const char *pid);
+int socket_send(int fd, char *buf, int len);
+int socket_recv(int fd, void **buf, unsigned int len);
+int socket_send_data(int fd, char *buf, unsigned int len);
 
-#ifdef _cplusplus
+int write_command(int fd, const uint64_t cmd);
+int read_command(int fd, uint64_t *cmd);
+
+#ifdef __cplusplus
 }
 #endif
 
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
deleted file mode 100755 (executable)
index 7442d81..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
-PROJECT(pims_ipc_test C)
-
-####################################################################
-# Basic configuration                                              #
-####################################################################
-# Set ready to build
-SET(EXT_LIBS_DIRS "")
-SET(EXT_LIBS_DEFS "")
-SET(EXT_LIBS_LDFLAGS "")
-
-# Set external libraries
-SET(EXT_LIBS
-    E_GLIB
-)
-
-FOREACH(flag ${EXT_LIBS})
-    SET(EXT_LIBS_DIRS       ${EXT_LIBS_DIRS}    ${${flag}_INCLUDE_DIRS})
-    SET(EXT_LIBS_DEFS       ${EXT_LIBS_DEFS}    ${${flag}_CFLAGS_OTHER})
-    SET(EXT_LIBS_LDFLAGS    ${EXT_LIBS_LDFLAGS} ${${flag}_LDFLAGS})
-ENDFOREACH(flag)
-
-####################################################################
-# Build this project                                               #
-####################################################################
-
-# Set source
-SET(SRCS
-    ${CMAKE_CURRENT_SOURCE_DIR}/test.c
-)
-
-INCLUDE_DIRECTORIES(
-    ${CMAKE_SOURCE_DIR}/include
-    ${EXT_LIBS_DIRS}
-)
-
-ADD_DEFINITIONS(
-    ${EXT_LIBS_DEFS}
-)
-
-ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS})
-TARGET_LINK_LIBRARIES(${PROJECT_NAME} pims-ipc ${EXT_LIBS_LDFLAGS})
-INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR})
-
diff --git a/test/sock-test.c b/test/sock-test.c
deleted file mode 100644 (file)
index a18e6f2..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * PIMS IPC
- *
- * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#define NAME "dom_sock_test"
-
-#define REPEAT_COUNT    100
-//#define BUFFER_SIZE 1024*1024
-#define BUFFER_SIZE 1024
-
-#define PLUS_TIME(a, b, c) do {\
-    a.tv_sec = b.tv_sec + c.tv_sec;\
-    a.tv_usec = b.tv_usec + c.tv_usec;\
-    if (a.tv_usec >= 1000000) {\
-        a.tv_sec++;\
-        a.tv_usec -= 1000000;\
-    }\
-} while (0)
-
-#define MINUS_TIME(a, b, c) do {\
-    a.tv_sec = b.tv_sec - c.tv_sec;\
-    a.tv_usec = b.tv_usec - c.tv_usec;\
-    if (a.tv_usec < 0) {\
-        a.tv_sec--;\
-        a.tv_usec += 1000000;\
-    }\
-} while (0)
-
-
-static char buffer[BUFFER_SIZE+1] = {0,};
-
-void server_main()
-{
-    int sock, msgsock, rval;
-    struct sockaddr_un server;
-
-    sock = socket(AF_UNIX, SOCK_STREAM, 0);
-    if (sock < 0) {
-        perror("opening stream socket");
-        exit(1);
-    }
-
-    server.sun_family = AF_UNIX;
-    strcpy(server.sun_path, NAME);
-    if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) {
-        perror("binding stream socket");
-        exit(1);
-    }
-    printf("Socket has name %s\n", server.sun_path);
-    listen(sock, 5);
-    for (;;) {
-        msgsock = accept(sock, 0, 0);
-        if (msgsock == -1)
-            perror("accept");
-        else do {
-            if ((rval = read(msgsock, buffer, BUFFER_SIZE)) < 0)
-                perror("reading stream message");
-            else if (rval == 0)
-                printf("Ending connection\n");
-            else
-            {
-                if ((rval = write(msgsock, buffer, BUFFER_SIZE)) < 0)
-                    perror("writing stream message");
-
-            }
-        } while (rval > 0);
-        close(msgsock);
-    }
-    close(sock);
-    unlink(NAME);
-}
-
-void client_main()
-{
-    int i;
-    int sock;
-    struct sockaddr_un server;
-    struct timeval start_tv = {0, 0};
-    struct timeval end_tv = {0, 0};
-    struct timeval diff_tv = {0, 0};
-    struct timeval prev_sum_tv = {0, 0};
-    struct timeval sum_tv = {0, 0};
-    int count = 0;
-
-    sock = socket(AF_UNIX, SOCK_STREAM, 0);
-    if (sock < 0) {
-        perror("opening stream socket");
-        exit(1);
-    }
-    server.sun_family = AF_UNIX;
-    strcpy(server.sun_path, NAME);
-
-    for (i = 0; i < BUFFER_SIZE; i++)
-        buffer[i] = 'a';
-    buffer[i] = 0;
-
-    if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
-        close(sock);
-        perror("connecting stream socket");
-        exit(1);
-    }
-    for (i = 0; i < REPEAT_COUNT; i++)
-    {
-
-        gettimeofday(&start_tv, NULL);
-        if (write(sock, buffer, BUFFER_SIZE) < 0)
-            perror("writing on stream socket");
-        if (read(sock, buffer, BUFFER_SIZE) < 0)
-            perror("read on stream socket");
-        gettimeofday(&end_tv, NULL);
-        MINUS_TIME(diff_tv, end_tv, start_tv);
-        PLUS_TIME(sum_tv, diff_tv, prev_sum_tv);
-        prev_sum_tv = sum_tv;
-        count++;
-        printf("start[%lu:%lu] end[%lu:%lu] diff[%lu:%lu]\n",
-                start_tv.tv_sec, start_tv.tv_usec,
-                end_tv.tv_sec, end_tv.tv_usec,
-                diff_tv.tv_sec, diff_tv.tv_usec);
-
-    }
-    if (i == REPEAT_COUNT)
-    {
-        printf("sum[%lu:%lu] count[%d]\n",
-                sum_tv.tv_sec, sum_tv.tv_usec, count);
-        printf("avg[%lu:%lu]\n",
-                sum_tv.tv_sec / count, (sum_tv.tv_sec % count * 1000000 + sum_tv.tv_usec) / count);
-    }
-
-    close(sock);
-}
-
-int main(int argc, char *argv[])
-{
-    if (argc != 2)
-    {
-        printf("Usage: %s client|server\n", argv[0]);
-        return -1;
-    }
-    if (strcmp(argv[1], "client") == 0)
-    {
-        printf("client mode..\n");
-        client_main();
-    }
-    else if (strcmp(argv[1], "server") == 0)
-    {
-        printf("server mode..\n");
-        server_main();
-    }
-    else
-    {
-        printf("Usage: %s client|server\n", argv[0]);
-        return -1;
-    }
-    return 0;
-}
-
-
diff --git a/test/test.c b/test/test.c
deleted file mode 100644 (file)
index 74e0b8a..0000000
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * PIMS IPC
- *
- * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <glib.h>
-#include <pims-ipc.h>
-#include <pims-ipc-svc.h>
-#include <pims-ipc-data.h>
-
-#define THREAD_COUNT    1
-#define REPEAT_COUNT    100
-#define BUFFER_SIZE 1024
-#define PLUS_TIME(a, b, c) do {\
-    a.tv_sec = b.tv_sec + c.tv_sec;\
-    a.tv_usec = b.tv_usec + c.tv_usec;\
-    if (a.tv_usec >= 1000000) {\
-        a.tv_sec++;\
-        a.tv_usec -= 1000000;\
-    }\
-} while (0)
-
-#define MINUS_TIME(a, b, c) do {\
-    a.tv_sec = b.tv_sec - c.tv_sec;\
-    a.tv_usec = b.tv_usec - c.tv_usec;\
-    if (a.tv_usec < 0) {\
-        a.tv_sec--;\
-        a.tv_usec += 1000000;\
-    }\
-} while (0)
-
-typedef struct {
-    int thread_count;
-    int repeat_count;
-    int message_size;
-    pims_ipc_h ipc;
-} test_arg_t;
-
-static gboolean __is_async = FALSE;
-static gboolean __is_publish = FALSE;
-
-void test_function(pims_ipc_h ipc, pims_ipc_data_h indata, pims_ipc_data_h *outdata, void *userdata)
-{
-    unsigned int size = 0;
-    char *str = NULL;
-
-    if (indata)
-    {
-        str = (char*)pims_ipc_data_get(indata, &size);
-        if (!str)
-        {
-            printf("pims_ipc_data_get error\n");
-            return;
-        }
-#if 0
-        str = (char*)pims_ipc_data_get(indata, &size);
-        if (!str)
-        {
-            printf("pims_ipc_data_get error\n");
-            return;
-        }
-        printf("%s\n", str);
-        str = (char*)pims_ipc_data_get(indata, &size);
-        if (!str)
-        {
-            printf("pims_ipc_data_get error\n");
-            return;
-        }
-        printf("%s\n", str);
-#endif
-    }
-
-    if (str && outdata)
-    {
-        *outdata = pims_ipc_data_create(0);
-        if (!*outdata)
-        {
-            printf("pims_ipc_data_create error\n");
-            return;
-        }
-        if (pims_ipc_data_put(*outdata, str, strlen(str) + 1) != 0)
-        {
-            printf("pims_ipc_data_put error\n");
-            pims_ipc_data_destroy(*outdata);
-            *outdata = NULL;
-            return;
-        }
-#if 0
-        if (pims_ipc_data_put(*outdata, "welcome", strlen("welcome") + 1) != 0)
-        {
-            printf("pims_ipc_data_put error\n");
-            pims_ipc_data_destroy(*outdata);
-            *outdata = NULL;
-            return;
-        }
-        if (pims_ipc_data_put(*outdata, "to the jungle", strlen("to the jungle") + 1) != 0)
-        {
-            printf("pims_ipc_data_put error\n");
-            pims_ipc_data_destroy(*outdata);
-            *outdata = NULL;
-            return;
-        }
-#endif
-    }
-}
-
-static gboolean publish_callback(gpointer data)
-{
-    pims_ipc_data_h indata = NULL;
-
-    indata = pims_ipc_data_create(0);
-    if (!indata)
-    {
-        printf("pims_ipc_data_create error\n");
-        return false;
-    }
-    if (pims_ipc_data_put(indata, "publish test", strlen("publish test") + 1) != 0)
-    {
-        printf("pims_ipc_data_put error\n");
-        return false;
-    }
-    if (pims_ipc_svc_publish("test_module", "publish", indata) != 0)
-    {
-        printf("pims_ipc_svc_publish error\n");
-        return false;
-    }
-
-    if (indata)
-        pims_ipc_data_destroy(indata);
-
-    return true;
-}
-
-int server_main()
-{
-
-    pims_ipc_svc_init("pims-ipc-test", getuid(), 0660);
-
-    if (pims_ipc_svc_register("test_module", "test_function", test_function, NULL) != 0)
-    {
-        printf("pims_ipc_svc_register error\n");
-        return -1;
-    }
-
-    if (__is_publish)
-    {
-        pims_ipc_svc_init_for_publish("pims-ipc-pub-test", getuid(), 0660);
-        g_timeout_add_seconds(3, publish_callback, NULL);
-    }
-
-    pims_ipc_svc_run_main_loop(NULL);
-
-    pims_ipc_svc_deinit();
-
-    return 0;
-}
-
-static gboolean call_async_idler_callback(gpointer data);
-
-static void call_async_callback(pims_ipc_h ipc, pims_ipc_data_h data_out, void *userdata)
-{
-    unsigned int size = 0;
-    char *str = NULL;
-
-    printf("(%x) call_async_callback(%p)", (unsigned int)pthread_self(), ipc);
-    if (data_out)
-    {
-        str = (char*)pims_ipc_data_get(data_out, &size);
-        if (!str)
-        {
-            printf("pims_ipc_data_get error\n");
-        }
-        else
-        {
-            printf("pims_ipc_data_get(%s) success\n", str);
-        }
-    }
-
-    sleep(1);
-
-    pims_ipc_data_h indata = NULL;
-    pims_ipc_data_h outdata = NULL;
-
-    indata = pims_ipc_data_create(0);
-    if (!indata)
-    {
-        printf("pims_ipc_data_create error\n");
-        return;
-    }
-    if (pims_ipc_data_put(indata, "hello world", strlen("hello world") + 1) != 0)
-    {
-        printf("pims_ipc_data_put error\n");
-        return;
-    }
-
-    if (pims_ipc_call(ipc, "test_module", "test_function", indata, &outdata) != 0)
-    {
-        printf("pims_ipc_call error\n");
-        return;
-    }
-    
-    if (indata)
-        pims_ipc_data_destroy(indata);
-    if (outdata)
-        pims_ipc_data_destroy(outdata);
-
-    sleep(1);
-
-    call_async_idler_callback(ipc);
-}
-
-static gboolean call_async_idler_callback(gpointer data)
-{
-    pims_ipc_data_h indata = NULL;
-    pims_ipc_data_h outdata = NULL;
-    pims_ipc_h ipc = data;
-    bool ret = false;
-
-    indata = pims_ipc_data_create(0);
-    if (!indata)
-    {
-        printf("pims_ipc_data_create error\n");
-        return FALSE;
-    }
-    if (pims_ipc_data_put(indata, "hello world", strlen("hello world") + 1) != 0)
-    {
-        printf("pims_ipc_data_put error\n");
-        return FALSE;
-    }
-
-    printf("(%x) call_async_idler_callback(%p)\n", (unsigned int)pthread_self(), ipc);
-    ret = pims_ipc_is_call_in_progress(ipc);
-    printf("(%x) before async call : pims_ipc_is_call_in_progress(%p) = %d\n", (unsigned int)pthread_self(), ipc, ret);
-    if (pims_ipc_call_async(ipc, "test_module", "test_function", indata, call_async_callback, NULL) != 0)
-    {
-        printf("pims_ipc_call_async error\n");
-        return FALSE;
-    }
-    ret = pims_ipc_is_call_in_progress(ipc);
-    printf("(%x) after async call : pims_ipc_is_call_in_progress(%p) = %d\n", (unsigned int)pthread_self(), ipc, ret);
-
-    if (pims_ipc_call(ipc, "test_module", "test_function", indata, &outdata) != 0)
-    {
-        printf("pims_ipc_call error during async-call\n");
-        return FALSE;
-    }
-    if (indata)
-        pims_ipc_data_destroy(indata);
-    if (outdata)
-        pims_ipc_data_destroy(outdata);
-
-    return FALSE;
-}
-
-int client_main(pims_ipc_h ipc, int repeat_count, int message_size)
-{
-    pims_ipc_data_h indata = NULL;
-    pims_ipc_data_h outdata = NULL;
-    int retval = -1;
-    unsigned int size = 0;
-    char *str = NULL;
-    int i = 0;
-    struct timeval start_tv = {0, 0};
-    struct timeval end_tv = {0, 0};
-    struct timeval diff_tv = {0, 0};
-    struct timeval prev_sum_tv = {0, 0};
-    struct timeval sum_tv = {0, 0};
-    int count = 0;
-    
-    char *buffer = g_malloc0(message_size + 1);
-
-    for (i = 0; i < message_size; i++)
-        buffer[i] = 'a';
-    buffer[i] = 0;
-
-    for (i = 0; i < repeat_count; i++)
-    {
-        gettimeofday(&start_tv, NULL);
-        indata = pims_ipc_data_create(0);
-        if (!indata)
-        {
-            printf("pims_ipc_data_create error\n");
-            break;
-        }
-        if (pims_ipc_data_put(indata, buffer, strlen(buffer) + 1) != 0)
-        {
-            printf("pims_ipc_data_put error\n");
-            break;
-        }
-#if 0
-        if (pims_ipc_data_put(indata, "hellow", strlen("hellow") + 1) != 0)
-        {
-            printf("pims_ipc_data_put error\n");
-            break;
-        }
-        if (pims_ipc_data_put(indata, "world", strlen("world") + 1) != 0)
-        {
-            printf("pims_ipc_data_put error\n");
-            break;
-        }
-#endif
-        if (pims_ipc_call(ipc, "test_module", "test_function", indata, &outdata) != 0)
-        {
-            printf("pims_ipc_call error\n");
-            break;
-        }
-        pims_ipc_data_destroy(indata);
-        indata = NULL;
-        if (outdata)
-        {
-            str = (char*)pims_ipc_data_get(outdata, &size);
-            if (!str)
-            {
-                printf("pims_ipc_data_get error\n");
-                break;
-            }
-#if 0
-            str = (char*)pims_ipc_data_get(outdata, &size);
-            if (!str)
-            {
-                printf("pims_ipc_data_get error\n");
-                break;
-            }
-            printf("%s\n", str);
-            str = (char*)pims_ipc_data_get(outdata, &size);
-            if (!str)
-            {
-                printf("pims_ipc_data_get error\n");
-                break;
-            }
-            printf("%s\n", str);
-#endif
-
-            pims_ipc_data_destroy(outdata);
-            outdata = NULL;
-        }
-        gettimeofday(&end_tv, NULL);
-        MINUS_TIME(diff_tv, end_tv, start_tv);
-        PLUS_TIME(sum_tv, diff_tv, prev_sum_tv);
-        prev_sum_tv = sum_tv;
-        count++;
-        printf("(%x) start[%lu:%lu] end[%lu:%lu] diff[%lu:%lu]\n",
-                (unsigned int)pthread_self(),
-                start_tv.tv_sec, start_tv.tv_usec,
-                end_tv.tv_sec, end_tv.tv_usec,
-                diff_tv.tv_sec, diff_tv.tv_usec);
-    }
-
-    if (i == repeat_count)
-    {
-        printf("(%x) sum[%lu:%lu] count[%d]\n",
-                (unsigned int)pthread_self(),
-                sum_tv.tv_sec, sum_tv.tv_usec, count);
-        printf("(%x) avg[%lu:%lu]\n",
-                (unsigned int)pthread_self(),
-                sum_tv.tv_sec / count, (sum_tv.tv_sec % count * 1000000 + sum_tv.tv_usec) / count);
-        retval = 0;
-    }
-
-    if (indata)
-        pims_ipc_data_destroy(indata);
-    if (outdata)
-        pims_ipc_data_destroy(outdata);
-
-    if (__is_async)
-        g_idle_add(call_async_idler_callback, ipc);
-
-    return retval;
-}
-
-static void* __worker_task(void *arg)
-{
-    test_arg_t *_arg = arg;
-    printf("(%x) worker %p, %d, %d\n", (unsigned int)pthread_self(), _arg->ipc, _arg->repeat_count, _arg->message_size);
-    client_main(_arg->ipc, _arg->repeat_count, _arg->message_size);
-    printf("worker task has been done\n");
-    return NULL;
-}
-
-static gboolean __launch_worker(gpointer data)
-{
-    test_arg_t *_arg = data;
-    int i = 0;
-    GThread **worker_threads = NULL;
-    gboolean joinable = FALSE;
-
-    worker_threads = g_new0(GThread*, _arg->thread_count);
-    if (!__is_async && !__is_publish)
-        joinable = TRUE;
-
-    for (i = 0; i < _arg->thread_count; i++)
-    {
-        pims_ipc_h ipc = NULL;
-        test_arg_t *arg = g_new0(test_arg_t, 1);
-        arg->repeat_count = _arg->repeat_count;
-        arg->message_size = _arg->message_size;
-        ipc = pims_ipc_create("pims-ipc-test");
-        if (!ipc)
-        {
-            printf("pims_ipc_create error\n");
-            return -1;
-        }
-        arg->ipc = ipc;
-
-        worker_threads[i] = g_thread_create(__worker_task, (void*)arg, joinable, NULL);
-    }
-
-    if (!__is_async && !__is_publish)
-    {
-        for (i = 0; i < _arg->thread_count; i++)
-        {
-            g_thread_join(worker_threads[i]);
-        }
-    }
-
-    g_free(worker_threads);
-
-    return FALSE;
-}
-
-static void subscribe_callback(pims_ipc_h ipc, pims_ipc_data_h data, void *userdata)
-{
-    unsigned int size = 0;
-    char *str = NULL;
-
-    printf("(%x) subscribe_callback(%p)", (unsigned int)pthread_self(), ipc);
-    if (data)
-    {
-        str = (char*)pims_ipc_data_get(data, &size);
-        if (!str)
-        {
-            printf("pims_ipc_data_get error\n");
-        }
-        else
-        {
-            printf("pims_ipc_data_get(%s) success\n", str);
-        }
-    }
-}
-
-static void __print_usage(char *prog)
-{
-    printf("Usage: %s [-r <repeat count> -s <message size> -t <thread count> -a] client|server \n", prog);
-}
-
-int main(int argc, char *argv[])
-{
-    int repeat_count = REPEAT_COUNT;
-    int message_size = BUFFER_SIZE;
-    int thread_count = THREAD_COUNT;
-    int c = 0;
-    test_arg_t arg;
-
-    opterr = 0;
-    optind = 0;
-
-    g_thread_init(NULL);
-
-    while ((c = getopt(argc, argv, "r:s:t:ap")) != -1)
-    {
-        switch (c)
-        {
-            case 'r':
-                repeat_count = atoi(optarg);
-                break;
-            case 's':
-                message_size = atoi(optarg);
-                break;
-            case 't':
-                thread_count = atoi(optarg);
-                break;
-            case 'a':
-                __is_async = TRUE;
-                break;
-            case 'p':
-                __is_publish = TRUE;
-                break;
-            case '?':
-                __print_usage(argv[0]);
-                return -1;
-        }
-            
-    }
-
-    if (argc - optind != 1)
-    {
-        __print_usage(argv[0]);
-        return -1;
-    }
-
-    if (strcmp(argv[optind], "client") == 0)
-    {
-        // async call 
-        GMainLoop* main_loop = g_main_loop_new(NULL, FALSE);
-
-        printf("client mode.. with %d threads\n", thread_count);
-
-        if (__is_publish)
-        {
-            pims_ipc_h ipc = NULL;
-            ipc = pims_ipc_create_for_subscribe("pims-ipc-pub-test");
-            if (!ipc)
-            {
-                printf("pims_ipc_create_for_subscribe error\n");
-                return -1;
-            }
-            pims_ipc_destroy_for_subscribe(ipc);
-            ipc = pims_ipc_create_for_subscribe("pims-ipc-pub-test");
-            if (!ipc)
-            {
-                printf("pims_ipc_create_for_subscribe error\n");
-                return -1;
-            }
-            if (pims_ipc_subscribe(ipc, "test_module", "publish", subscribe_callback, NULL) != 0) 
-            {
-                printf("pims_ipc_subscribe error\n");
-                return -1;
-            }
-            if (pims_ipc_unsubscribe(ipc, "test_module", "publish") != 0) 
-            {
-                printf("pims_ipc_unsubscribe error\n");
-                return -1;
-            }
-            if (pims_ipc_subscribe(ipc, "test_module", "publish", subscribe_callback, NULL) != 0) 
-            {
-                printf("pims_ipc_subscribe error\n");
-                return -1;
-            }
-        }
-
-        if (thread_count <= 1)
-        {
-            pims_ipc_h ipc = NULL;
-            ipc = pims_ipc_create("pims-ipc-test");
-            if (!ipc)
-            {
-                printf("pims_ipc_create error\n");
-                return -1;
-            }
-
-            client_main(ipc, repeat_count, message_size);
-        }
-        else
-        {
-            arg.message_size = message_size; 
-            arg.repeat_count = repeat_count; 
-            arg.thread_count = thread_count; 
-            if (__is_async || __is_publish)
-                g_idle_add(__launch_worker, &arg);
-            else
-                __launch_worker(&arg);
-        }
-
-        if (__is_async || __is_publish)
-            g_main_loop_run(main_loop);
-    }
-    else if (strcmp(argv[optind], "server") == 0)
-    {
-        printf("server mode..\n");
-        server_main();
-    }
-    else
-    {
-        __print_usage(argv[0]);
-        return -1;
-    }
-    return 0;
-}