From: jk7744.park Date: Sun, 1 Feb 2015 04:49:15 +0000 (+0900) Subject: tizen 2.3 release X-Git-Tag: submit/tizen_2.3/20150202.063413^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Ftizen_2.3;p=framework%2Fpim%2Fpims-ipc.git tizen 2.3 release --- diff --git a/CMakeLists.txt b/CMakeLists.txt index ef6d75c..21863e1 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,17 +15,15 @@ SET(EXEC_PREFIX "\${prefix}") SET(INCLUDEDIR "\${prefix}/${DEST_INCLUDE_DIR}") SET(VERSION_MAJOR 0) -SET(VERSION "${VERSION_MAJOR}.0.30") +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}\"") @@ -52,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) diff --git a/include/pims-ipc-data.h b/include/pims-ipc-data.h index 5137cca..8d664de 100644 --- a/include/pims-ipc-data.h +++ b/include/pims-ipc-data.h @@ -31,19 +31,9 @@ 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); +int pims_ipc_data_put(pims_ipc_data_h data, void *buf, unsigned int size); + #ifdef __cplusplus } diff --git a/include/pims-ipc-svc.h b/include/pims-ipc-svc.h index d384b00..918d105 100644 --- a/include/pims-ipc-svc.h +++ b/include/pims-ipc-svc.h @@ -38,6 +38,8 @@ int pims_ipc_svc_publish(char *module, char *event, pims_ipc_data_h data); void pims_ipc_svc_run_main_loop(GMainLoop* main_loop); +void pims_ipc_svc_set_client_disconnected_cb(pims_ipc_svc_client_disconnected_cb callback, void *userdata); + #ifdef __cplusplus } #endif diff --git a/include/pims-ipc-types.h b/include/pims-ipc-types.h index 54047eb..9ea5390 100644 --- a/include/pims-ipc-types.h +++ b/include/pims-ipc-types.h @@ -20,7 +20,6 @@ #ifndef __PIMS_IPC_TYPES_H__ #define __PIMS_IPC_TYPES_H__ -#include #include #include @@ -50,11 +49,14 @@ 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 } #endif diff --git a/packaging/pims-ipc.spec b/packaging/pims-ipc.spec index 6e260a9..48237d6 100644 --- a/packaging/pims-ipc.spec +++ b/packaging/pims-ipc.spec @@ -1,6 +1,6 @@ Name: pims-ipc Summary: library for PIMs IPC -Version: 0.0.30 +Version: 0.1.6 Release: 1 Group: System/Libraries License: Apache-2.0 @@ -10,7 +10,6 @@ BuildRequires: cmake BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(libsystemd-daemon) -BuildRequires: pkgconfig(libzmq) %description library for PIMs IPC @@ -28,12 +27,14 @@ library for PIMs IPC (developement files) %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} @@ -51,5 +52,4 @@ cp LICENSE.APLv2 %{buildroot}/usr/share/license/%{name} %defattr(-,root,root,-) %{_includedir}/pims-ipc/*.h %{_libdir}/*.so -%{_libdir}/pims_ipc_test %{_libdir}/pkgconfig/pims-ipc.pc diff --git a/pims-ipc.pc.in b/pims-ipc.pc.in index 7528eb1..20e62ee 100755 --- a/pims-ipc.pc.in +++ b/pims-ipc.pc.in @@ -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} diff --git a/src/pims-debug.h b/src/pims-debug.h index 8fcd384..d8eaa84 100644 --- a/src/pims-debug.h +++ b/src/pims-debug.h @@ -20,48 +20,25 @@ #ifndef __PIMS_DEBUG_H__ #define __PIMS_DEBUG_H__ -#ifndef _NON_SLP -#include -#endif #include +#define LOG_TAG "PIMS_IPC" +#include + #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,12 +47,19 @@ 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 } diff --git a/src/pims-internal.h b/src/pims-internal.h index ad2279e..fbc2b42 100644 --- a/src/pims-internal.h +++ b/src/pims-internal.h @@ -20,8 +20,6 @@ #ifndef __PIMS_INTERNAL_H__ #define __PIMS_INTERNAL_H__ -#include - #ifdef __cplusplus extern "C" { @@ -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,33 +38,16 @@ 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; -} +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 } diff --git a/src/pims-ipc-data-internal.h b/src/pims-ipc-data-internal.h new file mode 100644 index 0000000..ba947c0 --- /dev/null +++ b/src/pims-ipc-data-internal.h @@ -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 + +#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__ */ diff --git a/src/pims-ipc-data.c b/src/pims-ipc-data.c index fa0ee5d..9f1c487 100644 --- a/src/pims-ipc-data.c +++ b/src/pims-ipc-data.c @@ -24,480 +24,186 @@ #include #include -#include -#include -#include - -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; -} diff --git a/src/pims-ipc-svc.c b/src/pims-ipc-svc.c index ef48e0c..0c2fcd8 100644 --- a/src/pims-ipc-svc.c +++ b/src/pims-ipc-svc.c @@ -24,1238 +24,1481 @@ #include #include #include -#include +#include // pollfds +#include //fcntl +#include +#include + #include +#include // sockaddr_un +#include // ioctl +#include // epoll +#include // eventfd +#include //socket +#include -#include -#include -#include -#include -#include +#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; +} + + diff --git a/src/pims-ipc.c b/src/pims-ipc.c index 8dce7f4..7a37a85 100644 --- a/src/pims-ipc.c +++ b/src/pims-ipc.c @@ -24,851 +24,988 @@ #include #include #include -#include #include +#include // pollfds +#include // sockaddr_un +#include // ioctl +#include //socket +#include +#include // epoll +#include // eventfd +#include -#include -#include -#include -#include -#include +#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; - 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; + 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; +} - if (__gsequence_no == 0xffffffff) - __gsequence_no = (unsigned int)time(NULL); - else - __gsequence_no++; - return __gsequence_no; +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->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, __get_global_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; } + diff --git a/src/pims-socket.c b/src/pims-socket.c index bf02682..eff803d 100644 --- a/src/pims-socket.c +++ b/src/pims-socket.c @@ -16,8 +16,6 @@ * limitations under the License. */ - -#ifndef _NON_SLP #include #include #include @@ -25,262 +23,150 @@ #include #include #include -#include -#include -#include -#include +#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 - -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 diff --git a/src/pims-socket.h b/src/pims-socket.h index 5e1072e..e3bdb16 100644 --- a/src/pims-socket.h +++ b/src/pims-socket.h @@ -21,6 +21,7 @@ #define __PIMS_SOCKET_H__ #include +#include #include #include @@ -29,10 +30,12 @@ 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); + +int write_command(int fd, const uint64_t cmd); +int read_command(int fd, uint64_t *cmd); #ifdef __cplusplus } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100755 index 7442d81..0000000 --- a/test/CMakeLists.txt +++ /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 index a18e6f2..0000000 --- a/test/sock-test.c +++ /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 -#include -#include -#include -#include - -#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 index 74e0b8a..0000000 --- a/test/test.c +++ /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 -#include -#include -#include -#include -#include -#include -#include - -#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 -s -t -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; -}