4 * Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
26 #include <pims-ipc-data.h>
28 #include "ctsvc_client_ipc.h"
29 #include "ctsvc_client_utils.h"
30 #include "ctsvc_client_service_helper.h"
32 #include "ctsvc_internal.h"
33 #include "ctsvc_list.h"
34 #include "ctsvc_record.h"
35 #include "ctsvc_inotify.h"
37 #include "ctsvc_ipc_define.h"
38 #include "ctsvc_ipc_marshal.h"
39 #include "ctsvc_view.h"
40 #include "ctsvc_mutex.h"
41 #include "ctsvc_handle.h"
48 static GHashTable *_ctsvc_ipc_table = NULL;
49 static bool _ctsvc_ipc_disconnected = false;
51 static pims_ipc_h _ctsvc_get_ipc_handle()
53 struct ctsvc_ipc_s *ipc_data = NULL;
54 char ipc_key[CTSVC_STR_SHORT_LEN] = {0};
55 RETVM_IF(NULL == _ctsvc_ipc_table, NULL, "contacts not connected");
57 snprintf(ipc_key, sizeof(ipc_key), "%u", ctsvc_client_get_tid());
58 ipc_data = g_hash_table_lookup(_ctsvc_ipc_table, ipc_key);
60 if (NULL == ipc_data) {
61 snprintf(ipc_key, sizeof(ipc_key), "%u", ctsvc_client_get_pid());
62 ipc_data = g_hash_table_lookup(_ctsvc_ipc_table, ipc_key);
65 RETVM_IF(NULL == ipc_data, NULL, "g_hash_table_lookup(%s) Fail", ipc_key);
70 bool ctsvc_ipc_is_busy()
74 pims_ipc_h ipc = _ctsvc_get_ipc_handle();
76 CTS_ERR("_ctsvc_get_ipc_handle() return NULL");
80 ret = pims_ipc_is_call_in_progress(ipc);
82 CTS_ERR("global ipc channel is busy.");
87 static int _ctsvc_ipc_create(pims_ipc_h *p_ipc)
89 char sock_file[CTSVC_PATH_MAX_LEN] = {0};
90 snprintf(sock_file, sizeof(sock_file), CTSVC_SOCK_PATH"/.%s", getuid(), CTSVC_IPC_SERVICE);
91 pims_ipc_h ipc = pims_ipc_create(sock_file);
93 if (errno == EACCES) {
94 CTS_ERR("pims_ipc_create() Failed(%d)", CONTACTS_ERROR_PERMISSION_DENIED);
95 return CONTACTS_ERROR_PERMISSION_DENIED;
98 CTS_ERR("pims_ipc_create() Failed(%d)", CONTACTS_ERROR_IPC_NOT_AVALIABLE);
99 return CONTACTS_ERROR_IPC_NOT_AVALIABLE;
104 return CONTACTS_ERROR_NONE;
107 static void _ctsvc_ipc_data_free(gpointer p)
109 struct ctsvc_ipc_s *ipc_data = p;
110 if (NULL == ipc_data)
114 pims_ipc_destroy(ipc_data->ipc);
116 g_list_free(ipc_data->list_handle);
121 static int _ctsvc_ipc_connect(contacts_h contact, pims_ipc_h ipc)
124 pims_ipc_data_h outdata = NULL;
125 pims_ipc_data_h indata = NULL;
127 /* Access control : put cookie to indata */
128 indata = pims_ipc_data_create(0);
129 if (indata == NULL) {
130 CTS_ERR("pims_ipc_data_create() return NULL");
131 return CONTACTS_ERROR_OUT_OF_MEMORY;
134 ret = ctsvc_ipc_marshal_handle(contact, indata);
135 if (CONTACTS_ERROR_NONE != ret) {
136 CTS_ERR("ctsvc_ipc_marshal_handle Fail(%d)", ret);
137 pims_ipc_data_destroy(indata);
142 if (pims_ipc_call(ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_CONNECT, indata, &outdata) != 0) {
143 CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc_call failed");
144 pims_ipc_data_destroy(indata);
145 return CONTACTS_ERROR_IPC;
147 pims_ipc_data_destroy(indata);
150 ctsvc_ipc_unmarshal_int(outdata, &ret);
151 pims_ipc_data_destroy(outdata);
152 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_ipc_server_connect return(%d)", ret);
157 static void _ctsvc_ipc_disconnected_cb(void *user_data)
159 ctsvc_ipc_set_disconnected(true);
162 int ctsvc_ipc_connect(contacts_h contact, unsigned int handle_id)
164 int ret = CONTACTS_ERROR_NONE;
165 struct ctsvc_ipc_s *ipc_data = NULL;
166 char ipc_key[CTSVC_STR_SHORT_LEN] = {0};
168 snprintf(ipc_key, sizeof(ipc_key), "%u", handle_id);
170 if (NULL == _ctsvc_ipc_table)
171 _ctsvc_ipc_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _ctsvc_ipc_data_free);
173 ipc_data = g_hash_table_lookup(_ctsvc_ipc_table, ipc_key);
175 if (NULL == ipc_data) {
176 ipc_data = calloc(1, sizeof(struct ctsvc_ipc_s));
177 if (NULL == ipc_data)
179 CTS_ERR("calloc() Fail");
180 return CONTACTS_ERROR_OUT_OF_MEMORY;
182 ret = _ctsvc_ipc_create(&(ipc_data->ipc));
183 if (CONTACTS_ERROR_NONE != ret) {
184 _ctsvc_ipc_data_free(ipc_data);
187 g_hash_table_insert(_ctsvc_ipc_table, strdup(ipc_key), ipc_data);
188 ctsvc_ipc_set_disconnected_cb(ipc_data->ipc, _ctsvc_ipc_disconnected_cb, NULL);
190 _ctsvc_ipc_connect(contact, ipc_data->ipc);
191 ipc_data->list_handle = g_list_append(ipc_data->list_handle, contact);
193 return CONTACTS_ERROR_NONE;
197 int ctsvc_ipc_disconnect(contacts_h contact, unsigned int handle_id, int connection_count)
199 int ret = CONTACTS_ERROR_NONE;
200 struct ctsvc_ipc_s *ipc_data = NULL;
201 pims_ipc_data_h outdata = NULL;
202 pims_ipc_data_h indata = NULL;
203 char ipc_key[CTSVC_STR_SHORT_LEN] = {0};
205 RETVM_IF(NULL == _ctsvc_ipc_table, CONTACTS_ERROR_IPC, "contacts not connected");
206 snprintf(ipc_key, sizeof(ipc_key), "%u", handle_id);
208 ipc_data = g_hash_table_lookup(_ctsvc_ipc_table, ipc_key);
209 RETVM_IF(ipc_data == NULL, CONTACTS_ERROR_IPC, "contacts not connected");
211 indata = pims_ipc_data_create(0);
212 if (indata == NULL) {
213 CTS_ERR("ipc data created fail!");
214 return CONTACTS_ERROR_OUT_OF_MEMORY;
217 ret = ctsvc_ipc_marshal_handle(contact, indata);
218 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_ipc_marshal_handle() Fail(%d)", ret);
220 if (pims_ipc_call(ipc_data->ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_DISCONNECT, indata, &outdata) != 0) {
221 pims_ipc_data_destroy(indata);
222 CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc_call failed");
223 return CONTACTS_ERROR_IPC;
227 ctsvc_ipc_unmarshal_int(outdata, &ret);
228 pims_ipc_data_destroy(outdata);
230 if (ret != CONTACTS_ERROR_NONE) {
231 CTS_ERR("[GLOBAL_IPC_CHANNEL] pims_ipc didn't destroyed!!!(%d)", ret);
235 if (1 == connection_count) {
236 g_hash_table_remove(_ctsvc_ipc_table, ipc_key);
240 CTS_ERR("pims_ipc_call out data is NULL");
241 return CONTACTS_ERROR_IPC;
247 static void __ctsvc_ipc_lock()
249 if (0 == ctsvc_client_get_thread_connection_count())
250 ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_CALL);
253 static void __ctsvc_ipc_unlock(void)
255 if (0 == ctsvc_client_get_thread_connection_count())
256 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_CALL);
259 int ctsvc_ipc_call(char *module, char *function, pims_ipc_h data_in, pims_ipc_data_h *data_out)
261 pims_ipc_h ipc_handle;
263 if (true == ctsvc_ipc_get_disconnected()) {
264 ctsvc_ipc_set_disconnected(false);
265 ctsvc_ipc_recovery();
266 ctsvc_ipc_recover_for_change_subscription();
269 ipc_handle = _ctsvc_get_ipc_handle();
272 int ret = pims_ipc_call(ipc_handle, module, function, data_in, data_out);
273 __ctsvc_ipc_unlock();
278 void ctsvc_client_ipc_set_change_version(contacts_h contact, int version)
280 RETM_IF(NULL == contact, "contact is NULL");
281 ctsvc_base_s *base = (ctsvc_base_s *)contact;
282 base->version = version;
285 int ctsvc_client_ipc_get_change_version(contacts_h contact)
287 RETVM_IF(NULL == contact, -1, "contact is NULL");
288 ctsvc_base_s *base = (ctsvc_base_s *)contact;
289 return base->version;
292 int ctsvc_ipc_client_check_permission(int permission, bool *result)
294 pims_ipc_data_h indata = NULL;
295 pims_ipc_data_h outdata = NULL;
301 indata = pims_ipc_data_create(0);
302 if (indata == NULL) {
303 CTS_ERR("ipc data created fail !");
304 return CONTACTS_ERROR_OUT_OF_MEMORY;
307 ret = ctsvc_ipc_marshal_int(permission, indata);
308 if (ret != CONTACTS_ERROR_NONE) {
309 CTS_ERR("marshal fail");
310 pims_ipc_data_destroy(indata);
314 if (ctsvc_ipc_call(CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_CHECK_PERMISSION, indata, &outdata) != 0) {
315 CTS_ERR("ctsvc_ipc_call Fail");
316 pims_ipc_data_destroy(indata);
317 return CONTACTS_ERROR_IPC;
320 pims_ipc_data_destroy(indata);
323 if (CONTACTS_ERROR_NONE != ctsvc_ipc_unmarshal_int(outdata, &ret)) {
324 CTS_ERR("ctsvc_ipc_unmarshal_int() Fail");
325 pims_ipc_data_destroy(outdata);
326 return CONTACTS_ERROR_IPC;
329 if (CONTACTS_ERROR_NONE == ret && result) {
330 if (CONTACTS_ERROR_NONE != ctsvc_ipc_unmarshal_bool(outdata, result)) {
331 CTS_ERR("ctsvc_ipc_unmarshal_bool() Fail");
332 pims_ipc_data_destroy(outdata);
333 return CONTACTS_ERROR_IPC;
336 pims_ipc_data_destroy(outdata);
342 int ctsvc_ipc_set_disconnected_cb(pims_ipc_h ipc, void (*cb)(void *), void *user_data)
344 return pims_ipc_add_server_disconnected_cb(ipc, cb, user_data);
347 int ctsvc_ipc_unset_disconnected_cb(pims_ipc_h ipc)
349 return pims_ipc_remove_server_disconnected_cb(ipc);
352 void ctsvc_ipc_set_disconnected(bool is_disconnected)
354 _ctsvc_ipc_disconnected = is_disconnected;
357 int ctsvc_ipc_get_disconnected()
359 CTS_DBG("_ctsvc_ipc_disconnected=%d", _ctsvc_ipc_disconnected);
360 return _ctsvc_ipc_disconnected;
363 static void _ctsvc_ipc_recovery_foreach_cb(gpointer key, gpointer value, gpointer user_data)
366 struct ctsvc_ipc_s *ipc_data = value;
368 int ret = _ctsvc_ipc_create(&(ipc_data->ipc));
369 RETM_IF(CONTACTS_ERROR_NONE != ret, "_ctsvc_ipc_create() Fail(%d)", ret);
370 ctsvc_ipc_set_disconnected_cb(ipc_data->ipc, _ctsvc_ipc_disconnected_cb, NULL);
372 for (c=ipc_data->list_handle;c;c=c->next) {
373 contacts_h contact = c->data;
374 ret = _ctsvc_ipc_connect(contact, ipc_data->ipc);
375 WARN_IF(CONTACTS_ERROR_NONE != ret, "_ctsvc_ipc_connect() Fail(%d)", ret);
379 void ctsvc_ipc_recovery()
382 g_hash_table_foreach(_ctsvc_ipc_table, _ctsvc_ipc_recovery_foreach_cb, NULL);