connection recovery
[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_handle.h"
35 #include "ctsvc_client_service_helper.h"
36
37 static int _ctsvc_connection = 0;
38 static __thread int _ctsvc_connection_on_thread = 0;
39
40 int ctsvc_client_get_thread_connection_count()
41 {
42         return _ctsvc_connection_on_thread;
43 }
44
45 int ctsvc_client_connect_with_flags(contacts_h contact, unsigned int flags)
46 {
47         CTS_FN_CALL;
48         int ret = CONTACTS_ERROR_NONE;
49
50         /* If new flag is defined, errer check should be updated */
51         RETVM_IF(flags & 0x11111110, CONTACTS_ERROR_INVALID_PARAMETER, "flags is invalid");
52
53         ret = ctsvc_client_connect(contact);
54         if (ret == CONTACTS_ERROR_PERMISSION_DENIED)
55                 return ret;
56         else if (ret == CONTACTS_ERROR_NONE)
57                 return ret;
58
59         if (flags & CONTACTS_CONNECT_FLAG_RETRY) {
60                 int i;
61                 int waiting_time = 500;
62                 for (i=0;i<9;i++) {
63                         usleep(waiting_time * 1000);
64                         CTS_DBG("retry cnt=%d, ret=%x, %d",(i+1), ret, waiting_time);
65                         ret = ctsvc_client_connect(contact);
66                         if (ret == CONTACTS_ERROR_NONE)
67                                 break;
68                         if (6 < i)
69                                 waiting_time += 30000;
70                         else
71                                 waiting_time *= 2;
72                 }
73         }
74
75         return ret;
76 }
77
78 static void _ctsvc_ipc_disconnected_cb(void *user_data)
79 {
80         ctsvc_ipc_set_disconnected(true);
81 }
82
83 static void _ctsvc_ipc_initialized_cb(void *user_data)
84 {
85         ctsvc_ipc_recovery();
86         ctsvc_ipc_recover_for_change_subscription();
87         ctsvc_ipc_set_disconnected(false);
88 }
89
90 int ctsvc_client_connect(contacts_h contact)
91 {
92         CTS_FN_CALL;
93         int ret;
94         ctsvc_base_s *base = (ctsvc_base_s *)contact;
95
96         ctsvc_mutex_lock(CTS_MUTEX_CONNECTION);
97         if (0 == base->connection_count) {
98                 ret = ctsvc_ipc_connect(contact);
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                 ctsvc_ipc_set_disconnected_cb(_ctsvc_ipc_disconnected_cb, NULL);
125         }
126         else
127                 CTS_DBG("System : Contacts service has been already connected(%d)", _ctsvc_connection + 1);
128
129         if (1 == base->connection_count)
130                 ctsvc_inotify_subscribe_ipc_ready(contact, _ctsvc_ipc_initialized_cb, NULL);
131
132         _ctsvc_connection++;
133         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
134
135         return CONTACTS_ERROR_NONE;
136 }
137
138 int ctsvc_client_disconnect(contacts_h contact)
139 {
140         CTS_FN_CALL;
141         int ret;
142         ctsvc_mutex_lock(CTS_MUTEX_CONNECTION);
143
144         ctsvc_base_s *base = (ctsvc_base_s *)contact;
145         if (1 == base->connection_count) {
146                 ret = ctsvc_ipc_disconnect(contact, _ctsvc_connection);
147                 if (ret != CONTACTS_ERROR_NONE) {
148                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
149                         CTS_ERR("ctsvc_ipc_disconnect() Fail(%d)", ret);
150                         return ret;
151                 }
152                 ctsvc_inotify_unsubscribe_ipc_ready(contact);
153                 ctsvc_client_handle_remove((contacts_h)base);
154         }
155         else {
156                 base->connection_count--;
157         }
158
159         if (1 == _ctsvc_connection) {
160                 ctsvc_ipc_destroy_for_change_subscription();
161                 ctsvc_view_uri_deinit();
162                 ctsvc_inotify_close();
163                 ctsvc_socket_final();
164                 ctsvc_ipc_unset_disconnected_cb();
165         }
166         else if (1 < _ctsvc_connection)
167                 CTS_DBG("System : connection count is %d", _ctsvc_connection);
168         else {
169                 CTS_DBG("System : please call contacts_connect(), connection count is (%d)", _ctsvc_connection);
170                 ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
171                 return CONTACTS_ERROR_INVALID_PARAMETER;
172         }
173
174         _ctsvc_connection--;
175         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
176
177         return CONTACTS_ERROR_NONE;
178 }
179
180 int ctsvc_client_connect_on_thread(contacts_h contact)
181 {
182         int ret;
183         ctsvc_base_s *base = (ctsvc_base_s *)contact;
184
185         ctsvc_mutex_lock(CTS_MUTEX_CONNECTION);
186
187         if (0 == base->connection_count) {
188                 ret = ctsvc_ipc_connect(contact);
189                 if (ret != CONTACTS_ERROR_NONE) {
190                         CTS_ERR("ctsvc_ipc_connect() Fail(%d)", ret);
191                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
192                         return ret;
193                 }
194         }
195         base->connection_count++;
196
197         if (0 == _ctsvc_connection_on_thread) {
198                 ret = ctsvc_socket_init();
199                 if (ret != CONTACTS_ERROR_NONE) {
200                         CTS_ERR("ctsvc_socket_init() Fail(%d)", ret);
201                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
202                         return ret;
203                 }
204
205                 ret = ctsvc_inotify_init();
206                 if (ret != CONTACTS_ERROR_NONE) {
207                         CTS_ERR("ctsvc_inotify_init() Fail(%d)", ret);
208                         ctsvc_socket_final();
209                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
210                         return ret;
211                 }
212                 ctsvc_view_uri_init();
213                 ctsvc_ipc_create_for_change_subscription();
214                 ctsvc_ipc_set_disconnected_cb(_ctsvc_ipc_disconnected_cb, NULL);
215         }
216         else if (0 < _ctsvc_connection_on_thread)
217                 CTS_DBG("System : Contacts service has been already connected");
218
219         if (1 == base->connection_count)
220                 ctsvc_inotify_subscribe_ipc_ready(contact, _ctsvc_ipc_initialized_cb, NULL);
221
222         _ctsvc_connection_on_thread++;
223
224         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
225
226         return CONTACTS_ERROR_NONE;
227 }
228
229 int ctsvc_client_disconnect_on_thread(contacts_h contact)
230 {
231         int ret;
232         ctsvc_base_s *base = (ctsvc_base_s *)contact;
233
234         ctsvc_mutex_lock(CTS_MUTEX_CONNECTION);
235
236         if (1 == base->connection_count) {
237                 ret = ctsvc_ipc_disconnect(contact, _ctsvc_connection_on_thread);
238                 if (ret != CONTACTS_ERROR_NONE) {
239                         CTS_ERR("ctsvc_ipc_disconnect_on_thread() Fail(%d)", ret);
240                         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
241                         return ret;
242                 }
243                 ctsvc_inotify_unsubscribe_ipc_ready(contact);
244                 ctsvc_client_handle_remove((contacts_h)base);
245         }
246         else {
247                 base->connection_count--;
248         }
249
250         if (1 == _ctsvc_connection_on_thread) {
251                 ctsvc_ipc_destroy_for_change_subscription();
252                 ctsvc_view_uri_deinit();
253                 ctsvc_inotify_close();
254                 ctsvc_socket_final();
255                 ctsvc_ipc_unset_disconnected_cb();
256                 CTS_DBG("System : connection_on_thread was destroyed successfully");
257         }
258         else if (1 < _ctsvc_connection_on_thread) {
259                 CTS_DBG("System : connection count is %d", _ctsvc_connection_on_thread);
260         }
261         else {
262                 CTS_DBG("System : please call contacts_connect_on_thread(), connection count is (%d)", _ctsvc_connection_on_thread);
263                 ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
264                 return CONTACTS_ERROR_INVALID_PARAMETER;
265         }
266
267         _ctsvc_connection_on_thread--;
268
269         ctsvc_mutex_unlock(CTS_MUTEX_CONNECTION);
270
271         return CONTACTS_ERROR_NONE;
272 }
273