connection recovery 55/47355/3
authorGukhwan Cho <gh78.cho@samsung.com>
Wed, 2 Sep 2015 12:40:30 +0000 (21:40 +0900)
committerGukhwan Cho <gh78.cho@samsung.com>
Thu, 3 Sep 2015 06:35:36 +0000 (15:35 +0900)
Change-Id: I94ee99a8a15ad635c51614fba2d1ecc59d012ccf
Signed-off-by: Gukhwan Cho <gh78.cho@samsung.com>
12 files changed:
client/ctsvc_client_ipc.c
client/ctsvc_client_ipc.h
client/ctsvc_client_noti.c
client/ctsvc_client_service_helper.c
client/ctsvc_client_service_helper.h
common/ctsvc_inotify.c
common/ctsvc_inotify.h
common/ctsvc_notify.h
res/.CONTACTS_SVC_IPC_READY [new file with mode: 0644]
server/ctsvc_notification.c
server/ctsvc_notification.h
server/ctsvc_server.c

index a052f72..aa8530a 100644 (file)
  */
 
 #include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <glib.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <glib.h>
 #include <pims-ipc-data.h>
 
 #include "ctsvc_client_ipc.h"
+#include "ctsvc_client_service_helper.h"
 
 #include "ctsvc_internal.h"
 #include "ctsvc_list.h"
 #include "ctsvc_mutex.h"
 #include "ctsvc_handle.h"
 
-static __thread pims_ipc_h __contacts_ipc = NULL;
-static pims_ipc_h __contacts_global_ipc = NULL;
+#define CTS_STR_SHORT_LEN 1024 //short sql string length
 
