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