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>
29 #include "ctsvc_client_ipc.h"
30 #include "ctsvc_client_utils.h"
31 #include "ctsvc_client_service_helper.h"
33 #include "ctsvc_internal.h"
34 #include "ctsvc_list.h"
35 #include "ctsvc_record.h"
36 #include "ctsvc_inotify.h"
38 #include "ctsvc_ipc_define.h"
39 #include "ctsvc_ipc_marshal.h"
40 #include "ctsvc_view.h"
41 #include "ctsvc_mutex.h"
42 #include "ctsvc_handle.h"
49 static pthread_mutex_t _ctsvc_mutex_disconnected = PTHREAD_MUTEX_INITIALIZER;
50 static GHashTable *_ctsvc_ipc_table = NULL;
51 static bool _ctsvc_ipc_disconnected = false;
53 static pims_ipc_h _ctsvc_get_ipc_handle()
55 struct ctsvc_ipc_s *ipc_data = NULL;
56 char ipc_key[CTSVC_STR_SHORT_LEN] = {0};
57 RETVM_IF(NULL == _ctsvc_ipc_table, NULL, "contacts not connected");
59 snprintf(ipc_key, sizeof(ipc_key), "%u", ctsvc_client_get_tid());
60 ipc_data = g_hash_table_lookup(_ctsvc_ipc_table, ipc_key);
62 if (NULL == ipc_data) {
63 snprintf(ipc_key, sizeof(ipc_key), "%u", ctsvc_client_get_pid());
64 ipc_data = g_hash_table_lookup(_ctsvc_ipc_table, ipc_key);
67 RETVM_IF(NULL == ipc_data, NULL, "g_hash_table_lookup(%s) Fail", ipc_key);
73 bool ctsvc_ipc_is_busy()
77 pims_ipc_h ipc = _ctsvc_get_ipc_handle();
79 ERR("_ctsvc_get_ipc_handle() return NULL");
83 ret = pims_ipc_is_call_in_progress(ipc);
85 ERR("global ipc channel is busy.");
91 static int _ctsvc_ipc_create(pims_ipc_h *p_ipc)
93 char sock_file[CTSVC_PATH_MAX_LEN] = {0};
96 if (ctsvc_client_is_in_system_session()) {
97 if (CONTACTS_ERROR_NONE != ctsvc_client_get_active_uid(&uid))
98 return CONTACTS_ERROR_SYSTEM;
101 snprintf(sock_file, sizeof(sock_file), CTSVC_SOCK_PATH"/.%s", uid,
103 pims_ipc_h ipc = pims_ipc_create(sock_file);
105 /* LCOV_EXCL_START */
106 if (errno == EACCES) {
107 ERR("pims_ipc_create() Fail(%d)", CONTACTS_ERROR_PERMISSION_DENIED);
108 return CONTACTS_ERROR_PERMISSION_DENIED;
110 ERR("pims_ipc_create() Fail(%d)", CONTACTS_ERROR_IPC_NOT_AVALIABLE);
111 return CONTACTS_ERROR_IPC_NOT_AVALIABLE;
117 return CONTACTS_ERROR_NONE;
120 static void _ctsvc_ipc_data_free(gpointer p)
122 struct ctsvc_ipc_s *ipc_data = p;
123 if (NULL == ipc_data)
127 ctsvc_ipc_unset_disconnected_cb(ipc_data->ipc);
128 pims_ipc_destroy(ipc_data->ipc);
131 g_list_free(ipc_data->list_handle);
136 static int _ctsvc_ipc_connect(contacts_h contact, pims_ipc_h ipc)
139 pims_ipc_data_h outdata = NULL;
140 pims_ipc_data_h indata = NULL;
142 /* Access control : put cookie to indata */
143 indata = pims_ipc_data_create(0);
144 if (indata == NULL) {
145 /* LCOV_EXCL_START */
146 ERR("pims_ipc_data_create() return NULL");
147 return CONTACTS_ERROR_OUT_OF_MEMORY;
151 ret = ctsvc_ipc_marshal_handle(contact, indata);
152 if (CONTACTS_ERROR_NONE != ret) {
153 /* LCOV_EXCL_START */
154 ERR("ctsvc_ipc_marshal_handle() Fail(%d)", ret);
155 pims_ipc_data_destroy(indata);
161 ret = pims_ipc_call(ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_CONNECT, indata,
164 /* LCOV_EXCL_START */
165 ERR("pims_ipc_call() Fail(%d)", ret);
166 pims_ipc_data_destroy(indata);
167 return CONTACTS_ERROR_IPC;
170 pims_ipc_data_destroy(indata);
173 ctsvc_ipc_unmarshal_int(outdata, &ret);
174 pims_ipc_data_destroy(outdata);
175 if (CONTACTS_ERROR_NONE != ret)
176 ERR("ctsvc_ipc_unmarshal_int() return(%d)", ret);
181 /* LCOV_EXCL_START */
182 static void _ctsvc_ipc_disconnected_cb(void *user_data)
184 ctsvc_ipc_set_disconnected(true);
188 int ctsvc_ipc_connect(contacts_h contact, unsigned int handle_id)
190 int ret = CONTACTS_ERROR_NONE;
191 struct ctsvc_ipc_s *ipc_data = NULL;
192 char ipc_key[CTSVC_STR_SHORT_LEN] = {0};
194 snprintf(ipc_key, sizeof(ipc_key), "%u", handle_id);
196 if (NULL == _ctsvc_ipc_table) {
197 _ctsvc_ipc_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
198 _ctsvc_ipc_data_free);
200 ipc_data = g_hash_table_lookup(_ctsvc_ipc_table, ipc_key);
203 if (NULL == ipc_data) {
204 ipc_data = calloc(1, sizeof(struct ctsvc_ipc_s));
205 if (NULL == ipc_data) {
206 /* LCOV_EXCL_START */
207 ERR("calloc() Fail");
208 return CONTACTS_ERROR_OUT_OF_MEMORY;
211 ret = _ctsvc_ipc_create(&(ipc_data->ipc));
212 if (CONTACTS_ERROR_NONE != ret) {
213 _ctsvc_ipc_data_free(ipc_data);
216 g_hash_table_insert(_ctsvc_ipc_table, strdup(ipc_key), ipc_data);
217 ctsvc_ipc_set_disconnected_cb(ipc_data->ipc, _ctsvc_ipc_disconnected_cb, NULL);
219 _ctsvc_ipc_connect(contact, ipc_data->ipc);
220 ipc_data->list_handle = g_list_append(ipc_data->list_handle, contact);
222 return CONTACTS_ERROR_NONE;
226 int ctsvc_ipc_disconnect(contacts_h contact, unsigned int handle_id,
227 int connection_count)
229 int ret = CONTACTS_ERROR_NONE;
230 struct ctsvc_ipc_s *ipc_data = NULL;
231 pims_ipc_data_h outdata = NULL;
232 pims_ipc_data_h indata = NULL;
233 char ipc_key[CTSVC_STR_SHORT_LEN] = {0};
235 RETVM_IF(NULL == _ctsvc_ipc_table, CONTACTS_ERROR_IPC, "contacts not connected");
236 snprintf(ipc_key, sizeof(ipc_key), "%u", handle_id);
238 ipc_data = g_hash_table_lookup(_ctsvc_ipc_table, ipc_key);
239 RETVM_IF(ipc_data == NULL, CONTACTS_ERROR_IPC, "contacts not connected");
241 indata = pims_ipc_data_create(0);
242 if (indata == NULL) {
243 /* LCOV_EXCL_START */
244 ERR("pims_ipc_data_create() Fail");
245 return CONTACTS_ERROR_OUT_OF_MEMORY;
249 ret = ctsvc_ipc_marshal_handle(contact, indata);
250 if (CONTACTS_ERROR_NONE != ret) {
251 /* LCOV_EXCL_START */
252 ERR("ctsvc_ipc_marshal_handle() Fail(%d)", ret);
253 pims_ipc_data_destroy(indata);
258 ret = pims_ipc_call(ipc_data->ipc, CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_DISCONNECT,
261 pims_ipc_data_destroy(indata);
262 /* LCOV_EXCL_START */
263 ERR("pims_ipc_call() Fail(%d)", ret);
264 return CONTACTS_ERROR_IPC;
267 pims_ipc_data_destroy(indata);
270 ctsvc_ipc_unmarshal_int(outdata, &ret);
271 pims_ipc_data_destroy(outdata);
273 if (ret != CONTACTS_ERROR_NONE) {
274 /* LCOV_EXCL_START */
275 ERR("ctsvc_ipc_unmarshal_int() Fail(%d)", ret);
280 if (1 == connection_count)
281 g_hash_table_remove(_ctsvc_ipc_table, ipc_key);
283 /* LCOV_EXCL_START */
284 ERR("pims_ipc_call out data is NULL");
285 return CONTACTS_ERROR_IPC;
292 static void __ctsvc_ipc_lock()
294 if (0 == ctsvc_client_get_thread_connection_count())
295 ctsvc_mutex_lock(CTS_MUTEX_PIMS_IPC_CALL);
298 static void __ctsvc_ipc_unlock(void)
300 if (0 == ctsvc_client_get_thread_connection_count())
301 ctsvc_mutex_unlock(CTS_MUTEX_PIMS_IPC_CALL);
304 int ctsvc_ipc_call(char *module, char *function, pims_ipc_h data_in,
305 pims_ipc_data_h *data_out)
307 pims_ipc_h ipc_handle;
309 if (true == ctsvc_ipc_get_disconnected()) {
310 ctsvc_ipc_set_disconnected(false);
311 ctsvc_ipc_recovery();
312 ctsvc_ipc_recover_for_change_subscription();
315 ipc_handle = _ctsvc_get_ipc_handle();
318 int ret = pims_ipc_call(ipc_handle, module, function, data_in, data_out);
319 __ctsvc_ipc_unlock();
324 void ctsvc_client_ipc_set_change_version(contacts_h contact, int version)
326 ctsvc_base_s *base = (ctsvc_base_s*)contact;
328 RET_IF(NULL == contact);
330 base->version = version;
333 int ctsvc_client_ipc_get_change_version(contacts_h contact)
335 ctsvc_base_s *base = (ctsvc_base_s*)contact;
337 RETV_IF(NULL == contact, -1);
339 return base->version;
342 int ctsvc_ipc_client_check_permission(int permission, bool *result)
344 pims_ipc_data_h indata = NULL;
345 pims_ipc_data_h outdata = NULL;
351 indata = pims_ipc_data_create(0);
352 if (indata == NULL) {
353 /* LCOV_EXCL_START */
354 ERR("pims_ipc_data_create() Fail");
355 return CONTACTS_ERROR_OUT_OF_MEMORY;
359 ret = ctsvc_ipc_marshal_int(permission, indata);
360 if (ret != CONTACTS_ERROR_NONE) {
361 /* LCOV_EXCL_START */
362 ERR("ctsvc_ipc_marshal_int() Fail(%d)", ret);
363 pims_ipc_data_destroy(indata);
368 ret = ctsvc_ipc_call(CTSVC_IPC_MODULE, CTSVC_IPC_SERVER_CHECK_PERMISSION, indata,
371 /* LCOV_EXCL_START */
372 ERR("ctsvc_ipc_call() Fail(%d)", ret);
373 pims_ipc_data_destroy(indata);
374 return CONTACTS_ERROR_IPC;
378 pims_ipc_data_destroy(indata);
381 if (CONTACTS_ERROR_NONE != ctsvc_ipc_unmarshal_int(outdata, &ret)) {
382 /* LCOV_EXCL_START */
383 ERR("ctsvc_ipc_unmarshal_int() Fail");
384 pims_ipc_data_destroy(outdata);
385 return CONTACTS_ERROR_IPC;
389 if (CONTACTS_ERROR_NONE == ret && result) {
390 if (CONTACTS_ERROR_NONE != ctsvc_ipc_unmarshal_bool(outdata, result)) {
391 /* LCOV_EXCL_START */
392 ERR("ctsvc_ipc_unmarshal_bool() Fail");
393 pims_ipc_data_destroy(outdata);
394 return CONTACTS_ERROR_IPC;
398 pims_ipc_data_destroy(outdata);
404 /* LCOV_EXCL_START */
405 int ctsvc_ipc_set_disconnected_cb(pims_ipc_h ipc, void (*cb)(void *), void *user_data)
407 return pims_ipc_add_server_disconnected_cb(ipc, cb, user_data);
410 int ctsvc_ipc_unset_disconnected_cb(pims_ipc_h ipc)
412 return pims_ipc_remove_server_disconnected_cb(ipc);
415 void ctsvc_ipc_set_disconnected(bool is_disconnected)
417 pthread_mutex_lock(&_ctsvc_mutex_disconnected);
418 _ctsvc_ipc_disconnected = is_disconnected;
419 pthread_mutex_unlock(&_ctsvc_mutex_disconnected);
422 int ctsvc_ipc_get_disconnected()
424 pthread_mutex_lock(&_ctsvc_mutex_disconnected);
425 DBG("_ctsvc_ipc_disconnected=%d", _ctsvc_ipc_disconnected);
426 pthread_mutex_unlock(&_ctsvc_mutex_disconnected);
427 return _ctsvc_ipc_disconnected;
430 static void _ctsvc_ipc_recovery_foreach_cb(gpointer key, gpointer value,
434 struct ctsvc_ipc_s *ipc_data = value;
436 ctsvc_ipc_unset_disconnected_cb(ipc_data->ipc);
438 int ret = _ctsvc_ipc_create(&(ipc_data->ipc));
439 RETM_IF(CONTACTS_ERROR_NONE != ret, "_ctsvc_ipc_create() Fail(%d)", ret);
441 ctsvc_ipc_set_disconnected_cb(ipc_data->ipc, _ctsvc_ipc_disconnected_cb, NULL);
443 for (c = ipc_data->list_handle; c; c = c->next) {
444 contacts_h contact = c->data;
445 ret = _ctsvc_ipc_connect(contact, ipc_data->ipc);
446 WARN_IF(CONTACTS_ERROR_NONE != ret, "_ctsvc_ipc_connect() Fail(%d)", ret);
450 void ctsvc_ipc_recovery()
453 g_hash_table_foreach(_ctsvc_ipc_table, _ctsvc_ipc_recovery_foreach_cb, NULL);