-int ctsvc_ipc_connect_on_thread(contacts_h contact)
-{
-       int ret = CONTACTS_ERROR_NONE;
-       pims_ipc_data_h outdata = NULL;
+struct ctsvc_ipc_s {
+       pims_ipc_h ipc;
+       GList *list_handle;
+};
 
-       // ipc create
-       if (__contacts_ipc == NULL) {
-               char sock_file[CTSVC_PATH_MAX_LEN] = {0};
-               snprintf(sock_file, sizeof(sock_file), CTSVC_SOCK_PATH"/.%s", getuid(), CTSVC_IPC_SERVICE);
-               __contacts_ipc = pims_ipc_create(sock_file);
-               if (__contacts_ipc == NULL) {
-                       if (errno == EACCES) {
-                               CTS_ERR("pims_ipc_create() Fail(%d)", CONTACTS_ERROR_PERMISSION_DENIED);
-                               return CONTACTS_ERROR_PERMISSION_DENIED;
-                       }
-                       else {
-                               CTS_ERR("pims_ipc_create() Fail(%d)", CONTACTS_ERROR_IPC_NOT_AVALIABLE);
-                               return CONTACTS_ERROR_IPC_NOT_AVALIABLE;
-                       }
-               }
-       }
+static GHashTable *_ctsvc_ipc_table = NULL;
+static bool _ctsvc_ipc_disconnected = false;
+static int disconnected_cb_count = 0;
+
+static inline void _ctsvc_ipc_get_pid_str(char *buf, int buf_size)
+{
+       pid_t pid = getpid();
+       snprintf(buf, buf_size, "%d", (unsigned int)pid);
+}
 
+static inline void _ctsvc_ipc_get_tid_str(char *buf, int buf_size)
+{
+       pthread_t tid = pthread_self();
+       snprintf(buf, buf_size, "%d", (unsigned int)tid);
+}
 
-       // ipc call
-       if (pims_ipc_call(__contacts_ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_CONNECT, NULL, &outdata) != 0) {
-               CTS_ERR("pims_ipc_call Fail");
-               ret = CONTACTS_ERROR_IPC;
-               goto DATA_FREE;
+static struct ctsvc_ipc_s* _ctsvc_get_ipc_data()
+{
+       struct ctsvc_ipc_s *ipc_data = NULL;
+       char ipc_key[CTS_STR_SHORT_LEN] = {0};
+       RETVM_IF(NULL == _ctsvc_ipc_table, NULL, "contacts not connected");
+
+       _ctsvc_ipc_get_tid_str(ipc_key, sizeof(ipc_key));
+       ipc_data = g_hash_table_lookup(_ctsvc_ipc_table, ipc_key);
+       if (NULL == ipc_data) {
+               _ctsvc_ipc_get_pid_str(ipc_key, sizeof(ipc_key));
+               ipc_data = g_hash_table_lookup(_ctsvc_ipc_table, ipc_key);
        }
+       return ipc_data;
+}
 
-       if (outdata) {
-               unsigned int size = 0;
-               ret = *(int*) pims_ipc_data_get(outdata,&size);
+static pims_ipc_h _ctsvc_get_ipc_handle()
+{
+       struct ctsvc_ipc_s *ipc_data = _ctsvc_get_ipc_data();
+       if (ipc_data)
+               return ipc_data->ipc;
 
-               pims_ipc_data_destroy(outdata);
+       return NULL;
+}
 
-               if (ret != CONTACTS_ERROR_NONE) {
-                       CTS_ERR("ctsvc_ipc_server_connect return(%d)", ret);
-                       goto DATA_FREE;
-               }
-       }
+bool ctsvc_ipc_is_busy()
+{
+       bool ret = false;
 
-       return ret;
+       pims_ipc_h ipc = _ctsvc_get_ipc_handle();
+       if (NULL == ipc) {
+               CTS_ERR("_ctsvc_get_ipc_handle() return NULL");
+               return false;
+       }
 
-DATA_FREE:
-       pims_ipc_destroy(__contacts_ipc);
-       __contacts_ipc = NULL;
+       ret = pims_ipc_is_call_in_progress(ipc);
+       if (ret)
+               CTS_ERR("global ipc channel is busy.");
 
        return ret;
 }
 
-int ctsvc_ipc_disconnect_on_thread(contacts_h contact, int connection_count)
+static int _ctsvc_ipc_create(pims_ipc_h *p_ipc)
 {
-       int ret = CONTACTS_ERROR_NONE;
+       int ret;
+       pims_ipc_data_h indata = NULL;
        pims_ipc_data_h outdata = NULL;
 
-       RETVM_IF(__contacts_ipc == NULL, CONTACTS_ERROR_IPC, "contacts not connected");
+       char sock_file[CTSVC_PATH_MAX_LEN] = {0};
+       snprintf(sock_file, sizeof(sock_file), CTSVC_SOCK_PATH"/.%s", getuid(), CTSVC_IPC_SERVICE);
+       pims_ipc_h ipc = pims_ipc_create(sock_file);
+       if (NULL == ipc) {
+               if (errno == EACCES) {
+                       CTS_ERR("pims_ipc_create() Failed(%d)", CONTACTS_ERROR_PERMISSION_DENIED);
+                       return CONTACTS_ERROR_PERMISSION_DENIED;
+               }
+               else {
+                       CTS_ERR("pims_ipc_create() Failed(%d)", CONTACTS_ERROR_IPC_NOT_AVALIABLE);
+                       return CONTACTS_ERROR_IPC_NOT_AVALIABLE;
+               }
+       }
 
-       if (pims_ipc_call(__contacts_ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_DISCONNECT, NULL, &outdata) != 0) {
-               CTS_ERR("pims_ipc_call Fail");
-               return CONTACTS_ERROR_IPC;
+       *p_ipc = ipc;
+       return CONTACTS_ERROR_NONE;
+
+       /* ipc call */
+       if (pims_ipc_call(ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_CONNECT, indata, &outdata) != 0) {
+               CTS_ERR("pims_ipc_call failed");
+               pims_ipc_data_destroy(indata);
+               ret = CONTACTS_ERROR_IPC;
+               goto DATA_FREE;
        }
 
        if (outdata) {
                unsigned int size = 0;
                ret = *(int*) pims_ipc_data_get(outdata,&size);
-               pims_ipc_data_destroy(outdata);
 
-               if (ret != CONTACTS_ERROR_NONE)
-                       CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc didn't destroyed!!!(%d)", ret);
+               pims_ipc_data_destroy(outdata);
 
-               if (1 == connection_count) {
-                       pims_ipc_destroy(__contacts_ipc);
-                       __contacts_ipc = NULL;
+               if (ret != CONTACTS_ERROR_NONE) {
+                       CTS_ERR("ctsvc_ipc_server_connect return(%d)", ret);
+                       goto DATA_FREE;
                }
        }
-       else {
-               CTS_ERR("pims_ipc_call out data is NULL");
-               return CONTACTS_ERROR_IPC;
-       }
-
+       *p_ipc = ipc;
+       return CONTACTS_ERROR_NONE;
+DATA_FREE:
+       pims_ipc_destroy(ipc);
        return ret;
 }
 
-pims_ipc_h ctsvc_get_ipc_handle()
+static void _ctsvc_ipc_data_free(gpointer p)
 {
-       if (__contacts_ipc == NULL) {
-               if (__contacts_global_ipc == NULL) {
-                       CTS_ERR("IPC haven't been initialized yet.");
-                       return NULL;
-               }
-               CTS_DBG("fallback to global ipc channel");
-               return __contacts_global_ipc;
-       }
+       struct ctsvc_ipc_s *ipc_data = p;
+       if (NULL == ipc_data)
+               return;
+
+       if (ipc_data->ipc)
+               pims_ipc_destroy(ipc_data->ipc);
 
-       return __contacts_ipc;
+       g_list_free(ipc_data->list_handle);
+
+       free(ipc_data);
 }
 
-bool ctsvc_ipc_is_busy()
+static int _ctsvc_ipc_connect(contacts_h contact, pims_ipc_h ipc)
 {
-       bool ret = false;
+       int ret;
+       pims_ipc_data_h outdata = NULL;
+       pims_ipc_data_h indata = NULL;
 
-       if (__contacts_ipc != NULL) {
-               ret = pims_ipc_is_call_in_progress(__contacts_ipc);
-               if (ret)
-                       CTS_ERR("thread local ipc channel is busy.");
+       /* Access control : put cookie to indata */
+       indata = pims_ipc_data_create(0);
+       if (indata == NULL) {
+               CTS_ERR("pims_ipc_data_create() return NULL");
+               return CONTACTS_ERROR_OUT_OF_MEMORY;
        }
-       else {
-               ret = pims_ipc_is_call_in_progress(__contacts_global_ipc);
-               if (ret)
-                       CTS_ERR("global ipc channel is busy.");
+
+       ret = ctsvc_ipc_marshal_handle(contact, indata);
+       if (CONTACTS_ERROR_NONE != ret) {
+               CTS_ERR("ctsvc_ipc_marshal_handle Fail(%d)", ret);
+               pims_ipc_data_destroy(indata);
+               return ret;
        }
 
+       /* ipc call */
+       if (pims_ipc_call(ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_CONNECT, indata, &outdata) != 0) {
+               CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc_call failed");
+               pims_ipc_data_destroy(indata);
+               return CONTACTS_ERROR_IPC;
+       }
+       pims_ipc_data_destroy(indata);
+
+       if (outdata) {
+               ctsvc_ipc_unmarshal_int(outdata, &ret);
+               pims_ipc_data_destroy(outdata);
+               RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_ipc_server_connect return(%d)", ret);
+       }
        return ret;
 }
 
 int ctsvc_ipc_connect(contacts_h contact)
 {
        int ret = CONTACTS_ERROR_NONE;
-       pims_ipc_data_h outdata = NULL;
+       struct ctsvc_ipc_s *ipc_data = NULL;
+       char ipc_key[CTS_STR_SHORT_LEN] = {0};
 
-       // ipc create
-       if (__contacts_global_ipc == NULL) {
-               char sock_file[CTSVC_PATH_MAX_LEN] = {0};
-               snprintf(sock_file, sizeof(sock_file), CTSVC_SOCK_PATH"/.%s", getuid(), CTSVC_IPC_SERVICE);
-               __contacts_global_ipc = pims_ipc_create(sock_file);
-               if (__contacts_global_ipc == NULL) {
-                       if (errno == EACCES) {
-                               CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc_create() Fail(%d)", CONTACTS_ERROR_PERMISSION_DENIED);
-                               return CONTACTS_ERROR_PERMISSION_DENIED;
-                       }
-                       else {
-                               CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc_create() Fail(%d)", CONTACTS_ERROR_IPC_NOT_AVALIABLE);
-                               return CONTACTS_ERROR_IPC_NOT_AVALIABLE;
-                       }
-               }
-       }
+       RETV_IF(_ctsvc_ipc_disconnected, CONTACTS_ERROR_IPC_NOT_AVALIABLE);
 
-       /* ipc call */
-       if (pims_ipc_call(__contacts_global_ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_CONNECT, NULL, &outdata) != 0) {
-               CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc_call Fail");
-               ret = CONTACTS_ERROR_IPC;
-               goto DATA_FREE;
-       }
+       _ctsvc_ipc_get_tid_str(ipc_key, sizeof(ipc_key));
 
-       if (outdata) {
-               unsigned int size = 0;
-               ret = *(int*) pims_ipc_data_get(outdata,&size);
-               pims_ipc_data_destroy(outdata);
+       if (NULL == _ctsvc_ipc_table)
+               _ctsvc_ipc_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _ctsvc_ipc_data_free);
+       else
+               ipc_data = g_hash_table_lookup(_ctsvc_ipc_table, ipc_key);
 
-               if (ret != CONTACTS_ERROR_NONE) {
-                       CTS_ERR("ctsvc_ipc_server_connect return(%d)", ret);
-                       goto DATA_FREE;
+       if (NULL == ipc_data) {
+               ipc_data = calloc(1, sizeof(struct ctsvc_ipc_s));
+               ret = _ctsvc_ipc_create(&(ipc_data->ipc));
+               if (CONTACTS_ERROR_NONE != ret) {
+                       _ctsvc_ipc_data_free(ipc_data);
+                       return ret;
                }
+               g_hash_table_insert(_ctsvc_ipc_table, strdup(ipc_key), ipc_data);
        }
+       _ctsvc_ipc_connect(contact, ipc_data->ipc);
+       ipc_data->list_handle = g_list_append(ipc_data->list_handle, contact);
 
-       return ret;
-
-DATA_FREE:
-       pims_ipc_destroy(__contacts_global_ipc);
-       __contacts_global_ipc = NULL;
-       return ret;
+       return CONTACTS_ERROR_NONE;
 }
 
 
 int ctsvc_ipc_disconnect(contacts_h contact, int connection_count)
 {
        int ret = CONTACTS_ERROR_NONE;
+       char ipc_key[CTS_STR_SHORT_LEN] = {0};
+       struct ctsvc_ipc_s *ipc_data = NULL;
        pims_ipc_data_h outdata = NULL;
+       pims_ipc_data_h indata = NULL;
 
-       RETVM_IF(__contacts_global_ipc == NULL, CONTACTS_ERROR_IPC, "[GLOBAL_IPC_CHANNEL] contacts not connected");
+       RETV_IF(_ctsvc_ipc_disconnected, CONTACTS_ERROR_IPC_NOT_AVALIABLE);
+       RETVM_IF(NULL == _ctsvc_ipc_table, CONTACTS_ERROR_IPC, "contacts not connected");
 
-       if (pims_ipc_call(__contacts_global_ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_DISCONNECT, NULL, &outdata) != 0) {
-               CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc_call Fail");
+       _ctsvc_ipc_get_tid_str(ipc_key, sizeof(ipc_key));
+
+       ipc_data = g_hash_table_lookup(_ctsvc_ipc_table, ipc_key);
+       RETVM_IF(ipc_data == NULL, CONTACTS_ERROR_IPC, "contacts not connected");
+
+       indata = pims_ipc_data_create(0);
+       if (indata == NULL) {
+               CTS_ERR("ipc data created fail!");
+               return CONTACTS_ERROR_OUT_OF_MEMORY;
+       }
+
+       ret = ctsvc_ipc_marshal_handle(contact, indata);
+       RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_ipc_marshal_handle() Fail(%d)", ret);
+
+       if (pims_ipc_call(ipc_data->ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_DISCONNECT, indata, &outdata) != 0) {
+               pims_ipc_data_destroy(indata);
+               CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc_call failed");
                return CONTACTS_ERROR_IPC;
        }
 
        if (outdata) {
-               unsigned int size = 0;
-               ret = *(int*) pims_ipc_data_get(outdata,&size);
+               ctsvc_ipc_unmarshal_int(outdata, &ret);
                pims_ipc_data_destroy(outdata);
 
                if (ret != CONTACTS_ERROR_NONE) {
@@ -227,8 +275,7 @@ int ctsvc_ipc_disconnect(contacts_h contact, int connection_count)
                }
 
                if (1 == connection_count) {
-                       pims_ipc_destroy(__contacts_global_ipc);
-                       __contacts_global_ipc = NULL;
+                       g_hash_table_remove(_ctsvc_ipc_table, ipc_key);
                }
        }
        else {
@@ -241,19 +288,19 @@ int ctsvc_ipc_disconnect(contacts_h contact, int connection_count)
 
 static void __ctsvc_ipc_lock()
 {
-       if (__contacts_ipc == NULL)
+       if (0 == ctsvc_client_get_thread_connection_count())
                ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_CALL);
 }
 
 static void __ctsvc_ipc_unlock(void)
 {
-       if (__contacts_ipc == NULL)
+       if (0 == ctsvc_client_get_thread_connection_count())
                ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_CALL);
 }
 
 int ctsvc_ipc_call(char *module, char *function, pims_ipc_h data_in, pims_ipc_data_h *data_out)
 {
-       pims_ipc_h ipc_handle = ctsvc_get_ipc_handle();
+       pims_ipc_h ipc_handle = _ctsvc_get_ipc_handle();
 
        __ctsvc_ipc_lock();
 
@@ -322,3 +369,50 @@ int ctsvc_ipc_client_check_permission(int permission, bool *result)
        return ret;
 }
 
+
+
+int ctsvc_ipc_set_disconnected_cb(void (*cb)(void *), void *user_data)
+{
+       if (0 == disconnected_cb_count++)
+               return pims_ipc_set_server_disconnected_cb(cb, user_data);
+       return CONTACTS_ERROR_NONE;
+}
+
+int ctsvc_ipc_unset_disconnected_cb()
+{
+       if (1 == disconnected_cb_count--)
+               return pims_ipc_unset_server_disconnected_cb();
+       return CONTACTS_ERROR_NONE;
+}
+
+void ctsvc_ipc_set_disconnected(bool is_disconnected)
+{
+       _ctsvc_ipc_disconnected = is_disconnected;
+}
+
+static void _ctsvc_ipc_recovery_foreach_cb(gpointer key, gpointer value, gpointer user_data)
+{
+       GList *c;
+       struct ctsvc_ipc_s *ipc_data = value;
+
+       int ret = _ctsvc_ipc_create(&(ipc_data->ipc));
+       RETM_IF(CONTACTS_ERROR_NONE != ret, "_ctsvc_ipc_create() Fail(%d)", ret);
+
+       for (c=ipc_data->list_handle;c;c=c->next) {
+               contacts_h contact = c->data;
+               ret = _ctsvc_ipc_connect(contact, ipc_data->ipc);
+               WARN_IF(CONTACTS_ERROR_NONE != ret, "_ctsvc_ipc_connect() Fail(%d)", ret);
+       }
+}
+
+void ctsvc_ipc_recovery()
+{
+       CTS_DBG("ctsvc_ipc_recovery (_ctsvc_ipc_disconnected=%d)", _ctsvc_ipc_disconnected);
+
+       if (false == _ctsvc_ipc_disconnected)
+               return;
+
+       g_hash_table_foreach(_ctsvc_ipc_table, _ctsvc_ipc_recovery_foreach_cb, NULL);
+}
+
+
index 861fad2..d28273d 100644 (file)
@@ -23,8 +23,6 @@
 #include <pims-ipc.h>
 #include "contacts_types.h"
 
-pims_ipc_h ctsvc_get_ipc_handle();
-
 int ctsvc_ipc_connect(contacts_h contact);
 int ctsvc_ipc_disconnect(contacts_h contact, int connection_count);
 
@@ -35,8 +33,10 @@ int ctsvc_ipc_disconnect_on_thread(contacts_h contact, int connection_count);
 bool ctsvc_ipc_is_busy();
 
 pims_ipc_h ctsvc_ipc_get_handle_for_change_subsciption();
+
 int ctsvc_ipc_create_for_change_subscription();
 int ctsvc_ipc_destroy_for_change_subscription();
+int ctsvc_ipc_recover_for_change_subscription();
 
 int ctsvc_ipc_call(char *module, char *function, pims_ipc_h data_in, pims_ipc_data_h *data_out);
 
@@ -45,5 +45,10 @@ int ctsvc_client_ipc_get_change_version(contacts_h contact);
 
 int ctsvc_ipc_client_check_permission(int permission, bool *result);
 
+int ctsvc_ipc_set_disconnected_cb(void (*cb)(void *), void *user_data);
+int ctsvc_ipc_unset_disconnected_cb();
+void ctsvc_ipc_set_disconnected(bool is_disconnected);
+void ctsvc_ipc_recovery();
+
 #endif /* __CTSVC_CLIENT_IPC_H__ */
 
index 44788e4..6c44e97 100644 (file)
@@ -107,6 +107,21 @@ int ctsvc_ipc_create_for_change_subscription()
        return CONTACTS_ERROR_NONE;
 }
 
+int ctsvc_ipc_recover_for_change_subscription()
+{
+       ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_PUBSUB);
+       if (__ipc_pubsub_ref <= 0)
+               return CONTACTS_ERROR_NONE;
+       __ipc = pims_ipc_create_for_subscribe(CTSVC_IPC_SOCKET_PATH_FOR_CHANGE_SUBSCRIPTION);
+       if (!__ipc) {
+               CTS_ERR("pims_ipc_create_for_subscribe error\n");
+               ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
+               return CONTACTS_ERROR_IPC;
+       }
+       ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_PUBSUB);
+       return CONTACTS_ERROR_NONE;
+}
+
 int ctsvc_ipc_destroy_for_change_subscription()
 {
        ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_PUBSUB);
index 84f58da..72368a1 100644 (file)
 #include "ctsvc_client_handle.h"
 #include "ctsvc_client_service_helper.h"
 
-static int ctsvc_connection = 0;
-static __thread int ctsvc_connection_on_thread = 0;
+static int _ctsvc_connection = 0;
+static __thread int _ctsvc_connection_on_thread = 0;
+
+int ctsvc_client_get_thread_connection_count()
+{
+       return _ctsvc_connection_on_thread;
+}
 
 int ctsvc_client_connect_with_flags(contacts_h contact, unsigned int flags)
 {
@@ -70,6 +75,18 @@ int ctsvc_client_connect_with_flags(contacts_h contact, unsigned int flags)
        return ret;
 }
 
+static void _ctsvc_ipc_disconnected_cb(void *user_data)
+{
+       ctsvc_ipc_set_disconnected(true);
+}
+
+static void _ctsvc_ipc_initialized_cb(void *user_data)
+{
+       ctsvc_ipc_recovery();
+       ctsvc_ipc_recover_for_change_subscription();
+       ctsvc_ipc_set_disconnected(false);
+}
+
 int ctsvc_client_connect(contacts_h contact)
 {
        CTS_FN_CALL;
@@ -87,7 +104,7 @@ int ctsvc_client_connect(contacts_h contact)
        }
        base->connection_count++;
 
-       if (0 == ctsvc_connection) {
+       if (0 == _ctsvc_connection) {
                ret = ctsvc_socket_init();
                if (ret != CONTACTS_ERROR_NONE) {
                        CTS_ERR("ctsvc_socket_init() Fail(%d)", ret);
@@ -102,14 +119,17 @@ int ctsvc_client_connect(contacts_h contact)
                        ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
                        return ret;
                }
-
                ctsvc_view_uri_init();
                ctsvc_ipc_create_for_change_subscription();
+               ctsvc_ipc_set_disconnected_cb(_ctsvc_ipc_disconnected_cb, NULL);
        }
        else
-               CTS_DBG("System : Contacts service has been already connected(%d)", ctsvc_connection + 1);
+               CTS_DBG("System : Contacts service has been already connected(%d)", _ctsvc_connection + 1);
 
-       ctsvc_connection++;
+       if (1 == base->connection_count)
+               ctsvc_inotify_subscribe_ipc_ready(contact, _ctsvc_ipc_initialized_cb, NULL);
+
+       _ctsvc_connection++;
        ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
 
        return CONTACTS_ERROR_NONE;
@@ -123,33 +143,35 @@ int ctsvc_client_disconnect(contacts_h contact)
 
        ctsvc_base_s *base = (ctsvc_base_s *)contact;
        if (1 == base->connection_count) {
-               ret = ctsvc_ipc_disconnect(contact, ctsvc_connection);
+               ret = ctsvc_ipc_disconnect(contact, _ctsvc_connection);
                if (ret != CONTACTS_ERROR_NONE) {
                        ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
                        CTS_ERR("ctsvc_ipc_disconnect() Fail(%d)", ret);
                        return ret;
                }
+               ctsvc_inotify_unsubscribe_ipc_ready(contact);
                ctsvc_client_handle_remove((contacts_h)base);
        }
        else {
                base->connection_count--;
        }
 
-       if (1 == ctsvc_connection) {
+       if (1 == _ctsvc_connection) {
                ctsvc_ipc_destroy_for_change_subscription();
                ctsvc_view_uri_deinit();
                ctsvc_inotify_close();
                ctsvc_socket_final();
+               ctsvc_ipc_unset_disconnected_cb();
        }
-       else if (1 < ctsvc_connection)
-               CTS_DBG("System : connection count is %d", ctsvc_connection);
+       else if (1 < _ctsvc_connection)
+               CTS_DBG("System : connection count is %d", _ctsvc_connection);
        else {
-               CTS_DBG("System : please call contacts_connect(), connection count is (%d)", ctsvc_connection);
+               CTS_DBG("System : please call contacts_connect(), connection count is (%d)", _ctsvc_connection);
                ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
                return CONTACTS_ERROR_INVALID_PARAMETER;
        }
 
-       ctsvc_connection--;
+       _ctsvc_connection--;
        ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
 
        return CONTACTS_ERROR_NONE;
@@ -163,16 +185,16 @@ int ctsvc_client_connect_on_thread(contacts_h contact)
        ctsvc_mutex_lock(CTS_MUTEX_CONNECTION);
 
        if (0 == base->connection_count) {
-               ret = ctsvc_ipc_connect_on_thread(contact);
+               ret = ctsvc_ipc_connect(contact);
                if (ret != CONTACTS_ERROR_NONE) {
-                       CTS_ERR("ctsvc_ipc_connect_on_thread() Fail(%d)", ret);
+                       CTS_ERR("ctsvc_ipc_connect() Fail(%d)", ret);
                        ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
                        return ret;
                }
        }
        base->connection_count++;
 
-       if (0 == ctsvc_connection_on_thread) {
+       if (0 == _ctsvc_connection_on_thread) {
                ret = ctsvc_socket_init();
                if (ret != CONTACTS_ERROR_NONE) {
                        CTS_ERR("ctsvc_socket_init() Fail(%d)", ret);
@@ -187,14 +209,17 @@ int ctsvc_client_connect_on_thread(contacts_h contact)
                        ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
                        return ret;
                }
-
                ctsvc_view_uri_init();
                ctsvc_ipc_create_for_change_subscription();
+               ctsvc_ipc_set_disconnected_cb(_ctsvc_ipc_disconnected_cb, NULL);
        }
-       else if (0 < ctsvc_connection_on_thread)
+       else if (0 < _ctsvc_connection_on_thread)
                CTS_DBG("System : Contacts service has been already connected");
 
-       ctsvc_connection_on_thread++;
+       if (1 == base->connection_count)
+               ctsvc_inotify_subscribe_ipc_ready(contact, _ctsvc_ipc_initialized_cb, NULL);
+
+       _ctsvc_connection_on_thread++;
 
        ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
 
@@ -209,36 +234,37 @@ int ctsvc_client_disconnect_on_thread(contacts_h contact)
        ctsvc_mutex_lock(CTS_MUTEX_CONNECTION);
 
        if (1 == base->connection_count) {
-               ret = ctsvc_ipc_disconnect_on_thread(contact, ctsvc_connection_on_thread);
+               ret = ctsvc_ipc_disconnect(contact, _ctsvc_connection_on_thread);
                if (ret != CONTACTS_ERROR_NONE) {
                        CTS_ERR("ctsvc_ipc_disconnect_on_thread() Fail(%d)", ret);
                        ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
                        return ret;
                }
+               ctsvc_inotify_unsubscribe_ipc_ready(contact);
                ctsvc_client_handle_remove((contacts_h)base);
-
        }
        else {
                base->connection_count--;
        }
 
-       if (1 == ctsvc_connection_on_thread) {
+       if (1 == _ctsvc_connection_on_thread) {
                ctsvc_ipc_destroy_for_change_subscription();
                ctsvc_view_uri_deinit();
                ctsvc_inotify_close();
                ctsvc_socket_final();
+               ctsvc_ipc_unset_disconnected_cb();
                CTS_DBG("System : connection_on_thread was destroyed successfully");
        }
-       else if (1 < ctsvc_connection_on_thread) {
-               CTS_DBG("System : connection count is %d", ctsvc_connection_on_thread);
+       else if (1 < _ctsvc_connection_on_thread) {
+               CTS_DBG("System : connection count is %d", _ctsvc_connection_on_thread);
        }
        else {
-               CTS_DBG("System : please call contacts_connect_on_thread(), connection count is (%d)", ctsvc_connection_on_thread);
+               CTS_DBG("System : please call contacts_connect_on_thread(), connection count is (%d)", _ctsvc_connection_on_thread);
                ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
                return CONTACTS_ERROR_INVALID_PARAMETER;
        }
 
-       ctsvc_connection_on_thread--;
+       _ctsvc_connection_on_thread--;
 
        ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
 
index 5f27eb7..d0d0bf2 100644 (file)
@@ -29,5 +29,6 @@ int ctsvc_client_connect(contacts_h contact);
 int ctsvc_client_disconnect(contacts_h contact);
 int ctsvc_client_connect_on_thread(contacts_h contact);
 int ctsvc_client_disconnect_on_thread(contacts_h contact);
+int ctsvc_client_get_thread_connection_count();
 
 #endif /* __CTSVC_CLIENT_SERVICE_HELPER_H__ */
\ No newline at end of file
index 81592e5..602725e 100644 (file)
@@ -46,6 +46,14 @@ typedef struct
        bool blocked;
 }noti_info;
 
+struct socket_init_noti_info {
+       int wd;
+       int subscribe_count;
+       void (*cb)(void *);
+       void *cb_data;
+};
+
+static GHashTable *_ctsvc_socket_init_noti_table = NULL;
 static int __ctsvc_inoti_ref = 0;
 static int __inoti_fd = -1;
 static guint __inoti_handler = 0;
@@ -76,6 +84,16 @@ static inline void __ctsvc_inotify_handle_callback(GSList *noti_list, int wd, ui
        }
 }
 
+static void _ctsvc_inotify_socket_init_noti_table_foreach_cb(gpointer key, gpointer value, gpointer user_data)
+{
+       GList *c;
+       struct socket_init_noti_info *noti_info = value;
+
+       int wd = GPOINTER_TO_INT(user_data);
+       if (noti_info->wd == wd)
+               noti_info->cb(noti_info->cb_data);
+}
+
 static gboolean __ctsvc_inotify_gio_cb(GIOChannel *src, GIOCondition cond, gpointer data)
 {
        int fd, ret;
@@ -86,6 +104,9 @@ static gboolean __ctsvc_inotify_gio_cb(GIOChannel *src, GIOCondition cond, gpoin
 
        while (0 < (ret = read(fd, &ie, sizeof(ie)))) {
                if (sizeof(ie) == ret) {
+                       if (_ctsvc_socket_init_noti_table)
+                               g_hash_table_foreach(_ctsvc_socket_init_noti_table, _ctsvc_inotify_socket_init_noti_table_foreach_cb, GINT_TO_POINTER(ie.wd));
+
                        if (__noti_list)
                                __ctsvc_inotify_handle_callback(__noti_list, ie.wd, ie.mask);
 
@@ -248,6 +269,69 @@ static inline const char* __ctsvc_noti_get_file_path(const char *view_uri)
        return NULL;
 }
 
+int ctsvc_inotify_subscribe_ipc_ready(contacts_h contact, void (*cb)(void *), void *user_data)
+{
+       const char *noti_path = CTSVC_NOTI_IPC_READY;
+       struct socket_init_noti_info *noti_info = NULL;
+
+       if (NULL == _ctsvc_socket_init_noti_table)
+               _ctsvc_socket_init_noti_table = g_hash_table_new_full(g_str_hash, g_str_equal, free, free);
+       else
+               noti_info = g_hash_table_lookup(_ctsvc_socket_init_noti_table, noti_path);
+
+       if (NULL == noti_info) {
+               int wd = __ctsvc_inotify_get_wd(__inoti_fd, noti_path);
+               if (-1 == wd) {
+                       CTS_ERR("__ctsvc_inotify_get_wd() Failed(noti_path=%s, errno : %d)", noti_path, errno);
+                       if (errno == EACCES)
+                               return CONTACTS_ERROR_PERMISSION_DENIED;
+                       return CONTACTS_ERROR_SYSTEM;
+               }
+
+               int ret = __ctsvc_inotify_watch(__inoti_fd, noti_path);
+               if (CONTACTS_ERROR_NONE != ret) {
+                       CTS_ERR("__ctsvc_inotify_watch() Failed");
+                       return ret;
+               }
+
+               noti_info = calloc(1, sizeof(struct socket_init_noti_info));
+               if (NULL == noti_info) {
+                       CTS_ERR("calloc() return NULL");
+                       return ret;
+               }
+
+               noti_info->wd = wd;
+               noti_info->cb = cb;
+               noti_info->cb_data = user_data;
+               g_hash_table_insert(_ctsvc_socket_init_noti_table, strdup(noti_path), noti_info);
+       }
+       noti_info->subscribe_count++;
+       return CONTACTS_ERROR_NONE;
+}
+
+int ctsvc_inotify_unsubscribe_ipc_ready(contacts_h contact)
+{
+       RETVM_IF(NULL == _ctsvc_socket_init_noti_table, CONTACTS_ERROR_INVALID_PARAMETER, "_ctsvc_socket_init_noti_table is NULL");
+
+       const char *noti_path = CTSVC_NOTI_IPC_READY;
+       struct socket_init_noti_info *noti_info = NULL;
+
+       noti_info = g_hash_table_lookup(_ctsvc_socket_init_noti_table, noti_path);
+       RETVM_IF(NULL == noti_info, CONTACTS_ERROR_INVALID_PARAMETER, "g_hash_table_lookup() return NULL");
+
+       if (1 == noti_info->subscribe_count) {
+               int wd = noti_info->wd;
+               inotify_rm_watch(__inoti_fd, wd);
+               g_hash_table_remove(_ctsvc_socket_init_noti_table, noti_path); // free noti_info automatically
+       }
+       else {
+               noti_info->subscribe_count--;
+       }
+
+       return CONTACTS_ERROR_NONE;
+}
+
+
 int ctsvc_inotify_subscribe(contacts_h contact, const char *view_uri,
                        void *cb, void *data)
 {
index fec35c3..136d8f7 100644 (file)
@@ -28,4 +28,7 @@ void ctsvc_inotify_close(void);
 int ctsvc_inotify_subscribe(contacts_h contact, const char *view_uri, contacts_db_changed_cb cb, void *data);
 int ctsvc_inotify_unsubscribe(contacts_h contact, const char *view_uri, contacts_db_changed_cb cb, void *user_data);
 
+int ctsvc_inotify_subscribe_ipc_ready(contacts_h contact, void (*cb)(void *), void *user_data);
+int ctsvc_inotify_unsubscribe_ipc_ready(contacts_h contact);
+
 #endif /* __CTSVC_INOTIFY_H__ */
index 618b050..661f329 100644 (file)
@@ -31,6 +31,7 @@
 #define CTS_LOGO_IMAGE_LOCATION tzplatform_mkpath(TZ_USER_DATA,"contacts-svc/img/logo")
 #define CTSVC_CONTACT_IMG_FULL_LOCATION tzplatform_mkpath(TZ_USER_DATA,"contacts-svc/img/contact")
 
+#define CTSVC_NOTI_IPC_READY tzplatform_mkpath(TZ_USER_DATA,"contacts-svc/.CONTACTS_SVC_IPC_READY")
 #define CTSVC_NOTI_ADDRESSBOOK_CHANGED tzplatform_mkpath(TZ_USER_DATA,"contacts-svc/.CONTACTS_SVC_AB_CHANGED")
 #define CTSVC_NOTI_GROUP_CHANGED tzplatform_mkpath(TZ_USER_DATA,"contacts-svc/.CONTACTS_SVC_GROUP_CHANGED")
 #define CTSVC_NOTI_PERSON_CHANGED tzplatform_mkpath(TZ_USER_DATA,"contacts-svc/.CONTACTS_SVC_PERSON_CHANGED")
diff --git a/res/.CONTACTS_SVC_IPC_READY b/res/.CONTACTS_SVC_IPC_READY
new file mode 100644 (file)
index 0000000..e69de29
index 821d767..42ecbb7 100644 (file)
@@ -52,6 +52,15 @@ static TLS bool image_change = false;
 static TLS bool profile_change = false;
 static TLS bool company_change = false;
 
+void ctsvc_noti_publish_socket_initialize(void)
+{
+       int fd = open(CTSVC_NOTI_IPC_READY, O_TRUNC | O_RDWR);
+
+       if (0 <= fd) {
+               close(fd);
+       }
+}
+
 static inline void __ctsvc_noti_publish_contact_change(void)
 {
        int fd = open(CTSVC_NOTI_CONTACT_CHANGED, O_TRUNC | O_RDWR);
index 7c01397..1f386f4 100644 (file)
@@ -48,8 +48,9 @@ void ctsvc_set_profile_noti(void);
 void ctsvc_set_sdn_noti(void);
 void ctsvc_set_company_noti(void);
 
-void ctsvc_notification_send();
+void ctsvc_notification_send(void);
 void ctsvc_nofitication_cancel(void);
+void ctsvc_noti_publish_socket_initialize(void);
 
 void ctsvc_db_data_delete_callback(sqlite3_context * context,
                int argc, sqlite3_value ** argv);
index 1e3c064..976e45b 100644 (file)
@@ -109,6 +109,7 @@ static int __server_main(void)
 
                snprintf(sock_file, sizeof(sock_file), CTSVC_SOCK_PATH"/.%s_for_subscribe", getuid(), CTSVC_IPC_SERVICE);
                pims_ipc_svc_init_for_publish(sock_file, CTS_SECURITY_FILE_GROUP, 0660);
+               ctsvc_noti_publish_socket_initialize();
 
                ret = ctsvc_connect();
                if (CONTACTS_ERROR_NONE != ret) {
@@ -201,6 +202,7 @@ int main(int argc, char *argv[])
        ctsvc_create_rep_set_permission(CTS_LOGO_IMAGE_LOCATION, 0770);
        ctsvc_create_rep_set_permission(CTSVC_CONTACT_IMG_FULL_LOCATION, 0770);
 
+       ctsvc_create_file_set_permission(CTSVC_NOTI_IPC_READY, 0660);
        ctsvc_create_file_set_permission(CTSVC_NOTI_ADDRESSBOOK_CHANGED, 0660);
        ctsvc_create_file_set_permission(CTSVC_NOTI_GROUP_CHANGED, 0660);
        ctsvc_create_file_set_permission(CTSVC_NOTI_PERSON_CHANGED, 0660);