Update SMACK, Fix a crash of terminating sequence, etc, ...
[apps/livebox/data-provider-master.git] / src / notification_service.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <stdio.h>
17
18 #include <Eina.h>
19
20 #include <dlog.h>
21 #include <livebox-errno.h>
22 #include <packet.h>
23
24 #include <sys/smack.h>
25
26 #include <notification_ipc.h>
27 #include <notification_noti.h>
28 #include <notification_error.h>
29
30 #include "service_common.h"
31 #include "debug.h"
32 #include "util.h"
33 #include "conf.h"
34
35 #ifndef NOTIFICATION_DEL_PACKET_UNIT
36 #define NOTIFICATION_DEL_PACKET_UNIT 10
37 #endif
38
39 static struct info {
40         Eina_List *context_list;
41         struct service_context *svc_ctx;
42 } s_info = {
43         .context_list = NULL, /*!< \WARN: This is only used for SERVICE THREAD */
44         .svc_ctx = NULL, /*!< \WARN: This is only used for MAIN THREAD */
45 };
46
47 struct context {
48         struct tcb *tcb;
49         double seq;
50 };
51
52 struct noti_service {
53         const char *cmd;
54         void (*handler)(struct tcb *tcb, struct packet *packet, void *data);
55 };
56
57 /*!
58  * FUNCTIONS to handle notifcation
59  */
60 static inline int get_priv_id(int num_deleted, int *list_deleted, int index) {
61         if (index < num_deleted) {
62                 return *(list_deleted + index);
63         } else {
64                 return -1;
65         }
66 }
67
68 static inline char *get_string(char *string)
69 {
70         if (string == NULL) {
71                 return NULL;
72         }
73         if (string[0] == '\0') {
74                 return NULL;
75         }
76
77         return string;
78 }
79
80 static inline struct packet *create_packet_from_deleted_list(int op_num, int *list, int start_index) {
81         return packet_create(
82                 "del_noti_multiple",
83                 "iiiiiiiiiii",
84                 ((op_num - start_index) > NOTIFICATION_DEL_PACKET_UNIT) ? NOTIFICATION_DEL_PACKET_UNIT : op_num - start_index,
85                 get_priv_id(op_num, list, start_index),
86                 get_priv_id(op_num, list, start_index + 1),
87                 get_priv_id(op_num, list, start_index + 2),
88                 get_priv_id(op_num, list, start_index + 3),
89                 get_priv_id(op_num, list, start_index + 4),
90                 get_priv_id(op_num, list, start_index + 5),
91                 get_priv_id(op_num, list, start_index + 6),
92                 get_priv_id(op_num, list, start_index + 7),
93                 get_priv_id(op_num, list, start_index + 8),
94                 get_priv_id(op_num, list, start_index + 9)
95                 );
96 }
97
98 /*!
99  * SERVICE HANDLER
100  */
101 static void _handler_insert(struct tcb *tcb, struct packet *packet, void *data)
102 {
103         int ret = 0, ret_p = 0;
104         int priv_id = 0;
105         struct packet *packet_reply = NULL;
106         struct packet *packet_service = NULL;
107         notification_h noti = NULL;
108
109         noti = notification_create(NOTIFICATION_TYPE_NOTI);
110         if (noti != NULL) {
111                 if (notification_ipc_make_noti_from_packet(noti, packet) == NOTIFICATION_ERROR_NONE) {
112                         ret = notification_noti_insert(noti);
113                         notification_get_id(noti, NULL, &priv_id);
114                         DbgPrint("priv_id: [%d]\n", priv_id);
115                         packet_reply = packet_create_reply(packet, "ii", ret, priv_id);
116                         if (packet_reply) {
117                                 if ((ret_p = service_common_unicast_packet(tcb, packet_reply)) < 0) {
118                                         ErrPrint("failed to send reply packet: %d\n", ret_p);
119                                 }
120                                 packet_destroy(packet_reply);
121                         } else {
122                                 ErrPrint("failed to create a reply packet\n");
123                         }
124
125                         if (ret != NOTIFICATION_ERROR_NONE) {
126                                 ErrPrint("failed to insert a notification: %d\n", ret);
127                                 notification_free(noti);
128                                 return ;
129                         }
130
131                         packet_service = notification_ipc_make_packet_from_noti(noti, "add_noti", 2);
132                         if (packet_service != NULL) {
133                                 if ((ret_p = service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE)) < 0) {
134                                         ErrPrint("failed to send a multicast packet: %d\n", ret_p);
135                                 }
136                                 packet_destroy(packet_service);
137                         } else {
138                                 ErrPrint("failed to create a multicats packet\n");
139                         }
140                 } else {
141                         ErrPrint("Failed to create the packet");
142                 }
143                 notification_free(noti);
144         }
145 }
146
147 static void _handler_update(struct tcb *tcb, struct packet *packet, void *data)
148 {
149         int ret = 0, ret_p = 0;
150         int priv_id = 0;
151         struct packet *packet_reply = NULL;
152         struct packet *packet_service = NULL;
153         notification_h noti = NULL;
154
155         noti = notification_create(NOTIFICATION_TYPE_NOTI);
156         if (noti != NULL) {
157                 if (notification_ipc_make_noti_from_packet(noti, packet) == NOTIFICATION_ERROR_NONE) {
158                         ret = notification_noti_update(noti);
159
160                         notification_get_id(noti, NULL, &priv_id);
161                         DbgPrint("priv_id: [%d]\n", priv_id);
162                         packet_reply = packet_create_reply(packet, "ii", ret, priv_id);
163                         if (packet_reply) {
164                                 if ((ret_p = service_common_unicast_packet(tcb, packet_reply)) < 0) {
165                                         ErrPrint("failed to send reply packet:%d\n", ret_p);
166                                 }
167                                 packet_destroy(packet_reply);
168                         } else {
169                                 ErrPrint("failed to create a reply packet\n");
170                         }
171
172                         if (ret != NOTIFICATION_ERROR_NONE) {
173                                 ErrPrint("failed to update a notification:%d\n", ret);
174                                 notification_free(noti);
175                                 return ;
176                         }
177
178                         packet_service = notification_ipc_make_packet_from_noti(noti, "update_noti", 2);
179                         if (packet_service != NULL) {
180                                 if ((ret_p = service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE)) < 0) {
181                                         ErrPrint("failed to send a multicast packet: %d\n", ret_p);
182                                 }
183                                 packet_destroy(packet_service);
184                         }
185                 } else {
186                         ErrPrint("Failed to create the packet");
187                 }
188                 notification_free(noti);
189         }
190 }
191
192 static void _handler_refresh(struct tcb *tcb, struct packet *packet, void *data)
193 {
194         int ret = 0;
195         struct packet *packet_reply = NULL;
196
197         packet_reply = packet_create_reply(packet, "i", ret);
198         if (packet_reply) {
199                 if ((ret = service_common_unicast_packet(tcb, packet_reply)) < 0) {
200                         ErrPrint("failed to send reply packet:%d\n", ret);
201                 }
202                 packet_destroy(packet_reply);
203         } else {
204                 ErrPrint("failed to create a reply packet\n");
205         }
206
207         if ((ret = service_common_multicast_packet(tcb, packet, TCB_CLIENT_TYPE_SERVICE)) < 0) {
208                 ErrPrint("failed to send a multicast packet:%d\n", ret);
209         }
210 }
211
212 static void _handler_delete_single(struct tcb *tcb, struct packet *packet, void *data)
213 {
214         int num_changes = 0;
215         int ret = 0, ret_p = 0;
216         int priv_id = 0;
217         struct packet *packet_reply = NULL;
218         struct packet *packet_service = NULL;
219         char *pkgname = NULL;
220
221         if (packet_get(packet, "si", &pkgname, &priv_id) == 2) {
222                 pkgname = get_string(pkgname);
223
224                 ret = notification_noti_delete_by_priv_id_get_changes(pkgname, priv_id, &num_changes);
225
226                 DbgPrint("priv_id: [%d] num_delete:%d\n", priv_id, num_changes);
227                 packet_reply = packet_create_reply(packet, "ii", ret, priv_id);
228                 if (packet_reply) {
229                         if ((ret_p = service_common_unicast_packet(tcb, packet_reply)) < 0) {
230                                 ErrPrint("failed to send reply packet:%d\n", ret_p);
231                         }
232                         packet_destroy(packet_reply);
233                 } else {
234                         ErrPrint("failed to create a reply packet\n");
235                 }
236
237                 if (ret != NOTIFICATION_ERROR_NONE && num_changes <= 0) {
238                         ErrPrint("failed to delete a notification:%d %d\n", ret, num_changes);
239                         return ;
240                 }
241
242                 packet_service = packet_create("del_noti_single", "ii", 1, priv_id);
243                 if (packet_service != NULL) {
244                         if ((ret_p = service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE)) < 0) {
245                                 ErrPrint("failed to send a multicast packet: %d\n", ret_p);
246                         }
247                         packet_destroy(packet_service);
248                 }
249         } else {
250                 ErrPrint("Failed to get data from the packet");
251         }
252 }
253
254 static void _handler_delete_multiple(struct tcb *tcb, struct packet *packet, void *data)
255 {
256         int ret = 0, ret_p = 0;
257         struct packet *packet_reply = NULL;
258         struct packet *packet_service = NULL;
259         char *pkgname = NULL;
260         notification_type_e type = 0;
261         int num_deleted = 0;
262         int *list_deleted = NULL;
263
264         if (packet_get(packet, "si", &pkgname, &type) == 2) {
265                 pkgname = get_string(pkgname);
266                 DbgPrint("pkgname: [%s] type: [%d]\n", pkgname, type);
267
268                 ret = notification_noti_delete_all(type, pkgname, &num_deleted, &list_deleted);
269                 DbgPrint("ret: [%d] num_deleted: [%d]\n", ret, num_deleted);
270
271                 packet_reply = packet_create_reply(packet, "ii", ret, num_deleted);
272                 if (packet_reply) {
273                         if ((ret_p = service_common_unicast_packet(tcb, packet_reply)) < 0) {
274                                 ErrPrint("failed to send reply packet:%d\n", ret_p);
275                         }
276                         packet_destroy(packet_reply);
277                 } else {
278                         ErrPrint("failed to create a reply packet\n");
279                 }
280
281                 if (ret != NOTIFICATION_ERROR_NONE) {
282                         ErrPrint("failed to delete notifications:%d\n", ret);
283                         if (list_deleted != NULL) {
284                                 free(list_deleted);
285                         }
286                         return ;
287                 }
288
289                 if (num_deleted > 0) {
290                         if (num_deleted <= NOTIFICATION_DEL_PACKET_UNIT) {
291                                 packet_service = create_packet_from_deleted_list(num_deleted, list_deleted, 0);
292
293                                 if (packet_service) {
294                                         if ((ret_p = service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE)) < 0) {
295                                                 ErrPrint("failed to send a multicast packet: %d\n", ret_p);
296                                         }
297                                         packet_destroy(packet_service);
298                                 } else {
299                                         ErrPrint("failed to create a multicast packet\n");
300                                 }
301                         } else {
302                                 int set = 0;
303                                 int set_total = num_deleted / NOTIFICATION_DEL_PACKET_UNIT;
304
305                                 for (set = 0; set <= set_total; set++) {
306                                         packet_service = create_packet_from_deleted_list(num_deleted,
307                                                         list_deleted, set * NOTIFICATION_DEL_PACKET_UNIT);
308
309                                         if (packet_service) {
310                                                 if ((ret_p = service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE)) < 0) {
311                                                         ErrPrint("failed to send a multicast packet:%d\n", ret_p);
312                                                 }
313                                                 packet_destroy(packet_service);
314                                         } else {
315                                                 ErrPrint("failed to create a multicast packet\n");
316                                         }
317                                 }
318                         }
319                 }
320
321                 if (list_deleted != NULL) {
322                         free(list_deleted);
323                         list_deleted = NULL;
324                 }
325         } else {
326                 ErrPrint("Failed to get data from the packet");
327         }
328 }
329
330 static void _handler_service_register(struct tcb *tcb, struct packet *packet, void *data)
331 {
332         int ret = 0;
333         struct packet *packet_reply;
334
335         ret = tcb_client_type_set(tcb, TCB_CLIENT_TYPE_SERVICE);
336
337         packet_reply = packet_create_reply(packet, "i", ret);
338         if (packet_reply) {
339                 if ((ret = service_common_unicast_packet(tcb, packet_reply)) < 0) {
340                         ErrPrint("failed to send reply packet:%d\n", ret);
341                 }
342                 packet_destroy(packet_reply);
343         } else {
344                 ErrPrint("failed to create a reply packet\n");
345         }
346 }
347
348 /*!
349  * SERVICE THREAD
350  */
351 static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
352 {
353         int i = 0;
354         const char *command;
355         static struct noti_service service_req_table[] = {
356                 {
357                         .cmd = "add_noti",
358                         .handler = _handler_insert,
359                 },
360                 {
361                         .cmd = "update_noti",
362                         .handler = _handler_update,
363                 },
364                 {
365                         .cmd = "refresh_noti",
366                         .handler = _handler_refresh,
367                 },
368                 {
369                         .cmd = "del_noti_single",
370                         .handler = _handler_delete_single,
371                 },
372                 {
373                         .cmd = "del_noti_multiple",
374                         .handler = _handler_delete_multiple,
375                 },
376                 {
377                         .cmd = "service_register",
378                         .handler = _handler_service_register,
379                 },
380                 {
381                         .cmd = NULL,
382                         .handler = NULL,
383                 },
384         };
385
386         if (!packet) {
387                 DbgPrint("TCB: %p is terminated\n", tcb);
388                 return 0;
389         }
390
391         command = packet_command(packet);
392         if (!command) {
393                 ErrPrint("Invalid command\n");
394                 return -EINVAL;
395         }
396
397         switch (packet_type(packet)) {
398         case PACKET_REQ:
399                 /* Need to send reply packet */
400                 DbgPrint("%p REQ: Command: [%s]\n", tcb, command);
401
402                 for (i = 0; service_req_table[i].cmd; i++) {
403                         if (strcmp(service_req_table[i].cmd, command))
404                                 continue;
405
406                         service_req_table[i].handler(tcb, packet, data);
407                         break;
408                 }
409
410                 break;
411         case PACKET_REQ_NOACK:
412                 break;
413         case PACKET_ACK:
414                 break;
415         default:
416                 ErrPrint("Packet type is not valid[%s]\n", command);
417                 return -EINVAL;
418         }
419
420         /*!
421          * return value has no meanning,
422          * it will be printed by dlogutil.
423          */
424         return 0;
425 }
426
427
428 /*!
429  * MAIN THREAD
430  * Do not try to do anyother operation in these functions
431  */
432 HAPI int notification_service_init(void)
433 {
434         if (s_info.svc_ctx) {
435                 ErrPrint("Already initialized\n");
436                 return LB_STATUS_ERROR_ALREADY;
437         }
438
439         s_info.svc_ctx = service_common_create(NOTIFICATION_SOCKET, service_thread_main, NULL);
440         if (!s_info.svc_ctx) {
441                 ErrPrint("Unable to activate service thread\n");
442                 return LB_STATUS_ERROR_FAULT;
443         }
444
445         if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), NOTIFICATION_SMACK_LABEL, SMACK_LABEL_IPOUT) != 0) {
446                 if (errno != EOPNOTSUPP) {
447                         ErrPrint("Unable to set SMACK label(%d)\n", errno);
448                         service_common_destroy(s_info.svc_ctx);
449                         s_info.svc_ctx = NULL;
450                         return LB_STATUS_ERROR_FAULT;
451                 }
452         }
453
454         if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), NOTIFICATION_SMACK_LABEL, SMACK_LABEL_IPIN) != 0) {
455                 if (errno != EOPNOTSUPP) {
456                         ErrPrint("Unable to set SMACK label(%d)\n", errno);
457                         service_common_destroy(s_info.svc_ctx);
458                         s_info.svc_ctx = NULL;
459                         return LB_STATUS_ERROR_FAULT;
460                 }
461         }
462
463         DbgPrint("Successfully initiated\n");
464         return LB_STATUS_SUCCESS;
465 }
466
467 HAPI int notification_service_fini(void)
468 {
469         if (!s_info.svc_ctx)
470                 return LB_STATUS_ERROR_INVALID;
471
472         service_common_destroy(s_info.svc_ctx);
473         s_info.svc_ctx = NULL;
474         DbgPrint("Successfully Finalized\n");
475         return LB_STATUS_SUCCESS;
476 }
477
478 /* End of a file */