merge with master
[platform/core/system/sync-agent.git] / src / framework / event / handler.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 <fcntl.h>
25 #include <errno.h>
26 #include <glib.h>
27 #include <glib/gprintf.h>
28
29 #include "utility/sync_util.h"
30 #include "data-adapter/agent_handler_manager.h"
31 #include "fsapi/operation.h"
32
33 #include "event/util.h"
34 #include "event/data_accessor.h"
35 #include "event/data_accessor_internal.h"
36 #include "event/config.h"
37 #include "event/handler.h"
38
39 #define EVENT_RETRY_COUNT               2000
40
41 #ifndef EXPORT_API
42 #define EXPORT_API __attribute__ ((visibility("default")))
43 #endif
44
45 #ifndef SYNC_AGENT_LOG
46 #undef LOG_TAG
47 #define LOG_TAG "AF_EVENT"
48 #endif
49
50 static int _event_server_socket_id = 0;
51
52 static pthread_t event_handler_thread_id;
53
54 static void *_event_listener(void *arg);
55
56 static void __dispatch_event(int event_num, sync_agent_event_data_s * request, sync_agent_event_data_s * response);
57
58 EXPORT_API sync_agent_event_error_e sync_agent_run_event_handler(unsigned long int *thread_id)
59 {
60         _EXTERN_FUNC_ENTER;
61
62         _DEBUG_INFO("sync_agent_run_event_handler() start\n");
63
64         pthread_create(&event_handler_thread_id, 0, _event_listener, 0);
65
66         *thread_id = event_handler_thread_id;
67
68         _EXTERN_FUNC_EXIT;
69
70         return SYNC_AGENT_EVENT_SUCCESS;
71 }
72
73 EXPORT_API sync_agent_event_error_e sync_agent_clean_event_handler()
74 {
75         _EXTERN_FUNC_ENTER;
76
77         sync_agent_event_error_e event_err = event_clean_event_spec();
78         if (event_err != SYNC_AGENT_EVENT_SUCCESS) {
79                 _DEBUG_ERROR("Fail event_clean_event_spec : %d", event_err);
80         } else {
81                 _DEBUG_INFO("Success event_clean_event_spec : %d", event_err);
82         }
83         event_err = event_clean_noti_spec();
84         if (event_err != SYNC_AGENT_EVENT_SUCCESS) {
85                 _DEBUG_ERROR("Fail event_clean_noti_spec : %d", event_err);
86         } else {
87                 _DEBUG_INFO("Success event_clean_noti_spec : %d", event_err);
88         }
89
90         if (_event_server_socket_id != 0) {
91                 close(_event_server_socket_id);
92                 _event_server_socket_id = 0;
93         }
94
95         pthread_cancel(event_handler_thread_id);
96
97         _EXTERN_FUNC_EXIT;
98
99         return SYNC_AGENT_EVENT_SUCCESS;
100 }
101
102 EXPORT_API sync_agent_event_error_e sync_agent_set_event_callback(int event_num, sync_agent_event_cb callback)
103 {
104         _EXTERN_FUNC_ENTER;
105
106         _EXTERN_FUNC_EXIT;
107
108         return event_register_event_callback(event_num, callback);
109 }
110
111 EXPORT_API sync_agent_event_data_s *sync_agent_create_noti(int noti_num)
112 {
113         _EXTERN_FUNC_ENTER;
114
115         sync_agent_event_data_s *noti = (sync_agent_event_data_s *) calloc(1, sizeof(sync_agent_event_data_s));
116         if (noti == NULL) {
117                 _DEBUG_ERROR("Memory malloc FAILED. [noti]");
118                 return noti;
119         } else {
120                 noti->event_num = noti_num;
121         }
122
123         char *serialized_data = (char *)calloc(EVENT_MAX_STREAM_SIZE, sizeof(char));
124         if (serialized_data == NULL) {
125                 _DEBUG_ERROR("CALLOC failed !!!");
126                 sync_agent_free_event_data(noti);
127                 return NULL;
128         }
129         noti->size = serialized_data;
130         noti->data = serialized_data + 1;
131
132         sync_agent_append_event_data_param(noti, SYNC_AGENT_EVENT_PARAM_TYPE_INTEGER, &noti_num);
133
134         _EXTERN_FUNC_EXIT;
135
136         return noti;
137 }
138
139 EXPORT_API sync_agent_event_data_s *sync_agent_send_noti(const char *noti_key, sync_agent_event_data_s * noti, sync_agent_confirm_ipc_cancel_cb confirm_cancel, void *user_data, sync_agent_event_error_e * error)
140 {
141         _EXTERN_FUNC_ENTER;
142
143         if (noti_key == NULL) {
144                 _DEBUG_ERROR("noti key is NULL !!");
145                 *error = SYNC_AGENT_EVENT_IPC_ERR;
146                 return NULL;
147         }
148
149         if (noti == NULL) {
150                 _DEBUG_ERROR("sync_agent_event_data_s is NULL !!");
151                 *error = SYNC_AGENT_EVENT_IPC_ERR;
152                 return NULL;
153         }
154
155         *error = SYNC_AGENT_EVENT_SUCCESS;
156         const char *communication_path = NULL;
157
158         noti_type_e noti_type = event_get_noti_type(noti_key, noti->event_num);
159
160         switch (noti_type) {
161         case NOTI_TYPE_SIMPLE:
162                 communication_path = event_get_noti_path(noti_key);
163                 break;
164         default:
165                 *error = SYNC_AGENT_EVENT_IPC_ERR;
166                 return NULL;
167                 break;
168         }
169
170         _DEBUG_INFO("noti num : %d", noti->event_num);
171         _DEBUG_INFO("noti_type : %d", noti_type);
172         _DEBUG_INFO("communication_path : %s", communication_path);
173
174         sync_agent_event_data_s *reply_msg = NULL;
175         int send_data_size = (noti->data - noti->size) + 1;
176
177         if (sync_agent_is_existing_fs(communication_path)) {
178                 FILE *fp = NULL;
179                 fp = fopen(communication_path, "w");
180                 if (fp != NULL) {
181                         if (fwrite((void *)(noti->size), sizeof(char), send_data_size, fp) <= 0) {
182                                 _DEBUG_ERROR("fwrite() failed !!");
183                                 *error = SYNC_AGENT_EVENT_IPC_ERR;
184                                 fclose(fp);
185                                 return NULL;
186                         } else {
187                                 _DEBUG_INFO("fwrite() success !!");
188                                 fclose(fp);
189                         }
190                 } else {
191                         _DEBUG_ERROR("fopen( %s ) failed  !!", communication_path);
192                         *error = SYNC_AGENT_EVENT_IPC_ERR;
193                         return NULL;
194                 }
195         } else {
196                 _DEBUG_ERROR("file ( %s ) does not exist !!", communication_path);
197                 *error = SYNC_AGENT_EVENT_IPC_ERR;
198                 return NULL;
199         }
200
201         _EXTERN_FUNC_EXIT;
202
203         return reply_msg;
204 }
205
206 EXPORT_API void sync_agent_free_noti(sync_agent_event_data_s * noti)
207 {
208         _EXTERN_FUNC_ENTER;
209
210         if (noti != NULL) {
211                 sync_agent_free_event_data(noti);
212         }
213
214         _EXTERN_FUNC_EXIT;
215 }
216
217 static void *_event_listener(void *arg)
218 {
219         _INNER_FUNC_ENTER;
220
221         signal(SIGPIPE, SIG_IGN);
222
223         int client_sockfd;
224         int state;
225         socklen_t client_len;
226         struct sockaddr_un clientaddr, serveraddr;
227         int buf_len = 0;
228         int result = 0;
229
230         const char *communication_path = event_get_event_path();
231         _DEBUG_TRACE("event_path : %s", communication_path);
232
233         if (sync_agent_is_existing_fs(communication_path)) {
234                 _DEBUG_TRACE("%s file is exist !!");
235                 if (unlink(communication_path) == -1) { /* when file exist, remove previous file */
236                         _DEBUG_ERROR("unlink failed ( %s ), ERROR NUM [%d] !!", communication_path, errno);
237                         return NULL;
238                 } else {
239                         _DEBUG_TRACE("unlink success !!");
240                 }
241         } else {
242                 _DEBUG_TRACE("%s file is not exist !!");
243         }
244
245         client_len = sizeof(clientaddr);
246         if ((_event_server_socket_id = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
247                 return NULL;
248         }
249
250         bzero(&serveraddr, sizeof(serveraddr));
251         serveraddr.sun_family = AF_UNIX;
252         if (communication_path != NULL) {
253                 buf_len = g_strlcpy(serveraddr.sun_path, communication_path, sizeof(serveraddr.sun_path));
254                 if (buf_len >= sizeof(serveraddr.sun_path)) {
255                         _DEBUG_ERROR("serveraddr.sun_path buffer overflow !!");
256                         return NULL;
257                 }
258         } else {
259                 _DEBUG_ERROR("communication_path is NULL !!");
260                 return NULL;
261         }
262
263         state = bind(_event_server_socket_id, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
264         if (state == -1) {
265                 _DEBUG_ERROR("bind failed !!");
266                 return NULL;
267         }
268
269         mode_t sock_mode = (S_IRWXU | S_IRWXG | S_IRWXO);
270         if (chmod(communication_path, sock_mode) == -1) {
271                 _DEBUG_ERROR("chmod failed !! ( err : %d )", errno);
272 //              return NULL;
273         }
274
275         state = listen(_event_server_socket_id, 5);
276         if (state == -1) {
277                 _DEBUG_ERROR("listen failed !!");
278                 return NULL;
279         }
280
281         while (1) {
282                 _DEBUG_TRACE("In EventHandler loop=\n");
283
284                 char inbuf[EVENT_MAX_STREAM_SIZE + 1];
285                 char outbuf[EVENT_MAX_STREAM_SIZE + 1];
286                 memset(inbuf, 0x00, EVENT_MAX_STREAM_SIZE + 1);
287                 memset(outbuf, 0x00, EVENT_MAX_STREAM_SIZE + 1);
288                 sync_agent_event_data_s request;
289                 sync_agent_event_data_s response;
290                 request.data = inbuf;
291                 response.data = outbuf;
292                 event_init_event_data_iter(&request);
293                 event_init_event_data_iter(&response);
294
295                 client_sockfd = accept(_event_server_socket_id, (struct sockaddr *)&clientaddr, &client_len);
296                 if (client_sockfd < 0) {
297                         _DEBUG_ERROR("socket accept() failed !!");
298                         return NULL;
299                 }
300                 _DEBUG_TRACE("accept() was called\n");
301
302                 result = read(client_sockfd, (void *)inbuf, EVENT_MAX_STREAM_SIZE);
303                 if (result <= 0 || result > EVENT_MAX_STREAM_SIZE) {
304                         _DEBUG_ERROR("read failed !!");
305                         close(client_sockfd);
306                         return NULL;
307                 }
308                 if (strlen(inbuf) <= 0 || strlen(inbuf) > EVENT_MAX_STREAM_SIZE) {
309                         _DEBUG_ERROR("socket data read : size OUT OF BOUND !!");
310                         close(client_sockfd);
311                         return NULL;
312                 }
313
314                 int event_num;
315                 sync_agent_get_event_data_param_int(&request, &event_num);
316                 _DEBUG_TRACE("Received Event Number : %d\n", event_num);
317
318                 __dispatch_event(event_num, &request, &response);
319                 /*
320                  * need synchronous response case
321                  */
322                 event_type_e event_type = event_get_event_type(event_num);
323                 if (event_type == EVENT_TYPE_NEED_RESPONSE) {
324                         if (event_get_event_data_element_size(&response) > 0) {
325                                 int byte_size = event_get_event_data_byte_size(&response);
326                                 int write_ret = write(client_sockfd, outbuf, byte_size);
327                                 if (write_ret != byte_size) {
328                                         _DEBUG_ERROR("write() failed !!");
329                                 }
330                         }
331                 }
332
333                 close(client_sockfd);
334         }
335
336         _INNER_FUNC_EXIT;
337
338         return NULL;
339 }
340
341 static void __dispatch_event(int event_num, sync_agent_event_data_s * request, sync_agent_event_data_s * response)
342 {
343         _INNER_FUNC_ENTER;
344
345         retm_if(request == NULL, "sync_agent_event_data_s is NULL !!");
346         retm_if(response == NULL, "sync_agent_event_data_s is NULL !!");
347
348         sync_agent_event_cb event_callback = event_get_event_callback(event_num);
349         retm_if(event_callback == NULL, "event_get_event_callback return value is NULL !!");
350
351         event_callback(request, response);
352         _INNER_FUNC_EXIT;
353 }