Fix SVace warnings
[platform/core/connectivity/zigbee-manager.git] / zigbee-daemon / zigbee-lib / src / zblib_service.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Contact: Suresh Kumar N (suresh.n@samsung.com)
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <dlfcn.h>
20 #include <sys/stat.h>
21
22 #include <zblib.h>
23 #include <zblib_service.h>
24 #include <zblib_plugin.h>
25 #include <zblib_service_interface.h>
26 #include <zblib_request.h>
27
28 /**< ZigBee Service object */
29 struct zblib_service_type {
30         GMainLoop *main_loop; /**< Service main-loop */
31
32         GSList *interface_objs; /**< ZigBee Service interface objects */
33         GSList *plugins; /**< ZigBee plug-ins */
34
35         GHashTable *request_table; /**< Request Hash table */
36         guint request_id; /**< Request ID */
37 };
38
39 static void *__zblib_service_load_plugin(gchar *filename,
40         ZblibPluginDescriptor_t **descriptor_out)
41 {
42         ZblibPluginDescriptor_t *descriptor = NULL;
43         void *handle = NULL;
44         struct stat stat_buf;
45         char file_date[27];
46
47         zblib_check_null_ret_error("descriptor_out", descriptor_out, NULL);
48
49         /* Open .so */
50         handle = dlopen(filename, RTLD_LAZY);
51         if (G_UNLIKELY(NULL == handle)) {
52                 Z_LOGE("dlopen() failed:[%s]", filename);
53                 return NULL;
54         }
55
56         /* Get symbol - "zigbee_plugin_descriptor" */
57         descriptor = dlsym(handle, "zigbee_plugin_descriptor");
58         if (G_UNLIKELY(NULL == descriptor)) {
59                 Z_LOGE("dlsym() failed:[%s]", "plugin_define_desc");
60                 dlclose(handle);
61                 return NULL;
62         }
63
64         Z_LOGD("%s plugin", descriptor->name);
65         Z_LOGD(" - path = %s", filename);
66         Z_LOGD(" - version = %d", descriptor->version);
67
68         memset(&stat_buf, 0x00, sizeof(stat_buf));
69         memset(&file_date, '\0', sizeof(file_date));
70
71         if (0 == stat(filename, &stat_buf)) {
72                 if (NULL != ctime_r(&stat_buf.st_mtime, file_date)) {
73                         if (1 < strlen(file_date))
74                                 file_date[strlen(file_date)-1] = '\0';
75                         Z_LOGD(" - date = %s", file_date);
76                 }
77         }
78
79         /* Load plug-in */
80         if (G_LIKELY(descriptor->load)) {
81                 if (G_UNLIKELY(FALSE == descriptor->load())) {
82                         Z_LOGW("load() failed... Skip this plugin!");
83                         dlclose(handle);
84                         return NULL;
85                 } else {
86                         Z_LOGI("Plug-in (%s) loaded!", descriptor->name);
87                 }
88         }
89
90         *descriptor_out = descriptor;
91
92         return handle;
93 }
94
95 static gboolean __zblib_service_init_plugin(ZigBeePlugin *plugin)
96 {
97         const ZblibPluginDescriptor_t *descriptor = zblib_plugin_get_descriptor(plugin);
98
99         zblib_check_null_ret_error("descriptor", descriptor, FALSE);
100         zblib_check_null_ret_error("descriptor->init", descriptor->init, FALSE);
101
102         if (G_UNLIKELY(FALSE == descriptor->init(plugin))) {
103                 char *plugin_name = zblib_plugin_get_plugin_name(plugin);
104                 if (G_UNLIKELY(NULL != plugin_name)) {
105                         Z_LOGE("plugin(%s) init failed!", plugin_name);
106                         g_free(plugin_name);
107                 }
108                 return FALSE;
109         }
110
111         return TRUE;
112 }
113
114 static gboolean __zblib_service_unload_plugin(ZigBeePlugin *plugin)
115 {
116         const ZblibPluginDescriptor_t *descriptor = zblib_plugin_get_descriptor(plugin);
117         char *plugin_name = NULL;
118
119         zblib_check_null_ret_error("descriptor", descriptor, FALSE);
120         zblib_check_null_ret_error("descriptor->unload", descriptor->unload, FALSE);
121
122         plugin_name = zblib_plugin_get_plugin_name(plugin);
123
124         descriptor->unload(plugin);
125         Z_LOGI("plugin(%s) unloaded!", plugin_name);
126
127         g_free(plugin_name);
128
129         return TRUE;
130 }
131
132 static void __zblib_service_remove_request_table_iter(gpointer key,
133         gpointer value, gpointer user_data)
134 {
135         ZigBeeServiceInterface *service_interface = (ZigBeeServiceInterface *)user_data;
136         gint request_id = (gint)key;
137
138         NOT_USED(value);
139
140         zblib_check_null_ret("service_interface", service_interface);
141
142         Z_LOGD("Removing request id [%d]", request_id);
143         zblib_request_free(service_interface, request_id);
144 }
145
146 ZigBeeService *zblib_service_new()
147 {
148         ZigBeeService *service;
149
150         service = g_malloc0(sizeof(struct zblib_service_type));
151
152         /* Create g-main loop */
153         service->main_loop = g_main_loop_new(NULL, FALSE);
154         if (G_UNLIKELY(NULL == service->main_loop)) {
155                 Z_LOGE("g-main loop creation failed!!!");
156                 g_free(service);
157                 return NULL;
158         }
159
160         /* Create request hash table */
161         service->request_table = g_hash_table_new_full(g_direct_hash,
162                 g_direct_equal, NULL, NULL);
163
164         return service;
165 }
166
167 void zblib_service_free(ZigBeeService *service)
168 {
169         zblib_check_null_ret("service", service);
170
171         if (service->request_table) {
172                 GSList *interface_objs = NULL;
173                 ZigBeeServiceInterface *service_interface = NULL;
174
175                 interface_objs = service->interface_objs;
176                 if (NULL == interface_objs) {
177                         Z_LOGE("interface_objs is NULL");
178                 } else {
179                         while (interface_objs) {
180                                 service_interface = (ZigBeeServiceInterface *)interface_objs->data;
181
182                                 /* Remove left request */
183                                 g_hash_table_foreach(service->request_table,
184                                                 __zblib_service_remove_request_table_iter,
185                                                 service_interface);
186
187                                 /* Move to next service interface */
188                                 interface_objs = g_slist_next(interface_objs);
189                         }
190                         g_hash_table_remove_all(service->request_table);
191                         g_hash_table_destroy(service->request_table);
192                         service->request_table = NULL;
193                 }
194         }
195
196         /* Free plug-ins */
197         if (service->plugins) {
198                 g_slist_free(service->plugins);
199                 service->plugins = NULL;
200         }
201
202         /* Unref 'g-main loop' */
203         if (service->main_loop)
204                 g_main_loop_unref(service->main_loop);
205
206         g_free(service);
207 }
208
209 gboolean zblib_service_run(ZigBeeService *service)
210 {
211         zblib_check_null_ret_error("service", service, FALSE);
212         zblib_check_null_ret_error("service->main_loop", service->main_loop, FALSE);
213
214         g_main_loop_run(service->main_loop);
215
216         return TRUE;
217 }
218
219 gboolean zblib_service_exit(ZigBeeService *service)
220 {
221         zblib_check_null_ret_error("service", service, FALSE);
222         zblib_check_null_ret_error("service->main_loop", service->main_loop, FALSE);
223
224         g_main_loop_quit(service->main_loop);
225
226         return TRUE;
227 }
228
229 gboolean zblib_service_add_plugin(ZigBeeService *service, ZigBeePlugin *plugin)
230 {
231         gchar *plugin_name;
232
233         zblib_check_null_ret_error("service", service, FALSE);
234         zblib_check_null_ret_error("plugin", plugin, FALSE);
235
236         plugin_name = zblib_plugin_get_plugin_name(plugin);
237
238         /* All plug-ins would be appended */
239         service->plugins = g_slist_append(service->plugins, plugin);
240         Z_LOGD("%s added", plugin_name);
241         g_free(plugin_name);
242
243         return TRUE;
244 }
245
246 gboolean zblib_service_remove_plugin(ZigBeeService *service, ZigBeePlugin *plugin)
247 {
248         zblib_check_null_ret_error("service", service, FALSE);
249         zblib_check_null_ret_error("plugin", plugin, FALSE);
250
251         /* Specific vendor plug-in would be removed */
252         service->plugins = g_slist_remove(service->plugins, plugin);
253
254         /* Deinitialize plugin */
255         zblib_plugin_free(plugin);
256
257         return TRUE;
258 }
259
260 gboolean zblib_service_load_plugins(ZigBeeService *service, const char *plugin_path)
261 {
262         const gchar *file = NULL;
263         gchar *filename = NULL;
264         GDir *dir = NULL;
265         void *handle = NULL;
266         ZblibPluginDescriptor_t *descriptor = NULL;
267         ZigBeePlugin *plugin = NULL;
268         gboolean ret;
269
270         zblib_check_null_ret_error("service", service, FALSE);
271         zblib_check_null_ret_error("plugin_path", plugin_path, FALSE);
272
273         /* Open plug-in directory */
274         dir = g_dir_open(plugin_path, 0, NULL);
275         if (G_UNLIKELY(dir == NULL)) {
276                 Z_LOGE("Directory open failed!");
277                 return FALSE;
278         }
279
280         /* Scan through all libraries in plug-in directory */
281         while ((file = g_dir_read_name(dir)) != NULL) {
282                 if ((g_str_has_prefix(file, "lib") == TRUE)
283                                 || (g_str_has_suffix(file, ".so") == FALSE))
284                         continue;
285
286                 filename = g_build_filename(plugin_path, file, NULL);
287
288                 /* Load plug-in */
289                 handle = __zblib_service_load_plugin(filename, &descriptor);
290                 if (G_UNLIKELY(NULL == handle)) {
291                         g_free(filename);
292                         continue;
293                 }
294
295                 /* Create new plug-in */
296                 plugin = zblib_plugin_new(service, filename, descriptor, handle);
297                 if (G_UNLIKELY(NULL == plugin)) {
298                         g_free(filename);
299                         continue;
300                 }
301
302                 /* Add new plug-in */
303                 ret = zblib_service_add_plugin(service, plugin);
304                 if (G_UNLIKELY(FALSE == ret)) {
305                         zblib_plugin_free(plugin);
306                 }
307
308                 g_free(filename);
309         }
310         g_dir_close(dir);
311
312         return TRUE;
313 }
314
315 gboolean zblib_service_initialize_plugins(ZigBeeService *service)
316 {
317         GSList *list;
318
319         zblib_check_null_ret_error("service", service, FALSE);
320
321         /* Refer plug-in list */
322         list = zblib_service_ref_plugins(service);
323         while (list != NULL) {
324                 /* Initialize each plug-in */
325                 if (G_UNLIKELY(FALSE == __zblib_service_init_plugin((ZigBeePlugin *)(list->data)))) {
326                         list = g_slist_next(list);
327                         continue;
328                 }
329                 list = g_slist_next(list);
330         }
331
332         return TRUE;
333 }
334
335 gboolean zblib_service_unload_plugins(ZigBeeService *service)
336 {
337         GSList *list;
338
339         zblib_check_null_ret_error("service", service, FALSE);
340
341         list = zblib_service_ref_plugins(service);
342         while (list != NULL) {
343                 ZigBeePlugin *plugin = list->data;
344
345                 /* Unload each plug-in */
346                 if (G_UNLIKELY(FALSE == __zblib_service_unload_plugin(plugin))) {
347                         list = g_slist_next(list);
348                         continue;
349                 }
350
351                 list = g_slist_next(list);
352                 zblib_service_remove_plugin(service, plugin);
353         }
354
355         return TRUE;
356 }
357
358 GSList *zblib_service_ref_plugins(ZigBeeService *service)
359 {
360         zblib_check_null_ret_error("service", service, NULL);
361
362         return service->plugins;
363 }
364
365 gboolean zblib_service_add_service_interface(ZigBeeService *service,
366         ZigBeeServiceInterface *service_interface)
367 {
368         gchar *object_name;
369
370         zblib_check_null_ret_error("service", service, FALSE);
371         zblib_check_null_ret_error("service_interface_name", service_interface, FALSE);
372
373         object_name = zblib_service_interface_get_name(service_interface);
374
375         /*
376          * All service interface objects would be appended
377          */
378         service->interface_objs = g_slist_append(service->interface_objs, service_interface);
379         Z_LOGD("%s added", object_name);
380         g_free(object_name);
381
382         return TRUE;
383 }
384
385 gboolean zblib_service_remove_service_interface(ZigBeeService *service,
386         ZigBeeServiceInterface *service_interface)
387 {
388         zblib_check_null_ret_error("service", service, FALSE);
389         zblib_check_null_ret_error("service_interface_name", service_interface, FALSE);
390
391         /*
392          * service interface object would be removed
393          */
394         service->interface_objs = g_slist_remove(service->interface_objs, service_interface);
395
396         return TRUE;
397 }
398
399 ZigBeeServiceInterface *zblib_service_ref_service_interface(ZigBeeService *service,
400         const gchar *service_interface_name)
401 {
402         ZigBeeServiceInterface *service_interface = NULL;
403         ZigBeeServiceInterface *tmp_service_interface = NULL;
404         gchar *object_name;
405
406         GSList *list;
407
408         zblib_check_null_ret_error("service", service, NULL);
409         zblib_check_null_ret_error("service_interface_name", service_interface_name, NULL);
410
411         list = service->interface_objs;
412         while (list) {
413                 tmp_service_interface = (ZigBeeServiceInterface *)list->data;
414
415                 /* Get object name of service_interface */
416                 object_name = zblib_service_interface_get_name(tmp_service_interface);
417                 if (g_strcmp0(service_interface_name, object_name) == 0) {
418                         g_free(object_name);
419
420                         service_interface = tmp_service_interface;
421                         break;
422                 }
423                 g_free(object_name);
424
425                 list = g_slist_next(list);
426         }
427
428         if (NULL == service_interface) {
429                 Z_LOGE("Service interface object of name '%s' not found!",
430                         service_interface_name);
431                 return NULL;
432         }
433
434         Z_LOGD("'%s' found", service_interface_name);
435
436         return service_interface;
437 }
438
439 GHashTable *zblib_service_ref_request_hash_table(ZigBeeService *service)
440 {
441         zblib_check_null_ret_error("service", service, NULL);
442
443         return service->request_table;
444 }
445
446 gint zblib_service_generate_request_id(ZigBeeService *service)
447 {
448         zblib_check_null_ret_error("service", service, -1);
449
450         /* Increment request ID */
451         service->request_id++;
452
453         return (gint)service->request_id;
454 }
455
456 gboolean zblib_service_dispatch_request(ZigBeeService *service,
457         guint request_id)
458 {
459         ZigBeePlugin *plugin = NULL;
460         GSList *plugin_list = NULL;
461         gboolean ret = FALSE;
462
463         zblib_check_null_ret_error("service", service, FALSE);
464
465         /* Fetch plugin_list */
466         plugin_list = service->plugins;
467         zblib_check_null_ret_error("plugin_list", plugin_list, FALSE);
468
469         while (plugin_list) {
470                 plugin = (ZigBeePlugin *)plugin_list->data;
471
472                 /* Dispatch request to plugin */
473                 ret = zblib_plugin_dispatch_request(plugin, request_id);
474
475                 /* Move to next plugin */
476                 plugin_list = g_slist_next(plugin_list);
477         }
478
479         return ret;
480 }
481
482 void zblib_service_send_response(ZigBeeService *service,
483         guint request_id, gpointer resp_data, guint resp_data_len)
484 {
485         ZigBeeServiceInterface *service_interface = NULL;
486
487         zblib_check_null_ret("service", service);
488
489         service_interface = zblib_request_ref_service_interface(service, request_id);
490         zblib_check_null_ret("service_interface", service_interface);
491
492         /* Send response to service interface */
493         zblib_service_interface_send_response(service_interface,
494                 request_id, resp_data, resp_data_len);
495 }
496
497 void zblib_service_send_notification(ZigBeeService *service,
498         guint noti_id, gpointer noti_data, guint noti_data_len)
499 {
500         GSList *interface_objs = NULL;
501         ZigBeeServiceInterface *service_interface = NULL;
502
503         zblib_check_null_ret("service", service);
504
505         interface_objs = service->interface_objs;
506         zblib_check_null_ret("interface_objs", interface_objs);
507
508         while (interface_objs) {
509                 service_interface = (ZigBeeServiceInterface *)interface_objs->data;
510
511                 /* Send notification to service interface */
512                 zblib_service_interface_send_notification(service_interface,
513                         noti_id, noti_data, noti_data_len);
514
515                 /* Move to next service interface */
516                 interface_objs = g_slist_next(interface_objs);
517         }
518 }