22170490709d9989cedf4f977ef21c813aaa4903
[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 = zblib_plugin_get_plugin_name(plugin);
118
119         zblib_check_null_ret_error("descriptor", descriptor, FALSE);
120         zblib_check_null_ret_error("descriptor->unload", descriptor->unload, FALSE);
121
122         descriptor->unload(plugin);
123         Z_LOGI("plugin(%s) unloaded!", plugin_name);
124
125         return TRUE;
126 }
127
128 ZigBeeService *zblib_service_new()
129 {
130         ZigBeeService *service;
131
132         service = g_malloc0(sizeof(struct zblib_service_type));
133
134         /* Create g-main loop */
135         service->main_loop = g_main_loop_new(NULL, FALSE);
136         if (G_UNLIKELY(NULL == service->main_loop)) {
137                 Z_LOGE("g-main loop creation failed!!!");
138                 g_free(service);
139                 return NULL;
140         }
141
142         /* Create request hash table */
143         service->request_table = g_hash_table_new_full(g_direct_hash,
144                 g_direct_equal, NULL, NULL);
145
146         return service;
147 }
148
149 void zblib_service_free(ZigBeeService *service)
150 {
151         zblib_check_null_ret("service", service);
152
153         /* Free plug-ins */
154         if (service->plugins) {
155                 g_slist_free(service->plugins);
156                 service->plugins = NULL;
157         }
158
159         /* Unref 'g-main loop' */
160         if (service->main_loop)
161                 g_main_loop_unref(service->main_loop);
162
163         g_free(service);
164 }
165
166 gboolean zblib_service_run(ZigBeeService *service)
167 {
168         zblib_check_null_ret_error("service", service, FALSE);
169         zblib_check_null_ret_error("service->main_loop", service->main_loop, FALSE);
170
171         g_main_loop_run(service->main_loop);
172
173         return TRUE;
174 }
175
176 gboolean zblib_service_exit(ZigBeeService *service)
177 {
178         zblib_check_null_ret_error("service", service, FALSE);
179         zblib_check_null_ret_error("service->main_loop", service->main_loop, FALSE);
180
181         g_main_loop_quit(service->main_loop);
182
183         return TRUE;
184 }
185
186 gboolean zblib_service_add_plugin(ZigBeeService *service, ZigBeePlugin *plugin)
187 {
188         gchar *plugin_name;
189
190         zblib_check_null_ret_error("service", service, FALSE);
191         zblib_check_null_ret_error("plugin", plugin, FALSE);
192
193         plugin_name = zblib_plugin_get_plugin_name(plugin);
194
195         /* All plug-ins would be appended */
196         service->plugins = g_slist_append(service->plugins, plugin);
197         Z_LOGD("%s added", plugin_name);
198         g_free(plugin_name);
199
200         return TRUE;
201 }
202
203 gboolean zblib_service_remove_plugin(ZigBeeService *service, ZigBeePlugin *plugin)
204 {
205         zblib_check_null_ret_error("service", service, FALSE);
206         zblib_check_null_ret_error("plugin", plugin, FALSE);
207
208         /* Specific vendor plug-in would be removed */
209         service->plugins = g_slist_remove(service->plugins, plugin);
210
211         return TRUE;
212 }
213
214 gboolean zblib_service_load_plugins(ZigBeeService *service, const char *plugin_path)
215 {
216         const gchar *file = NULL;
217         gchar *filename = NULL;
218         GDir *dir = NULL;
219         void *handle = NULL;
220         ZblibPluginDescriptor_t *descriptor = NULL;
221         ZigBeePlugin *plugin = NULL;
222         gboolean ret;
223
224         zblib_check_null_ret_error("service", service, FALSE);
225         zblib_check_null_ret_error("plugin_path", plugin_path, FALSE);
226
227         /* Open plug-in directory */
228         dir = g_dir_open(plugin_path, 0, NULL);
229         if (G_UNLIKELY(dir == NULL)) {
230                 Z_LOGE("Directory open failed!");
231                 return FALSE;
232         }
233
234         /* Scan through all libraries in plug-in directory */
235         while ((file = g_dir_read_name(dir)) != NULL) {
236                 if ((g_str_has_prefix(file, "lib") == TRUE)
237                                 || (g_str_has_suffix(file, ".so") == FALSE))
238                         continue;
239
240                 filename = g_build_filename(plugin_path, file, NULL);
241
242                 /* Load plug-in */
243                 handle = __zblib_service_load_plugin(filename, &descriptor);
244                 if (G_UNLIKELY(NULL == handle)) {
245                         g_free(filename);
246                         continue;
247                 }
248
249                 /* Create new plug-in */
250                 plugin = zblib_plugin_new(service, filename, descriptor, handle);
251                 if (G_UNLIKELY(NULL == plugin)) {
252                         g_free(filename);
253                         continue;
254                 }
255
256                 /* Add new plug-in */
257                 ret = zblib_service_add_plugin(service, plugin);
258                 if (G_UNLIKELY(FALSE == ret)) {
259                         zblib_plugin_free(plugin);
260                 }
261
262                 g_free(filename);
263         }
264         g_dir_close(dir);
265
266         return TRUE;
267 }
268
269 gboolean zblib_service_initialize_plugins(ZigBeeService *service)
270 {
271         GSList *list;
272
273         zblib_check_null_ret_error("service", service, FALSE);
274
275         /* Refer plug-in list */
276         list = zblib_service_ref_plugins(service);
277         while (list != NULL) {
278                 /* Initialize each plug-in */
279                 if (G_UNLIKELY(FALSE == __zblib_service_init_plugin((ZigBeePlugin *)(list->data)))) {
280                         list = g_slist_next(list);
281                         continue;
282                 }
283                 list = g_slist_next(list);
284         }
285
286         return TRUE;
287 }
288
289 gboolean zblib_service_unload_plugins(ZigBeeService *service)
290 {
291         GSList *list;
292
293         zblib_check_null_ret_error("service", service, FALSE);
294
295         list = zblib_service_ref_plugins(service);
296         while (list != NULL) {
297                 ZigBeePlugin *plugin = list->data;
298
299                 /* Unload each plug-in */
300                 if (G_UNLIKELY(FALSE == __zblib_service_unload_plugin(plugin))) {
301                         list = g_slist_next(list);
302                         continue;
303                 }
304
305                 list = g_slist_next(list);
306                 zblib_service_remove_plugin(service, plugin);
307         }
308
309         return TRUE;
310 }
311
312 GSList *zblib_service_ref_plugins(ZigBeeService *service)
313 {
314         zblib_check_null_ret_error("service", service, NULL);
315
316         return service->plugins;
317 }
318
319 gboolean zblib_service_add_service_interface(ZigBeeService *service,
320         ZigBeeServiceInterface *service_interface)
321 {
322         gchar *object_name;
323
324         zblib_check_null_ret_error("service", service, FALSE);
325         zblib_check_null_ret_error("service_interface_name", service_interface, FALSE);
326
327         object_name = zblib_service_interface_get_name(service_interface);
328
329         /*
330          * All service interface objects would be appended
331          */
332         service->interface_objs = g_slist_append(service->interface_objs, service_interface);
333         Z_LOGD("%s added", object_name);
334         g_free(object_name);
335
336         return TRUE;
337 }
338
339 gboolean zblib_service_remove_service_interface(ZigBeeService *service,
340         ZigBeeServiceInterface *service_interface)
341 {
342         zblib_check_null_ret_error("service", service, FALSE);
343         zblib_check_null_ret_error("service_interface_name", service_interface, FALSE);
344
345         /*
346          * service interface object would be removed
347          */
348         service->interface_objs = g_slist_remove(service->interface_objs, service_interface);
349
350         return TRUE;
351 }
352
353 ZigBeeServiceInterface *zblib_service_ref_service_interface(ZigBeeService *service,
354         const gchar *service_interface_name)
355 {
356         ZigBeeServiceInterface *service_interface = NULL;
357         ZigBeeServiceInterface *tmp_service_interface = NULL;
358         gchar *object_name;
359
360         GSList *list;
361
362         zblib_check_null_ret_error("service", service, NULL);
363         zblib_check_null_ret_error("service_interface_name", service_interface_name, NULL);
364
365         list = service->interface_objs;
366         while (list) {
367                 tmp_service_interface = (ZigBeeServiceInterface *)list->data;
368
369                 /* Get object name of service_interface */
370                 object_name = zblib_service_interface_get_name(tmp_service_interface);
371                 if (g_strcmp0(service_interface_name, object_name) == 0) {
372                         g_free(object_name);
373
374                         service_interface = tmp_service_interface;
375                         break;
376                 }
377
378                 list = g_slist_next(list);
379         }
380
381         if (NULL == service_interface) {
382                 Z_LOGE("Service interface object of name '%s' not found!",
383                         service_interface_name);
384                 return NULL;
385         }
386
387         Z_LOGD("'%s' found", service_interface_name);
388
389         return service_interface;
390 }
391
392 GHashTable *zblib_service_ref_request_hash_table(ZigBeeService *service)
393 {
394         zblib_check_null_ret_error("service", service, NULL);
395
396         return service->request_table;
397 }
398
399 gint zblib_service_generate_request_id(ZigBeeService *service)
400 {
401         zblib_check_null_ret_error("service", service, -1);
402
403         /* Increment request ID */
404         service->request_id++;
405
406         return (gint)service->request_id;
407 }
408
409 gboolean zblib_service_dispatch_request(ZigBeeService *service,
410         guint request_id)
411 {
412         ZigBeePlugin *plugin = NULL;
413         GSList *plugin_list = NULL;
414         gboolean ret = FALSE;
415
416         zblib_check_null_ret_error("service", service, FALSE);
417
418         /* Fetch plugin_list */
419         plugin_list = service->plugins;
420         zblib_check_null_ret_error("plugin_list", plugin_list, FALSE);
421
422         while (plugin_list) {
423                 plugin = (ZigBeePlugin *)plugin_list->data;
424
425                 /* Dispatch request to plugin */
426                 ret = zblib_plugin_dispatch_request(plugin, request_id);
427
428                 /* Move to next plugin */
429                 plugin_list = g_slist_next(plugin_list);
430         }
431
432         return ret;
433 }
434
435 void zblib_service_send_response(ZigBeeService *service,
436         guint request_id, gpointer resp_data, guint resp_data_len)
437 {
438         ZigBeeServiceInterface *service_interface = NULL;
439
440         service_interface = zblib_request_ref_service_interface(service, request_id);
441         zblib_check_null_ret("service_interface", service_interface);
442
443         /* Send response to service interface */
444         zblib_service_interface_send_response(service_interface,
445                 request_id, resp_data, resp_data_len);
446 }
447
448 void zblib_service_send_notification(ZigBeeService *service,
449         guint noti_id, gpointer noti_data, guint noti_data_len)
450 {
451         GSList *interface_objs = NULL;
452         ZigBeeServiceInterface *service_interface = NULL;
453
454         zblib_check_null_ret("service", service);
455
456         interface_objs = service->interface_objs;
457         zblib_check_null_ret("interface_objs", interface_objs);
458
459         while (interface_objs) {
460                 service_interface = (ZigBeeServiceInterface *)interface_objs->data;
461
462                 /* Send notification to service interface */
463                 zblib_service_interface_send_notification(service_interface,
464                         noti_id, noti_data, noti_data_len);
465
466                 /* Move to next service interface */
467                 interface_objs = g_slist_next(interface_objs);
468         }
469 }