2db133f8c4a23fb431d7e820c79e78bea716e708
[platform/core/system/sync-agent.git] / src / framework / event / ui_api.c
1 /*
2  * sync-agent
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the License);
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <pthread.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <glib.h>
26 #include <glib/gprintf.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <sys/inotify.h>
30
31 #include "utility/sync_util.h"
32 #include "fsapi/operation.h"
33
34 #include "event/config.h"
35 #include "event/util.h"
36 #include "event/data_accessor.h"
37 #include "event/data_accessor_internal.h"
38 #include "event/ui_api.h"
39
40 #ifndef EXPORT_API
41 #define EXPORT_API __attribute__ ((visibility("default")))
42 #endif
43
44 #ifndef SYNC_AGENT_LOG
45 #undef LOG_TAG
46 #define LOG_TAG "AF_EVENT_UI"
47 #endif
48
49 #define EVENT_SIZE      (sizeof(struct inotify_event))
50
51 static int inotify_fd;
52 static int inotify_wd;
53 static int gsource_id;
54
55 static gboolean _agent_noti_listener(GIOChannel * p_src, GIOCondition cond, gpointer p_data);
56
57 static void __dispatch_noti(int noti_num, sync_agent_event_data_s * noti, sync_agent_event_error_e * error);
58
59 EXPORT_API sync_agent_event_data_s *sync_agent_create_event(int event_num)
60 {
61         _EXTERN_FUNC_ENTER;
62
63         sync_agent_event_data_s *event = (sync_agent_event_data_s *) malloc(sizeof(sync_agent_event_data_s));
64         if (event == NULL) {
65                 _DEBUG_ERROR("Memory malloc FAILED. [event]");
66                 return NULL;
67         }
68         event->event_num = event_num;
69
70         char *serialized_data = (char *)calloc(EVENT_MAX_STREAM_SIZE, sizeof(char));
71         if (serialized_data != NULL) {
72                 event->size = serialized_data;
73                 event->data = serialized_data + 1;
74
75                 sync_agent_append_event_data_param(event, SYNC_AGENT_EVENT_PARAM_TYPE_INTEGER, &event_num);
76         } else {
77                 free(event);
78                 return NULL;
79         }
80
81         _EXTERN_FUNC_EXIT;
82
83         return event;
84 }
85
86 EXPORT_API sync_agent_event_data_s *sync_agent_send_event(sync_agent_event_data_s * event, sync_agent_event_error_e * error)
87 {
88         _EXTERN_FUNC_ENTER;
89
90         if (event == NULL) {
91                 _DEBUG_ERROR("sync_agent_event_data_s is NULL !!");
92                 *error = SYNC_AGENT_EVENT_IPC_ERR;
93                 return NULL;
94         }
95
96         *error = SYNC_AGENT_EVENT_SUCCESS;
97         int client_len;
98         int client_sockfd;
99         struct sockaddr_un clientaddr;
100         int buf_len = 0;
101
102         client_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
103         if (client_sockfd == -1) {
104                 _DEBUG_ERROR("socket create Error!!");
105                 *error = SYNC_AGENT_EVENT_IPC_ERR;
106                 return NULL;
107         }
108
109         bzero(&clientaddr, sizeof(clientaddr));
110         clientaddr.sun_family = AF_UNIX;
111         /*
112          * select socket path, whether event type is response for notification
113          */
114         const char *communication_path = NULL;
115         event_type_e event_type = event_get_event_type(event->event_num);
116         switch (event_type) {
117         case EVENT_TYPE_NO_RESPONSE:
118         case EVENT_TYPE_NEED_RESPONSE:
119                 communication_path = event_get_event_path();
120                 break;
121         default:
122                 break;
123         }
124
125         if (communication_path == NULL) {
126                 close(client_sockfd);
127                 *error = SYNC_AGENT_EVENT_IPC_ERR;
128                 return NULL;
129         }
130
131         _DEBUG_INFO("communication_path : %s", communication_path);
132
133         if (communication_path != NULL) {
134                 buf_len = g_strlcpy(clientaddr.sun_path, communication_path, sizeof(clientaddr.sun_path));
135                 if (buf_len >= sizeof(clientaddr.sun_path)) {
136                         _DEBUG_ERROR("clientaddr.sun_path buffer overflow !!");
137                         close(client_sockfd);
138                         *error = SYNC_AGENT_EVENT_IPC_ERR;
139                         return NULL;
140                 }
141         } else {
142                 _DEBUG_ERROR("communication_path is NULL !!");
143                 close(client_sockfd);
144                 *error = SYNC_AGENT_EVENT_IPC_ERR;
145                 return NULL;
146         }
147
148         client_len = sizeof(clientaddr);
149
150         if (connect(client_sockfd, (struct sockaddr *)&clientaddr, client_len) < 0) {
151                 _DEBUG_ERROR("socket connect error ( %d )", errno);
152                 close(client_sockfd);
153                 *error = SYNC_AGENT_EVENT_IPC_ERR;
154                 return NULL;
155         }
156
157         int send_data_size = (event->data - event->size) + 1;
158         int write_ret = write(client_sockfd, (void *)(event->size), send_data_size);
159         if (write_ret == -1) {
160                 _DEBUG_INFO("write() failed !!");
161                 close(client_sockfd);
162                 *error = SYNC_AGENT_EVENT_IPC_ERR;
163                 return NULL;
164         }
165
166         if (event_type != EVENT_TYPE_NEED_RESPONSE) {
167                 _DEBUG_INFO("Do not need synchronous response");
168                 *error = SYNC_AGENT_EVENT_SUCCESS;
169                 close(client_sockfd);
170                 return NULL;
171         }
172
173         /*
174          * receive Logic
175          */
176         char *connection_result = (char *)calloc(EVENT_MAX_STREAM_SIZE, sizeof(char));
177         if (connection_result == NULL) {
178                 _DEBUG_ERROR("Memory malloc FAILED. [connection_result]");
179                 close(client_sockfd);
180                 *error = SYNC_AGENT_EVENT_FAIL;
181                 return NULL;
182         }
183
184         if (read(client_sockfd, connection_result, EVENT_MAX_STREAM_SIZE) <= 0) {
185                 _DEBUG_ERROR("Socket Error - failed to read()");
186                 if (connection_result != NULL)
187                         free(connection_result);
188                 close(client_sockfd);
189                 *error = SYNC_AGENT_EVENT_IPC_ERR;
190                 return NULL;
191         }
192         close(client_sockfd);
193
194         event_print_event_data(connection_result);
195
196         sync_agent_event_data_s *reply_msg = (sync_agent_event_data_s *) malloc(sizeof(sync_agent_event_data_s));
197         if (reply_msg == NULL) {
198                 _DEBUG_ERROR("Memory malloc FAILED. [reply_msg]");
199                 if (connection_result != NULL)
200                         free(connection_result);
201                 *error = SYNC_AGENT_EVENT_FAIL;
202                 return NULL;
203         }
204         reply_msg->data = connection_result;
205
206         event_init_event_data_iter(reply_msg);
207
208         _EXTERN_FUNC_EXIT;
209
210         return reply_msg;
211 }
212
213 EXPORT_API sync_agent_event_error_e sync_agent_run_noti_listener(const char *noti_key)
214 {
215         _EXTERN_FUNC_ENTER;
216
217         retvm_if(noti_key == NULL, SYNC_AGENT_EVENT_FAIL, "noti key is NULL !!");
218
219         GIOChannel *gio_channel = NULL;
220         GSource *g_source = NULL;
221         int result = 0;
222
223         _DEBUG_TRACE("noti_key : %s", noti_key);
224
225         const char *communication_path = event_get_noti_path(0);
226         _DEBUG_TRACE("Noti communication path : %s", communication_path);
227
228         if (sync_agent_is_existing_fs(communication_path)) {
229                 _DEBUG_TRACE("%s file is exist !!");
230                 if (unlink(communication_path) == -1) {
231                         _DEBUG_ERROR("unlink failed ( %s ), ERROR NUM [%d] !!", communication_path, errno);
232                         return SYNC_AGENT_EVENT_FAIL;
233                 } else {
234                         _DEBUG_TRACE("unlink success !!");
235                 }
236         } else {
237                 _DEBUG_TRACE("%s file is not exist !!");
238         }
239
240         int fd = creat(communication_path, S_IRWXU | S_IRWXG | S_IRWXO);
241         if (fd < 0) {
242                 _DEBUG_ERROR("creat() failed !!");
243                 return SYNC_AGENT_EVENT_FAIL;
244         } else {
245                 _DEBUG_TRACE("%s file is created !!");
246         }
247
248         /* initialize an inotify instance */
249         inotify_fd = inotify_init();
250         if (inotify_fd == -1) {
251                 _DEBUG_ERROR("inotify_init() failed !!");
252                 return SYNC_AGENT_EVENT_FAIL;
253         }
254
255         /* change file's attribute */
256         result = fcntl(inotify_fd, F_SETFD, FD_CLOEXEC);
257         if (result == -1) {
258                 _DEBUG_ERROR("fcntl() failed !!");
259                 return SYNC_AGENT_EVENT_FAIL;
260         }
261         result = fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
262         if (result == -1) {
263                 _DEBUG_ERROR("fcntl() failed !!");
264                 return SYNC_AGENT_EVENT_FAIL;
265         }
266
267         /* add a watch to an initialized inotify instance */
268         inotify_wd = inotify_add_watch(inotify_fd, communication_path, IN_CLOSE_WRITE);
269         if (inotify_wd == -1) {
270                 _DEBUG_ERROR("inotify_add_watch() failed !!");
271                 return SYNC_AGENT_EVENT_FAIL;
272         }
273
274         /* create a new GIOChannel given a file descriptor */
275         gio_channel = g_io_channel_unix_new(inotify_fd);
276         if (gio_channel == NULL) {
277                 _DEBUG_ERROR("g_io_channel_unix_new() failed  !!");
278                 return SYNC_AGENT_EVENT_FAIL;
279         }
280
281         /* turn on nonblocking mode */
282         g_io_channel_set_flags(gio_channel, G_IO_FLAG_NONBLOCK, NULL);
283
284         /* create a GSource that's dispatched when condition is met for the given channel */
285         g_source = g_io_create_watch(gio_channel, G_IO_IN);
286
287         /* sets the priority of a source */
288         g_source_set_priority(g_source, G_PRIORITY_HIGH);
289
290         /* set the callback function for a source */
291         g_source_set_callback(g_source, (GSourceFunc) _agent_noti_listener, (gpointer) noti_key, NULL);
292
293         /* add a GSource to a context so that it will be executed within that context */
294         gsource_id = g_source_attach(g_source, NULL);
295         g_io_channel_unref(gio_channel);
296
297         _EXTERN_FUNC_EXIT;
298         return SYNC_AGENT_EVENT_SUCCESS;
299 }
300
301 EXPORT_API sync_agent_event_error_e sync_agent_stop_noti_listener()
302 {
303         _EXTERN_FUNC_ENTER;
304
305         inotify_rm_watch(inotify_fd, inotify_wd);
306         close(inotify_fd);
307
308         g_source_remove(gsource_id);
309
310         _EXTERN_FUNC_EXIT;
311
312         return SYNC_AGENT_EVENT_SUCCESS;
313 }
314
315 EXPORT_API sync_agent_event_error_e sync_agent_set_noti_callback(int notiType, sync_agent_noti_cb callback, void *data)
316 {
317         _EXTERN_FUNC_ENTER;
318
319         _EXTERN_FUNC_EXIT;
320
321         return event_register_noti_callback(notiType, callback, data);
322 }
323
324 EXPORT_API void sync_agent_free_event(sync_agent_event_data_s * event)
325 {
326         _EXTERN_FUNC_ENTER;
327
328         if (event != NULL) {
329                 sync_agent_free_event_data(event);
330         }
331
332         _EXTERN_FUNC_EXIT;
333 }
334
335 static gboolean _agent_noti_listener(GIOChannel * p_src, GIOCondition cond, gpointer p_data)
336 {
337         _INNER_FUNC_ENTER;
338
339         int buf_len = 0;
340         struct inotify_event event = { 0, };
341         int event_pos = 0;
342
343         char *noti_key = (char *)p_data;
344         _DEBUG_TRACE("noti key : %s", noti_key);
345
346         const char *communication_path = event_get_noti_path(0);
347         _DEBUG_TRACE("Noti communication path : %s", communication_path);
348
349         buf_len = read(inotify_fd, (void *)&event, sizeof(event));
350         if (buf_len < 0) {
351                 _DEBUG_ERROR("read() failed !!");
352                 return FALSE;
353         } else {
354                 _DEBUG_TRACE("buffer length : %d", buf_len);
355         }
356
357         while (event_pos < buf_len) {
358                 sync_agent_event_data_s *noti = (sync_agent_event_data_s *) calloc(1, sizeof(sync_agent_event_data_s));
359                 if (noti == NULL) {
360                         _DEBUG_ERROR("calloc failed !!");
361                         return FALSE;
362                 }
363
364                 char *inbuf = (char *)calloc(EVENT_MAX_STREAM_SIZE, sizeof(char));
365                 if (inbuf == NULL) {
366                         _DEBUG_ERROR("calloc failed !!");
367                         free(noti);
368                         return FALSE;
369                 }
370
371                 noti->data = inbuf;
372                 event_init_event_data_iter(noti);
373
374                 FILE *fp = NULL;
375                 fp = fopen(communication_path, "r");
376                 if (fp != NULL) {
377                         if (fread(inbuf, sizeof(char), EVENT_MAX_STREAM_SIZE, fp) <= 0) {
378                                 _DEBUG_ERROR("fread() failed !!");
379                                 free(inbuf);
380                                 free(noti);
381                                 fclose(fp);
382                                 return FALSE;
383                         } else {
384                                 _DEBUG_TRACE("fread() success !!");
385                                 fclose(fp);
386                         }
387                 } else {
388                         _DEBUG_ERROR("fopen( %s ) failed !!", communication_path);
389                         free(inbuf);
390                         free(noti);
391                         return FALSE;
392                 }
393
394                 int noti_num;
395                 sync_agent_get_event_data_param_int(noti, &noti_num);
396                 _DEBUG_TRACE("Received Noti Number : %d", noti_num);
397
398                 sync_agent_event_error_e error = SYNC_AGENT_EVENT_SUCCESS;;
399                 __dispatch_noti(noti_num, noti, &error);
400                 if (error != SYNC_AGENT_EVENT_SUCCESS) {
401                         _DEBUG_ERROR("__dispatch_noti() failed !!");
402                 } else {
403                         _DEBUG_TRACE("__dispatch_noti() success !!");
404                 }
405
406                 event_pos += EVENT_SIZE + event.len;
407         }
408
409         _INNER_FUNC_EXIT;
410
411         return TRUE;
412 }
413
414 static void __dispatch_noti(int noti_num, sync_agent_event_data_s * noti, sync_agent_event_error_e * error)
415 {
416         _INNER_FUNC_ENTER;
417
418         retm_if(noti == NULL, "sync_agent_event_data_s is NULL !!");
419
420         sync_agent_noti_cb noti_callback = event_get_noti_callback(noti_num);
421         void *additional_param = event_get_noti_callback_additional_param(noti_num);
422
423         if (noti_callback != NULL) {
424                 noti_callback(noti, additional_param);
425                 *error = SYNC_AGENT_EVENT_SUCCESS;
426         } else {
427                 *error = SYNC_AGENT_EVENT_FAIL;
428         }
429
430         _INNER_FUNC_EXIT;
431 }