Fix a crash issue
[platform/core/api/vine.git] / src / vine-disc.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
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 */
17
18 #include <dlfcn.h>
19 #include <net/if.h>
20
21 #include "vine.h"
22 #include "vine-constants.h"
23 #include "vine-service.h"
24 #include "vine-disc.h"
25 #include "vine-disc-plugin.h"
26 #include "vine-log.h"
27 #include "vine-utils.h"
28
29 static struct {
30         const char *name;
31         const char *path;
32 } __vine_disc_plugins_info[] = {
33         [VINE_DISCOVERY_METHOD_DNS_SD] = {"DNS-SD", DNS_SD_PLUGIN_PATH},
34 #ifdef BT_SUPPORT
35         [VINE_DISCOVERY_METHOD_BLE] = {"BLE", BLE_PLUGIN_PATH},
36 #endif
37 #ifdef NAN_SUPPORT
38         [VINE_DISCOVERY_METHOD_NAN] = {"NAN", NAN_PLUGIN_PATH},
39 #endif
40         {NULL, NULL},
41 };
42
43 static struct {
44         vine_disc_plugin_fn fn;
45         vine_disc_plugin_callbacks callbacks;
46         vine_disc_error (*init)(vine_disc_plugin_fn *fn);
47 } __vine_disc_plugins[] = {
48         {{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
49                 {NULL, NULL, NULL, NULL, NULL}, NULL},
50         {{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
51                 {NULL, NULL, NULL, NULL, NULL}, NULL},
52         {{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
53                 {NULL, NULL, NULL, NULL, NULL}, NULL},
54         {{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
55                 {NULL, NULL, NULL, NULL, NULL}, NULL},
56 };
57
58 typedef struct {
59         vine_discovery_method_e method;
60         vine_disc_plugin_fn *plugin_fn;
61
62         vine_disc_published_cb published_cb;
63         void *published_cb_data;
64         vine_disc_discovered_cb discovered_cb;
65         void *discovered_cb_data;
66         vine_disc_ip_resolved_cb ip_resolved_cb;
67         void *ip_resolved_cb_data;
68         vine_service_h service;  // Used only for vine_disc_resolve_ip
69
70         void *plugin_handle; // Handle to be used in each plugin
71         vine_event_queue_h event_queue;
72 } vine_disc_s;
73
74 typedef struct {
75         char service_name[VINE_MAX_SERVICE_NAME_LEN + 1];
76         vine_disc_error error;
77 } vine_published_event;
78
79 typedef struct {
80         bool available;
81         char service_type[VINE_MAX_SERVICE_TYPE_LEN + 1];
82         char service_name[VINE_MAX_SERVICE_NAME_LEN + 1];
83         char host_name[VINE_MAX_HOST_NAME_LEN + 1];
84         int port;
85         map<string, string> attributes;
86         char iface_name[IF_NAMESIZE + 1];
87         int more_coming;
88         char mac[VINE_MAC_LEN + 1];
89 } vine_discovered_event;
90
91 typedef struct {
92         bool add;
93         vine_address_family_e address_family;
94         char ip[VINE_MAX_IP_LEN + 1];
95         vine_service_h service;
96 } vine_ip_resolved_event;
97
98 vine_error_e __convert_disc_error_to_vine_error(vine_disc_error error)
99 {
100         switch (error) {
101         case VINE_DISC_ERROR_NONE:
102                 return VINE_ERROR_NONE;
103         case VINE_DISC_ERROR_OUT_OF_MEMORY:
104                 return VINE_ERROR_OUT_OF_MEMORY;
105         case VINE_DISC_ERROR_NAME_CONFLICT: // DNS-SD changed the service name
106                 return VINE_ERROR_NAME_CONFLICT;
107                 // TODO: To be determined if which vine error will be returned
108         case VINE_DISC_ERROR_SERVICE_DEREGISTERED:
109                 return VINE_ERROR_SERVICE_DEREGISTERED;
110         case VINE_DISC_ERROR_NOT_SUPPORTED:
111                 return VINE_ERROR_NOT_SUPPORTED;
112         case VINE_DISC_ERROR_SERVICE_NOT_RUNNING:
113         default:
114                 return VINE_ERROR_OPERATION_FAILED;
115         }
116 }
117
118 static void __invoke_published_user_cb(void *event, void *user_data)
119 {
120         VINE_LOGD("event[%p] user_data[%p]", event, user_data);
121         vine_published_event *pub_event = (vine_published_event *)event;
122         vine_disc_s *disc_handle = (vine_disc_s *)user_data;
123         RET_IF(disc_handle == NULL, "Disc handle is NULL");
124
125         VINE_LOGD("Call session callback for published event");
126         if (disc_handle->published_cb)
127                 disc_handle->published_cb(disc_handle,
128                         pub_event->service_name,
129                         __convert_disc_error_to_vine_error(pub_event->error),
130                         disc_handle->published_cb_data);
131 }
132
133 static void __invoke_discovered_user_cb(void *event, void *user_data)
134 {
135         VINE_LOGD("event[%p] user_data[%p]", event, user_data);
136         vine_discovered_event *discovered_event = (vine_discovered_event *)event;
137         vine_disc_s *disc_handle = (vine_disc_s *)user_data;
138         RET_IF(disc_handle == NULL, "Disc handle is NULL");
139         RET_IF(event == NULL, "Discovered event is NULL");
140
141         VINE_LOGD("Call session callback for discovered event");
142
143         if (disc_handle->discovered_cb)
144                 disc_handle->discovered_cb(disc_handle,
145                         discovered_event->available,
146                         discovered_event->service_type,
147                         discovered_event->service_name,
148                         discovered_event->host_name,
149                         discovered_event->mac,
150                         discovered_event->port,
151                         discovered_event->attributes,
152                         discovered_event->iface_name,
153                         discovered_event->more_coming,
154                         disc_handle->discovered_cb_data);
155 }
156
157 static void __invoke_ip_resolved_user_cb(void *event, void *user_data)
158 {
159         VINE_LOGD("event[%p] user_data[%p]", event, user_data);
160         vine_ip_resolved_event *resolved_event = (vine_ip_resolved_event *)event;
161         vine_disc_s *disc_handle = (vine_disc_s *)user_data;
162         RET_IF(disc_handle == NULL, "Disc handle is NULL");
163         RET_IF(event == NULL, "Discovered event is NULL");
164
165         VINE_LOGD("Call session callback for ip resolved event");
166
167         if (disc_handle->ip_resolved_cb)
168                 disc_handle->ip_resolved_cb(disc_handle,
169                         disc_handle->service,
170                         resolved_event->add,
171                         resolved_event->ip,
172                         resolved_event->address_family,
173                         disc_handle->ip_resolved_cb_data);
174 }
175
176 static void __free_pub_event(void *data)
177 {
178         VINE_LOGD("Free pub_event[%p]", data);
179         free(data);
180 }
181
182 static void __free_discovered_event(void *data)
183 {
184         VINE_LOGD("Free discovered_event[%p]", data);
185         vine_discovered_event *discovered_event = (vine_discovered_event *)data;
186
187         discovered_event->attributes.clear();
188         delete discovered_event;
189 }
190
191 static void __free_ip_resolved_event(void *data)
192 {
193         VINE_LOGD("Free ip_resolved_event[%p]", data);
194         delete (vine_ip_resolved_event *)data;
195 }
196
197 static void __published_cb(void *plugin_handle,
198                 const char *service_name, vine_disc_error error, void *user_data)
199 {
200         VINE_LOGD("Published callback from plugin");
201         VINE_LOGD("service_name[%s] error [%d] user_data[%p]",
202                         service_name, error, user_data);
203
204         vine_published_event *pub_event =
205                 (vine_published_event *)calloc(1, sizeof(vine_published_event));
206         RET_IF(pub_event == NULL, "Out of memory");
207         strncpy(pub_event->service_name, service_name, VINE_MAX_SERVICE_NAME_LEN);
208         pub_event->error = error;
209
210         VINE_LOGD("Create a pub_event[%p]", pub_event);
211
212         vine_disc_s *disc_handle = (vine_disc_s *)user_data;
213         if (disc_handle)
214                 vine_event_loop_add_event(disc_handle->event_queue, pub_event,
215                         __invoke_published_user_cb, __free_pub_event, user_data);
216 }
217
218 static void __discovered_cb(void *plugin_handle, bool available,
219                 const char *service_type, const char *service_name,
220                 const char *host_name, const char *mac, int port, const map<string, string> &attr,
221                 const char *iface_name, int more_coming, void *user_data)
222 {
223         RET_IF(service_type == NULL, "service type is NULL");
224         RET_IF(service_name == NULL, "service_name type is NULL");
225
226         VINE_LOGD("Discovered callback from plugin available[%d]", available);
227         VINE_LOGD("service type[%s] service_name[%s] host_name[%s] mac[%s] port[%d] iface[%s] user_data[%p]",
228                         service_type, service_name, host_name, mac, port, iface_name, user_data);
229
230         vine_discovered_event *discovered_event = new vine_discovered_event;
231
232         discovered_event->available = available;
233         strncpy(discovered_event->service_type, service_type, VINE_MAX_SERVICE_TYPE_LEN);
234         discovered_event->service_type[VINE_MAX_SERVICE_TYPE_LEN] = 0;
235         strncpy(discovered_event->service_name, service_name, VINE_MAX_SERVICE_NAME_LEN);
236         discovered_event->service_type[VINE_MAX_SERVICE_NAME_LEN] = 0;
237         strncpy(discovered_event->iface_name, iface_name, IF_NAMESIZE);
238         discovered_event->iface_name[IF_NAMESIZE] = 0;
239         if (host_name != NULL) {
240                 strncpy(discovered_event->host_name, host_name, VINE_MAX_HOST_NAME_LEN);
241                 discovered_event->host_name[VINE_MAX_HOST_NAME_LEN] = 0;
242         }
243         else {
244                 memset(discovered_event->host_name, 0, VINE_MAX_HOST_NAME_LEN + 1);
245         }
246         if (mac != NULL) {
247                 strncpy(discovered_event->mac, mac, VINE_MAC_LEN);
248                 discovered_event->mac[VINE_MAC_LEN] = 0;
249         }
250         else {
251                 memset(discovered_event->mac, 0, VINE_MAC_LEN + 1);
252         }
253
254         discovered_event->port = port;
255         discovered_event->attributes = attr;
256         discovered_event->more_coming = more_coming;
257
258         VINE_LOGD("Create a discovered_event[%p]", discovered_event);
259
260         vine_disc_s *disc_handle = (vine_disc_s *)user_data;
261         if (disc_handle) {
262                 if (vine_event_loop_add_event(disc_handle->event_queue, discovered_event,
263                         __invoke_discovered_user_cb, __free_discovered_event, user_data) == VINE_ERROR_NONE)
264                         return;
265         }
266         __free_discovered_event(discovered_event);
267 }
268
269 static void __ip_resolved_cb(void *plugin_handle, bool add,
270                 const char *ip, sa_family_t address_family, void *user_data)
271 {
272         VINE_LOGD("IP resolved callback from plugin Add[%d]", add);
273         VINE_LOGD("IP[%s] address family[%d] user_data[%p]",
274                         ip, address_family, user_data);
275
276         vine_ip_resolved_event *resolved_event = new vine_ip_resolved_event;
277
278         resolved_event->add = add;
279         if (address_family == AF_INET)
280                 resolved_event->address_family = VINE_ADDRESS_FAMILY_IPV4;
281         else if (address_family == AF_INET6)
282                 resolved_event->address_family = VINE_ADDRESS_FAMILY_IPV6;
283         else
284                 VINE_LOGE("Invalid address family %d", address_family);
285
286         strncpy(resolved_event->ip, ip, VINE_MAX_IP_LEN);
287
288         VINE_LOGD("Create a IP resolved event[%p]", resolved_event);
289
290         vine_disc_s *disc_handle = (vine_disc_s *)user_data;
291         if (disc_handle)
292                 vine_event_loop_add_event(disc_handle->event_queue, resolved_event,
293                         __invoke_ip_resolved_user_cb, __free_ip_resolved_event,
294                         user_data);
295 }
296
297 void __vine_disc_epoll_handler(int fd, int events, void *user_data)
298 {
299         VINE_LOGD("Process event for fd[%d] events[%d] disc_handle[%p]", fd, events, user_data);
300         vine_disc_s *disc_handle = (vine_disc_s *)user_data;
301         if (!disc_handle || !disc_handle->plugin_fn || disc_handle->plugin_fn->process_event == NULL) {
302                 VINE_LOGE("No process_event() defined");
303                 return;
304         }
305         vine_disc_error err = disc_handle->plugin_fn->process_event(disc_handle->plugin_handle, fd);
306         if (err != VINE_DISC_ERROR_NONE) {
307                 VINE_LOGE("Fail to process event %d", err);
308                 vine_event_loop_del_io_handler(fd);
309         }
310 }
311
312 void __fd_added_cb(int fd, void *user_data)
313 {
314         RET_IF(fd < 0, "Invalid fd");
315         vine_disc_h disc = (vine_disc_h)user_data;
316         VINE_LOGD("New fd to be listened");
317         VINE_LOGD("Add epoll handler for fd[%d]. vine_disc_h[%p]", fd, disc);
318
319         vine_event_loop_add_io_handler(fd, VINE_POLLIN | VINE_POLLHUP,
320                         __vine_disc_epoll_handler, disc);
321 }
322
323 void __fd_removed_cb(int fd, void *user_data)
324 {
325         VINE_LOGD("fd[%d] will be removed. vine_disc_h[%p]", fd, user_data);
326         RET_IF(fd < 0, "Invalid fd");
327         vine_event_loop_del_io_handler(fd);
328 }
329
330 static int __load_disc_plugins()
331 {
332         for (int i = 0; __vine_disc_plugins_info[i].path; ++i) {
333                 void *handle = dlopen(__vine_disc_plugins_info[i].path, RTLD_LAZY | RTLD_NODELETE);
334                 if (handle) {
335                         __vine_disc_plugins[i].init =
336                                         (vine_disc_error (*)(vine_disc_plugin_fn *))
337                                                 dlsym(handle, "vine_disc_plugin_init");
338                         dlclose(handle);
339                         VINE_LOGI("Loaded %s", __vine_disc_plugins_info[i].path);
340                 } else {
341                         VINE_LOGE("%s doesn't exist", __vine_disc_plugins_info[i].path);
342                         if (i == VINE_DISCOVERY_METHOD_DNS_SD) {
343                                 VINE_LOGE("%s is a default plugins. It should be loaded.",
344                                         __vine_disc_plugins_info[i].name);
345                                 return VINE_ERROR_OPERATION_FAILED;
346                         }
347                 }
348         }
349
350    return VINE_ERROR_NONE;
351 }
352
353 static void __init_plugins()
354 {
355         for (int i = 0; __vine_disc_plugins[i].init; ++i) {
356                 __vine_disc_plugins[i].init(&__vine_disc_plugins[i].fn);
357                 __vine_disc_plugins[i].callbacks.published_cb = __published_cb;
358                 __vine_disc_plugins[i].callbacks.discovered_cb = __discovered_cb;
359                 __vine_disc_plugins[i].callbacks.ip_resolved_cb = __ip_resolved_cb;
360                 __vine_disc_plugins[i].callbacks.fd_added_cb = __fd_added_cb;
361                 __vine_disc_plugins[i].callbacks.fd_removed_cb = __fd_removed_cb;
362                 __vine_disc_plugins[i].fn.register_callbacks(__vine_disc_plugins[i].callbacks);
363         }
364 }
365
366 int vine_disc_init()
367 {
368         int ret = __load_disc_plugins();
369         RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to load plugins");
370
371         __init_plugins();
372
373         return VINE_ERROR_NONE;
374 }
375
376 void vine_disc_deinit()
377 {
378 }
379
380 int vine_disc_create(vine_discovery_method_e disc_method, vine_disc_h *disc)
381 {
382         RET_VAL_IF(!vine_disc_is_plugin_loaded(disc_method), VINE_ERROR_OPERATION_FAILED,
383                 "Plugin is not loaded");
384
385         vine_disc_s *disc_handle = (vine_disc_s *)calloc(1, sizeof(vine_disc_s));
386         RET_VAL_IF(disc_handle == NULL, VINE_ERROR_OUT_OF_MEMORY, "Out of Memory");
387
388         *disc = disc_handle;
389         disc_handle->method = disc_method;
390         disc_handle->plugin_fn = &__vine_disc_plugins[disc_method].fn;
391         VINE_LOGD("New Discovery handle[%p] disc_method[%d]", disc_handle, disc_method);
392
393         return VINE_ERROR_NONE;
394 }
395
396 void vine_disc_destroy(vine_disc_h disc)
397 {
398         vine_disc_s *disc_handle = (vine_disc_s *)disc;
399         if (disc_handle && disc_handle->plugin_fn &&
400                 disc_handle->plugin_fn->deinit && disc_handle->plugin_handle)
401                 disc_handle->plugin_fn->deinit(disc_handle->plugin_handle);
402         free(disc);
403 }
404
405 static void __vine_disc_set_published_cb(vine_disc_h disc,
406                 vine_disc_published_cb cb, void *user_data)
407 {
408         vine_disc_s *disc_handle = (vine_disc_s *)disc;
409         disc_handle->published_cb = cb;
410         disc_handle->published_cb_data = user_data;
411 }
412
413 static void __vine_disc_set_discovered_cb(vine_disc_h disc,
414                 vine_disc_discovered_cb cb, void *user_data)
415 {
416         vine_disc_s *disc_handle = (vine_disc_s *)disc;
417         disc_handle->discovered_cb = cb;
418         disc_handle->discovered_cb_data = user_data;
419 }
420
421 static void __vine_disc_set_ip_resolved_cb(vine_disc_h disc,
422                 vine_disc_ip_resolved_cb cb, void *user_data)
423 {
424         vine_disc_s *disc_handle = (vine_disc_s *)disc;
425         disc_handle->ip_resolved_cb = cb;
426         disc_handle->ip_resolved_cb_data = user_data;
427 }
428
429 vine_error_e __vine_disc_plugin_publish(vine_disc_h disc, vine_service_h service,
430         const char *iface_name)
431 {
432         RET_VAL_IF(disc == NULL, VINE_ERROR_INVALID_OPERATION, "disc is NULL");
433
434         VINE_LOGD("service[%p], disc handle[%p]", service, disc);
435         vine_disc_s *disc_handle = (vine_disc_s *)disc;
436         void *plugin_handle = NULL;
437
438         RET_VAL_IF(disc_handle->plugin_fn == NULL, VINE_ERROR_INVALID_OPERATION, "plugin_fn is NULL");
439         if (disc_handle->plugin_fn->init == NULL) {
440                 VINE_LOGE("No init() defined");
441                 return VINE_ERROR_OPERATION_FAILED;
442         }
443
444         vine_disc_error error = disc_handle->plugin_fn->init(&plugin_handle, disc);
445         RET_VAL_IF(error != VINE_DISC_ERROR_NONE,
446                         __convert_disc_error_to_vine_error(error),
447                         "Fail to init %d", error);
448
449         disc_handle->plugin_handle = plugin_handle;
450         VINE_LOGD("plugin handle[%p]", plugin_handle);
451
452         if (disc_handle->plugin_fn->publish == NULL) {
453                 VINE_LOGE("No publish() defined");
454                 disc_handle->plugin_fn->deinit(plugin_handle);
455                 disc_handle->plugin_handle = NULL;
456                 return VINE_ERROR_OPERATION_FAILED;
457         }
458
459         error = disc_handle->plugin_fn->publish(plugin_handle,
460                 _vine_service_get_type(service), _vine_service_get_name(service),
461                 _vine_service_get_port(service), _vine_service_get_attributes(service),
462                 iface_name);
463         if (error != VINE_DISC_ERROR_NONE) {
464                 VINE_LOGE("Fail to publish %d", error);
465                 disc_handle->plugin_fn->deinit(plugin_handle);
466                 disc_handle->plugin_handle = NULL;
467                 return __convert_disc_error_to_vine_error(error);
468         }
469
470         return VINE_ERROR_NONE;
471 }
472
473 int vine_disc_publish(vine_disc_h disc,
474                 vine_service_h service, const char *iface_name,
475                 vine_disc_published_cb cb, void *user_data,
476                 vine_event_queue_h event_queue)
477 {
478         RET_VAL_IF(disc == NULL, VINE_ERROR_INVALID_PARAMETER, "disc is NULL");
479         RET_VAL_IF(service == NULL, VINE_ERROR_INVALID_PARAMETER, "service is NULL");
480
481         VINE_LOGD("Publishevent_queue[%p]", event_queue);
482         VINE_LOGD("service[%p] disc[%p]", service, disc);
483         __vine_disc_set_published_cb(disc, cb, user_data);
484
485         vine_disc_s *disc_handle = (vine_disc_s *)disc;
486         disc_handle->event_queue = event_queue;
487
488         int ret = __vine_disc_plugin_publish(disc, service, iface_name);
489         if (ret != VINE_ERROR_NONE) {
490                 VINE_LOGE("Fail to publish the service %d", ret);
491                 return ret;
492         }
493
494         return VINE_ERROR_NONE;
495 }
496
497 vine_error_e __vine_disc_plugin_stop_publish(vine_disc_h disc)
498 {
499         RET_VAL_IF(disc == NULL, VINE_ERROR_INVALID_OPERATION, "disc is NULL");
500
501         vine_disc_error error = VINE_DISC_ERROR_NONE;
502         vine_disc_s *disc_handle = (vine_disc_s *)disc;
503
504         RET_VAL_IF(disc_handle->plugin_fn == NULL, VINE_ERROR_INVALID_OPERATION, "plugin_fn is NULL");
505         if (disc_handle->plugin_fn->init == NULL) {
506                 VINE_LOGE("No init() defined");
507                 return VINE_ERROR_OPERATION_FAILED;
508         }
509
510         if (disc_handle->plugin_fn->stop_publish == NULL) {
511                 VINE_LOGE("No stop_publish() defined");
512                 return VINE_ERROR_OPERATION_FAILED;
513         }
514
515         error = disc_handle->plugin_fn->stop_publish(disc_handle->plugin_handle);
516         if (error != VINE_DISC_ERROR_NONE) {
517                 VINE_LOGE("Fail to stop publish %d", error);
518                 return __convert_disc_error_to_vine_error(error);
519         }
520
521         return VINE_ERROR_NONE;
522 }
523
524 int vine_disc_stop_publish(vine_disc_h disc)
525 {
526         RET_VAL_IF(disc == NULL, VINE_ERROR_INVALID_PARAMETER, "disc is NULL");
527
528         int ret = __vine_disc_plugin_stop_publish(disc);
529         if (ret != VINE_ERROR_NONE) {
530                 VINE_LOGE("Fail to stop publish %d", ret);
531                 return ret;
532         }
533
534         return VINE_ERROR_NONE;
535 }
536
537 vine_error_e __vine_disc_plugin_subscribe(vine_disc_h disc,
538                 const char *service_type, const char *iface_name)
539 {
540         RET_VAL_IF(disc == NULL, VINE_ERROR_INVALID_OPERATION, "disc is NULL");
541
542         VINE_LOGD("service_type[%s], disc handle[%p]", service_type, disc);
543         vine_disc_s *disc_handle = (vine_disc_s *)disc;
544         void *plugin_handle = NULL;
545
546         RET_VAL_IF(disc_handle->plugin_fn == NULL, VINE_ERROR_INVALID_OPERATION, "plugin_fn is NULL");
547         if (disc_handle->plugin_fn->init == NULL) {
548                 VINE_LOGE("No init() defined");
549                 return VINE_ERROR_OPERATION_FAILED;
550         }
551         vine_disc_error error = disc_handle->plugin_fn->init(&plugin_handle, disc);
552         RET_VAL_IF(error != VINE_DISC_ERROR_NONE,
553                         __convert_disc_error_to_vine_error(error),
554                         "Fail to init %d", error);
555
556         disc_handle->plugin_handle = plugin_handle;
557         VINE_LOGD("plugin handle[%p]", plugin_handle);
558
559         if (disc_handle->plugin_fn->subscribe == NULL) {
560                 VINE_LOGE("No subscribe() defined");
561                 disc_handle->plugin_fn->deinit(plugin_handle);
562                 disc_handle->plugin_handle = NULL;
563                 return VINE_ERROR_OPERATION_FAILED;
564         }
565         error = disc_handle->plugin_fn->subscribe(plugin_handle, service_type, iface_name);
566         if (error != VINE_DISC_ERROR_NONE) {
567                 VINE_LOGE("Fail to subscribe %d", error);
568                 disc_handle->plugin_fn->deinit(plugin_handle);
569                 disc_handle->plugin_handle = NULL;
570                 return __convert_disc_error_to_vine_error(error);
571         }
572
573         return VINE_ERROR_NONE;
574 }
575
576 int vine_disc_subscribe(vine_disc_h disc,
577                 const char *service_type, const char *iface_name,
578                 vine_disc_discovered_cb cb, void *user_data,
579                 vine_event_queue_h event_queue)
580 {
581         RET_VAL_IF(disc == NULL, VINE_ERROR_INVALID_PARAMETER, "disc is NULL");
582
583         VINE_LOGD("Subscribe event_queue[%p]", event_queue);
584         VINE_LOGD("service_type[%s] disc[%p]", service_type, disc);
585
586         __vine_disc_set_discovered_cb(disc, cb, user_data);
587
588         vine_disc_s *disc_handle = (vine_disc_s *)disc;
589         disc_handle->event_queue = event_queue;
590
591         int ret = __vine_disc_plugin_subscribe(disc, service_type, iface_name);
592         if (ret != VINE_ERROR_NONE) {
593                 VINE_LOGE("Fail to subscribe the service %d", ret);
594                 return ret;
595         }
596
597         return VINE_ERROR_NONE;
598 }
599
600 vine_error_e __vine_disc_plugin_stop_subscribe(vine_disc_h disc)
601 {
602         RET_VAL_IF(disc == NULL, VINE_ERROR_INVALID_OPERATION, "disc is NULL");
603
604         vine_disc_error error = VINE_DISC_ERROR_NONE;
605         vine_disc_s *disc_handle = (vine_disc_s *)disc;
606
607         RET_VAL_IF(disc_handle->plugin_fn == NULL, VINE_ERROR_INVALID_OPERATION, "plugin_fn is NULL");
608         if (disc_handle->plugin_fn->init == NULL) {
609                 VINE_LOGE("No init() defined");
610                 return VINE_ERROR_OPERATION_FAILED;
611         }
612
613         if (disc_handle->plugin_fn->stop_subscribe == NULL) {
614                 VINE_LOGE("No stop_subscribe() defined");
615                 return VINE_ERROR_OPERATION_FAILED;
616         }
617
618         error = disc_handle->plugin_fn->stop_subscribe(disc_handle->plugin_handle);
619         if (error != VINE_DISC_ERROR_NONE) {
620                 VINE_LOGE("Fail to stop publish %d", error);
621                 return __convert_disc_error_to_vine_error(error);
622         }
623
624         return VINE_ERROR_NONE;
625 }
626
627 int vine_disc_stop_subscribe(vine_disc_h disc)
628 {
629         RET_VAL_IF(disc == NULL, VINE_ERROR_INVALID_PARAMETER, "disc is NULL");
630
631         int ret = __vine_disc_plugin_stop_subscribe(disc);
632         if (ret != VINE_ERROR_NONE) {
633                 VINE_LOGE("Fail to stop subscribe %d", ret);
634                 return ret;
635         }
636
637         return VINE_ERROR_NONE;
638 }
639
640 vine_error_e __vine_disc_plugin_resolve_ip(vine_disc_h disc, vine_service_h service)
641 {
642         RET_VAL_IF(disc == NULL, VINE_ERROR_INVALID_OPERATION, "disc is NULL");
643
644         VINE_LOGD("service[%p], disc handle[%p]", service, disc);
645         vine_disc_s *disc_handle = (vine_disc_s *)disc;
646         void *plugin_handle = NULL;
647
648         RET_VAL_IF(disc_handle->plugin_fn == NULL, VINE_ERROR_INVALID_OPERATION, "plugin_fn is NULL");
649         if (disc_handle->plugin_fn->init == NULL) {
650                 VINE_LOGE("No init() defined");
651                 return VINE_ERROR_OPERATION_FAILED;
652         }
653         vine_disc_error error = disc_handle->plugin_fn->init(&plugin_handle, disc);
654         RET_VAL_IF(error != VINE_DISC_ERROR_NONE,
655                         __convert_disc_error_to_vine_error(error),
656                         "Fail to init %d", error);
657
658         disc_handle->plugin_handle = plugin_handle;
659         VINE_LOGD("plugin handle[%p]", plugin_handle);
660
661         if (disc_handle->plugin_fn->resolve_ip == NULL) {
662                 VINE_LOGE("No resolve_ip() defined");
663                 disc_handle->plugin_fn->deinit(plugin_handle);
664                 disc_handle->plugin_handle = NULL;
665                 return VINE_ERROR_OPERATION_FAILED;
666         }
667         error = disc_handle->plugin_fn->resolve_ip(plugin_handle,
668                 _vine_service_get_type(service), _vine_service_get_name(service),
669                 _vine_service_get_host_name(service), nullptr, _vine_service_get_iface_name(service),
670                 (int)_vine_service_get_address_family(service));
671         if (error != VINE_DISC_ERROR_NONE) {
672                 VINE_LOGE("Fail to resolve ip %d", error);
673                 disc_handle->plugin_fn->deinit(plugin_handle);
674                 disc_handle->plugin_handle = NULL;
675                 return __convert_disc_error_to_vine_error(error);
676         }
677
678         return VINE_ERROR_NONE;
679 }
680
681 int vine_disc_resolve_ip(vine_disc_h disc,
682                  vine_service_h service,
683                  vine_disc_ip_resolved_cb cb, void *user_data,
684                  vine_event_queue_h event_queue)
685 {
686         RET_VAL_IF(disc == NULL, VINE_ERROR_INVALID_PARAMETER, "disc is NULL");
687         RET_VAL_IF(service == NULL, VINE_ERROR_INVALID_PARAMETER, "service is NULL");
688
689         VINE_LOGD("Resolve IP for a service[%p] event_queue[%p]", service, event_queue);
690
691         __vine_disc_set_ip_resolved_cb(disc, cb, user_data);
692
693         vine_disc_s *disc_handle = (vine_disc_s *)disc;
694         disc_handle->event_queue = event_queue;
695         disc_handle->service = service;
696
697         int ret = __vine_disc_plugin_resolve_ip(disc, service);
698         if (ret != VINE_ERROR_NONE) {
699                 VINE_LOGE("Fail to subscribe the service %d", ret);
700                 return ret;
701         }
702
703         return VINE_ERROR_NONE;
704 }
705
706 vine_error_e __vine_disc_plugin_cancel_resolve_ip(vine_disc_h disc, vine_service_h service)
707 {
708         RET_VAL_IF(disc == NULL, VINE_ERROR_INVALID_OPERATION, "disc is NULL");
709
710         VINE_LOGD("service[%p], disc handle[%p]", service, disc);
711         vine_disc_s *disc_handle = (vine_disc_s *)disc;
712         void *plugin_handle = disc_handle->plugin_handle;
713         VINE_LOGD("plugin handle[%p]", plugin_handle);
714
715         RET_VAL_IF(disc_handle->plugin_fn == NULL, VINE_ERROR_INVALID_OPERATION, "plugin_fn is NULL");
716         if (disc_handle->plugin_fn->cancel_resolve_ip == NULL) {
717                 VINE_LOGE("No resolve_ip() defined");
718                 return VINE_ERROR_OPERATION_FAILED;
719         }
720
721         vine_disc_error error = disc_handle->plugin_fn->cancel_resolve_ip(plugin_handle);
722         if (error != VINE_DISC_ERROR_NONE)
723                 VINE_LOGE("Fail to cancel_resolve_ip %d", error);
724
725         return __convert_disc_error_to_vine_error(error);
726 }
727
728 int vine_disc_cancel_resolve_ip(vine_disc_h disc, vine_service_h service)
729 {
730         RET_VAL_IF(service == NULL, VINE_ERROR_INVALID_PARAMETER, "service is NULL");
731         RET_VAL_IF(disc == NULL, VINE_ERROR_INVALID_PARAMETER, "disc is NULL");
732
733         VINE_LOGD("Cancel resolving IP for a service[%p] disc_handle[%p]", service, disc);
734
735         int ret = __vine_disc_plugin_cancel_resolve_ip(disc, service);
736         if (ret != VINE_ERROR_NONE) {
737                 VINE_LOGE("Fail to cancel resolving IP %d", ret);
738                 return ret;
739         }
740
741         vine_disc_s *disc_handle = (vine_disc_s *)disc;
742         disc_handle->event_queue = NULL;
743         disc_handle->service = NULL;
744
745         return VINE_ERROR_NONE;
746 }
747
748 bool vine_disc_is_plugin_loaded(vine_discovery_method_e disc_method)
749 {
750         return __vine_disc_plugins[(int)disc_method].init != NULL;
751 }