ctsvc_client_handle_remove in CTS_MUTEX_CONNECTION during disconnect_on_thread
[platform/core/pim/contacts-service.git] / client / ctsvc_client_service_helper.c
1 /*
2  * Contacts Service
3  *
4  * Copyright (c) 2010 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Dohyung Jin <dh.jin@samsung.com>
7  *                 Jongwon Lee <gogosing.lee@samsung.com>
8  *                 Donghee Ye <donghee.ye@samsung.com>
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */
23 #include <errno.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <unistd.h>
27
28 #include "contacts.h"
29 #include "ctsvc_internal.h"
30 #include "ctsvc_socket.h"
31 #include "ctsvc_mutex.h"
32 #include "ctsvc_inotify.h"
33 #include "ctsvc_client_ipc.h"
34 #include "ctsvc_client_utils.h"
35 #include "ctsvc_client_handle.h"
36 #include "ctsvc_client_service_helper.h"
37
38 static int _ctsvc_connection = 0;
39 static __thread int _ctsvc_connection_on_thread = 0;
40
41 int ctsvc_client_get_thread_connection_count()
42 {
43         return _ctsvc_connection_on_thread;
44 }
45
46 int ctsvc_client_connect_with_flags(contacts_h contact, unsigned int flags)
47 {
48         CTS_FN_CALL;
49         int ret = CONTACTS_ERROR_NONE;
50
51         /* If new flag is defined, errer check should be updated */
52         RETVM_IF(flags & 0x11111110, CONTACTS_ERROR_INVALID_PARAMETER, "flags is invalid");
53
54         ret = ctsvc_client_connect(contact);
55         if (ret == CONTACTS_ERROR_PERMISSION_DENIED)
56                 return ret;
57         else if (ret == CONTACTS_ERROR_NONE)
58                 return ret;
59
60         if (flags & CONTACTS_CONNECT_FLAG_RETRY) {
61                 int i;
62                 int waiting_time = 500;
63                 for (i=0;i<9;i++) {
64                         usleep(waiting_time * 1000);
65                         CTS_DBG("retry cnt=%d, ret=%x, %d",(i+1), ret, waiting_time);
66                         ret = ctsvc_client_connect(contact);
67                         if (ret == CONTACTS_ERROR_NONE)
68                                 break;
69                         if (6 < i)
70                                 waiting_time += 30000;
71                         else
72                                 waiting_time *= 2;
73                 }
74         }
75
76         return ret;
77 }
78
79 static void _ctsvc_ipc_initialized_cb(void *user_data)
80 {
81         CTS_FN_CALL;
82         if (true == ctsvc_ipc_get_disconnected()) {
83                 ctsvc_ipc_set_disconnected(false);
84                 ctsvc_ipc_recovery();
85                 ctsvc_ipc_recover_for_change_subscription();
86         }
87 }
88
89 int ctsvc_client_connect(contacts_h contact)
90 {
91         CTS_FN_CALL;
92         int ret;
93         ctsvc_base_s *base = (ctsvc_base_s *)contact;
94         RETV_IF(NULL == base, CONTACTS_ERROR_INVALID_PARAMETER);
95
96         ctsvc_mutex_lock(CTS_MUTEX_CONNECTION);
97         if (0 == base->connection_count) {
98                 ret = ctsvc_ipc_connect(contact, ctsvc_client_get_pid());
99                 if (ret != CONTACTS_ERROR_NONE) {
100                         CTS_ERR("ctsvc_ipc_connect() Fail(%d)", ret);
101                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
102                         return ret;
103                 }
104         }
105         base->connection_count++;
106
107         if (0 == _ctsvc_connection) {
108                 ret = ctsvc_socket_init();
109                 if (ret != CONTACTS_ERROR_NONE) {
110                         CTS_ERR("ctsvc_socket_init() Fail(%d)", ret);
111                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
112                         return ret;
113                 }
114
115                 ret = ctsvc_inotify_init();
116                 if (ret != CONTACTS_ERROR_NONE) {
117                         CTS_ERR("ctsvc_inotify_init() Fail(%d)", ret);
118                         ctsvc_socket_final();
119                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
120                         return ret;
121                 }
122                 ctsvc_view_uri_init();
123                 ctsvc_ipc_create_for_change_subscription();
124         }
125         else
126                 CTS_DBG("System : Contacts service has been already connected(%d)", _ctsvc_connection + 1);
127
128         if (1 == base->connection_count)
129                 ctsvc_inotify_subscribe_ipc_ready(contact, _ctsvc_ipc_initialized_cb, NULL);
130
131         _ctsvc_connection++;
132         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
133
134         return CONTACTS_ERROR_NONE;
135 }
136
137 int ctsvc_client_disconnect(contacts_h contact)
138 {
139         CTS_FN_CALL;
140         int ret;
141         ctsvc_base_s *base = (ctsvc_base_s *)contact;
142         RETV_IF(NULL == base, CONTACTS_ERROR_INVALID_PARAMETER);
143
144         ctsvc_mutex_lock(CTS_MUTEX_CONNECTION);
145
146         if (1 == base->connection_count) {
147                 ret = ctsvc_ipc_disconnect(contact, ctsvc_client_get_pid(), _ctsvc_connection);
148                 if (ret != CONTACTS_ERROR_NONE) {
149                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
150                         CTS_ERR("ctsvc_ipc_disconnect() Fail(%d)", ret);
151                         return ret;
152                 }
153                 ctsvc_inotify_unsubscribe_ipc_ready(contact);
154         }
155         base->connection_count--;
156
157         if (1 == _ctsvc_connection) {
158                 ctsvc_ipc_destroy_for_change_subscription();
159                 ctsvc_view_uri_deinit();
160                 ctsvc_inotify_close();
161                 ctsvc_socket_final();
162
163         }
164         else if (1 < _ctsvc_connection)
165                 CTS_DBG("System : connection count is %d", _ctsvc_connection);
166         else {
167                 CTS_DBG("System : please call contacts_connect(), connection count is (%d)", _ctsvc_connection);
168                 ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
169                 return CONTACTS_ERROR_DB;
170         }
171
172         _ctsvc_connection--;
173
174         if (0 == base->connection_count) {
175                 CTS_INFO("connection_count is 0. remove handle");
176                 ret = ctsvc_client_handle_remove(ctsvc_client_get_pid(), contact);
177                 WARN_IF(CONTACTS_ERROR_NONE != ret, "ctsvc_client_handle_remove() Fail(%d)", ret);
178         }
179         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
180
181         return CONTACTS_ERROR_NONE;
182 }
183
184 int ctsvc_client_connect_on_thread(contacts_h contact)
185 {
186         int ret;
187         ctsvc_base_s *base = (ctsvc_base_s *)contact;
188         RETV_IF(NULL == base, CONTACTS_ERROR_INVALID_PARAMETER);
189
190         ctsvc_mutex_lock(CTS_MUTEX_CONNECTION);
191
192         if (0 == base->connection_count) {
193                 ret = ctsvc_ipc_connect(contact, ctsvc_client_get_tid());
194                 if (ret != CONTACTS_ERROR_NONE) {
195                         CTS_ERR("ctsvc_ipc_connect() Fail(%d)", ret);
196                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
197                         return ret;
198                 }
199         }
200         base->connection_count++;
201
202         if (0 == _ctsvc_connection_on_thread) {
203                 ret = ctsvc_socket_init();
204                 if (ret != CONTACTS_ERROR_NONE) {
205                         CTS_ERR("ctsvc_socket_init() Fail(%d)", ret);
206                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
207                         return ret;
208                 }
209
210                 ret = ctsvc_inotify_init();
211                 if (ret != CONTACTS_ERROR_NONE) {
212                         CTS_ERR("ctsvc_inotify_init() Fail(%d)", ret);
213                         ctsvc_socket_final();
214                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
215                         return ret;
216                 }
217                 ctsvc_view_uri_init();
218                 ctsvc_ipc_create_for_change_subscription();
219         }
220         else if (0 < _ctsvc_connection_on_thread)
221                 CTS_DBG("System : Contacts service has been already connected");
222
223         if (1 == base->connection_count)
224                 ctsvc_inotify_subscribe_ipc_ready(contact, _ctsvc_ipc_initialized_cb, NULL);
225
226         _ctsvc_connection_on_thread++;
227
228         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
229
230         return CONTACTS_ERROR_NONE;
231 }
232
233 int ctsvc_client_disconnect_on_thread(contacts_h contact)
234 {
235         int ret;
236         ctsvc_base_s *base = (ctsvc_base_s *)contact;
237         RETV_IF(NULL == base, CONTACTS_ERROR_INVALID_PARAMETER);
238
239         ctsvc_mutex_lock(CTS_MUTEX_CONNECTION);
240
241         if (1 == base->connection_count) {
242                 ret = ctsvc_ipc_disconnect(contact, ctsvc_client_get_tid(), _ctsvc_connection_on_thread);
243                 if (ret != CONTACTS_ERROR_NONE) {
244                         CTS_ERR("ctsvc_ipc_disconnect() Fail(%d)", ret);
245                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
246                         return ret;
247                 }
248                 ctsvc_inotify_unsubscribe_ipc_ready(contact);
249         }
250         base->connection_count--;
251
252         if (1 == _ctsvc_connection_on_thread) {
253                 ctsvc_ipc_destroy_for_change_subscription();
254                 ctsvc_view_uri_deinit();
255                 ctsvc_inotify_close();
256                 ctsvc_socket_final();
257                 CTS_DBG("System : connection_on_thread was destroyed successfully");
258         }
259         else if (1 < _ctsvc_connection_on_thread) {
260                 CTS_DBG("System : connection count is %d", _ctsvc_connection_on_thread);
261         }
262         else {
263                 CTS_DBG("System : please call contacts_connect_on_thread(), connection count is (%d)", _ctsvc_connection_on_thread);
264                 ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
265                 return CONTACTS_ERROR_DB;
266         }
267
268         _ctsvc_connection_on_thread--;
269
270         if (0 == base->connection_count) {
271                 CTS_INFO("connection_count is 0. remove handle");
272                 ret = ctsvc_client_handle_remove(ctsvc_client_get_tid(), contact);
273                 WARN_IF(CONTACTS_ERROR_NONE != ret, "ctsvc_client_handle_remove() Fail(%d)", ret);
274         }
275         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
276
277         return CONTACTS_ERROR_NONE;
278 }
279